Compare commits

...

47 Commits
1.5 ... 1.7

Author SHA1 Message Date
e87bed6df2 updated README 2006-09-26 14:32:02 +02:00
4ee05b3294 small change 2006-09-26 14:08:42 +02:00
e81eb46a78 added slight error check to getcolor 2006-09-26 13:49:16 +02:00
f315832f75 small fix 2006-09-26 13:30:30 +02:00
97ced11e53 changed order of colordefs in config.h's, changed config.arg.h to fit to new dmenu 2006-09-26 13:24:14 +02:00
4d6c4d36ce removed useless debug info 2006-09-26 08:17:35 +02:00
b4d53bf194 added configure(), but this doesn't really fix those frking broken SDL apps 2006-09-26 07:40:19 +02:00
67bc08d1b9 slight change of event handling order 2006-09-25 21:28:00 +02:00
bcb07de750 simplified mouse resizals 2006-09-25 21:19:18 +02:00
7d7cde0fd6 applied sanders jukka patch 2006-09-25 20:38:30 +02:00
6b25d06d7d applied Jukkas patch 2006-09-25 08:21:51 +02:00
cff951c650 removed all dotile checks 2006-09-22 18:48:35 +02:00
114cc3ec02 applied Jukkas remark (dunno if this is correct though) 2006-09-22 16:35:49 +02:00
3c4b7672a8 applied jukkas patch 2006-09-22 15:39:38 +02:00
6de149eb22 man page fix 2006-09-22 14:02:41 +02:00
da909dd1e8 ismax toggling on mouse based action 2006-09-22 14:00:54 +02:00
67986e81ee hotfix 2006-09-22 13:58:21 +02:00
346bdea946 small change to achieve Jukka's last proposal 2006-09-22 13:53:28 +02:00
05c10c5776 fixed issue pointed out by Jukka 2006-09-22 11:49:24 +02:00
b2cb925d99 patched resizemouse according to sanders remark 2006-09-22 11:24:01 +02:00
9fb6502b3b small man page fix 2006-09-22 10:01:51 +02:00
9eb226ff78 sander check this 2006-09-22 09:43:21 +02:00
e34c4eaf61 slight change to config.arg.h (I use ff floating) 2006-09-22 08:22:39 +02:00
9e75bcfc75 updated man page 2006-09-22 08:17:42 +02:00
d800ec05ff implemented the maximization as I described on the mailinglist, this feels better to me. 2006-09-22 07:37:56 +02:00
bda53ac6ad reviewed client.c 2006-09-20 09:53:21 +02:00
4230932563 reviewed util.c 2006-09-20 09:49:32 +02:00
f17e898bd1 fixed a nuance in dwm.1 2006-09-20 09:45:39 +02:00
886b2088f1 improved intro comment in dwm.h, updated config.mk 2006-09-20 09:40:35 +02:00
551d6bb23d some simplifications to intro in dwm.h 2006-09-19 16:13:44 +02:00
d504005e91 Added tag 1.6 for changeset ad3fa2d185426c51fd5deceae809770363f8d33c 2006-09-16 11:21:01 +02:00
2511b5c675 added visibility check to enternotify as well 2006-09-15 14:21:25 +02:00
28aba061ec offscreen client appearance fixes 2006-09-15 10:54:32 +02:00
8e37c78ce3 focus() enforces visibility of a client if not NULL 2006-09-15 10:49:05 +02:00
ca68975ff8 removed useless inclusion 2006-09-14 11:07:44 +02:00
529be52fea fixed executing of dmenu output to handle args correctly 2006-09-12 19:09:04 +02:00
ca65478c89 removed a bunch of lines through making function signatures more consistent with my style ( { does not belong to a new line, if function args are single-lined) 2006-09-12 10:57:28 +02:00
a1e9362d38 some more simplifications of intro comment in dwm.h, this should suffice for comments in dwm 2006-09-12 09:50:06 +02:00
cbfc69e310 made introduction comment in dwm.h shorter 2006-09-12 09:46:19 +02:00
1d7674bb22 applied Christof Musik's multihead patch for a pathologic cornercase 2006-09-12 08:27:11 +02:00
e6cc22396a added a general comment to dwm.h how dwm is basically organized 2006-09-12 08:14:22 +02:00
868159fd0a some other simplifications 2006-09-11 17:31:21 +02:00
b597fa4637 fixed some other comments, now also the code side seems to be at a level to be reviewed by experienced programmers 2006-09-11 11:28:28 +02:00
d2d394eccf small change to comments, renamed two set* functions in client.c into update* 2006-09-11 10:00:56 +02:00
438beeabde small fix 2006-09-11 08:58:58 +02:00
281f0981a6 added some comments 2006-09-11 07:40:41 +02:00
6ff346bed9 Added tag 1.5 for changeset 728c9089b079721b43c3347124639a29baa22a97 2006-09-08 08:32:08 +02:00
14 changed files with 294 additions and 347 deletions

View File

@ -12,3 +12,5 @@ bbc98e77ae89a7c9232a5be0835f60ea00d8036e 1.0
e3179ce2b90451d2807cd53b589d768412b8666b 1.2
f5f5cbf016a94b48a8fe9c47f0736e96d166d5d4 1.3
3cff9403766bf83a9fc2a0aef230115d68de2a8e 1.4
728c9089b079721b43c3347124639a29baa22a97 1.5
ad3fa2d185426c51fd5deceae809770363f8d33c 1.6

2
README
View File

@ -1,5 +1,5 @@
dwm - dynamic window manager
----------------------------
============================
dwm is an extremely fast, small, and dynamic window manager for X.

124
client.c
View File

@ -11,19 +11,17 @@
/* static functions */
static void
detachstack(Client *c)
{
detachstack(Client *c) {
Client **tc;
for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
*tc = c->snext;
}
static void
grabbuttons(Client *c, Bool focus)
{
grabbuttons(Client *c, Bool focused) {
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
if(focus) {
if(focused) {
XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
@ -54,12 +52,10 @@ grabbuttons(Client *c, Bool focus)
else
XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
GrabModeAsync, GrabModeSync, None, None);
}
static void
resizetitle(Client *c)
{
resizetitle(Client *c) {
c->tw = textw(c->name);
if(c->tw > c->w)
c->tw = c->w + 2;
@ -69,36 +65,47 @@ resizetitle(Client *c)
XMoveResizeWindow(dpy, c->twin, c->tx, c->ty, c->tw, c->th);
else
XMoveResizeWindow(dpy, c->twin, c->tx + 2 * sw, c->ty, c->tw, c->th);
}
static int
xerrordummy(Display *dsply, XErrorEvent *ee)
{
xerrordummy(Display *dsply, XErrorEvent *ee) {
return 0;
}
/* extern functions */
void
ban(Client *c)
{
ban(Client *c) {
XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
XMoveWindow(dpy, c->twin, c->tx + 2 * sw, c->ty);
}
void
focus(Client *c)
{
configure(Client *c) {
XEvent synev;
synev.type = ConfigureNotify;
synev.xconfigure.display = dpy;
synev.xconfigure.event = c->win;
synev.xconfigure.window = c->win;
synev.xconfigure.x = c->x;
synev.xconfigure.y = c->y;
synev.xconfigure.width = c->w;
synev.xconfigure.height = c->h;
synev.xconfigure.border_width = c->border;
synev.xconfigure.above = None;
XSendEvent(dpy, c->win, True, NoEventMask, &synev);
}
void
focus(Client *c) {
Client *old;
if(!issel)
if(!issel || (c && !isvisible(c)))
return;
if(!sel)
sel = c;
else if(sel != c) {
if(maximized)
togglemax(NULL);
old = sel;
sel = c;
if(old) {
@ -119,8 +126,7 @@ focus(Client *c)
}
Client *
getclient(Window w)
{
getclient(Window w) {
Client *c;
for(c = clients; c; c = c->next)
@ -130,8 +136,7 @@ getclient(Window w)
}
Client *
getctitle(Window w)
{
getctitle(Window w) {
Client *c;
for(c = clients; c; c = c->next)
@ -141,8 +146,7 @@ getctitle(Window w)
}
void
gravitate(Client *c, Bool invert)
{
gravitate(Client *c, Bool invert) {
int dx = 0, dy = 0;
switch(c->grav) {
@ -196,8 +200,7 @@ gravitate(Client *c, Bool invert)
}
void
killclient(Arg *arg)
{
killclient(Arg *arg) {
if(!sel)
return;
if(sel->proto & PROTODELWIN)
@ -207,8 +210,7 @@ killclient(Arg *arg)
}
void
manage(Window w, XWindowAttributes *wa)
{
manage(Window w, XWindowAttributes *wa) {
Client *c;
Window trans;
XSetWindowAttributes twa;
@ -223,7 +225,7 @@ manage(Window w, XWindowAttributes *wa)
c->th = bh;
c->border = 0;
setsize(c);
updatesize(c);
if(c->x + c->w + 2 > sw)
c->x = sw - c->w - 2;
@ -260,7 +262,7 @@ manage(Window w, XWindowAttributes *wa)
c->snext = stack;
stack = clients = c;
settitle(c);
updatetitle(c);
ban(c);
XMapWindow(dpy, c->win);
XMapWindow(dpy, c->twin);
@ -270,8 +272,7 @@ manage(Window w, XWindowAttributes *wa)
}
void
resize(Client *c, Bool sizehints, Corner sticky)
{
resize(Client *c, Bool sizehints, Corner sticky) {
int bottom = c->y + c->h;
int right = c->x + c->w;
XWindowChanges wc;
@ -295,6 +296,16 @@ resize(Client *c, Bool sizehints, Corner sticky)
if(sticky == BotLeft || sticky == BotRight)
c->y = bottom - c->h;
/* offscreen appearance fixes */
if(c->x + c->w < 0)
c->x = 0;
if(c->y + c->h < bh)
c->y = bh;
if(c->x > sw)
c->x = sw - c->w;
if(c->y > sh)
c->y = sh - c->h;
resizetitle(c);
wc.x = c->x;
wc.y = c->y;
@ -304,13 +315,13 @@ resize(Client *c, Bool sizehints, Corner sticky)
wc.border_width = 0;
else
wc.border_width = 1;
XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
configure(c);
XSync(dpy, False);
}
void
setsize(Client *c)
{
updatesize(Client *c) {
long msize;
XSizeHints size;
@ -348,8 +359,7 @@ setsize(Client *c)
}
void
settitle(Client *c)
{
updatetitle(Client *c) {
char **list = NULL;
int n;
XTextProperty name;
@ -376,46 +386,10 @@ settitle(Client *c)
}
void
togglemax(Arg *arg)
{
int ox, oy, ow, oh;
Client *c;
XEvent ev;
if(!sel)
return;
if((maximized = !maximized)) {
ox = sel->x;
oy = sel->y;
ow = sel->w;
oh = sel->h;
sel->x = sx;
sel->y = sy + bh;
sel->w = sw - 2;
sel->h = sh - 2 - bh;
restack();
for(c = getnext(clients); c; c = getnext(c->next))
if(c != sel)
ban(c);
resize(sel, arrange == dofloat, TopLeft);
sel->x = ox;
sel->y = oy;
sel->w = ow;
sel->h = oh;
}
else
arrange(NULL);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
unmanage(Client *c)
{
unmanage(Client *c) {
Client *nc;
/* The server grab construct avoids race conditions. */
XGrabServer(dpy);
XSetErrorHandler(xerrordummy);

View File

@ -11,15 +11,15 @@ const char *tags[] = { "dev", "work", "net", "fnord", NULL };
#define TILESYMBOL "[]="
#define FONT "-*-terminus-medium-*-*-*-12-*-*-*-*-*-iso10646-*"
#define SELBGCOLOR "#333366"
#define SELFGCOLOR "#eeeeee"
#define NORMBGCOLOR "#333333"
#define NORMFGCOLOR "#dddddd"
#define SELBGCOLOR "#333366"
#define SELFGCOLOR "#eeeeee"
#define STATUSBGCOLOR "#222222"
#define STATUSFGCOLOR "#9999cc"
#define MODKEY Mod1Mask
#define MASTERW 60 /* percent */
#define MODKEY Mod1Mask
#define KEYS \
static Key key[] = { \
@ -28,12 +28,12 @@ static Key key[] = { \
{ .cmd = "exec uxterm -bg '#111111' -fg '#eeeeee' -cr '#eeeeee' +sb -fn '"FONT"'" } }, \
{ MODKEY, XK_p, spawn, \
{ .cmd = "exe=\"$(IFS=:; for dir in $PATH; do " \
"for file in \"$dir\"/*; do [ -x \"$file\" ] && echo \"${file##*/}\"; done; " \
"done | sort -u | dmenu)\" && exec \"$exe\"" } }, \
"for file in \"$dir\"/*; do [ -x \"$file\" ] && echo \"${file##*/}\"; done; done " \
"| sort -u | dmenu -font '"FONT"' -normbg '"NORMBGCOLOR"' -normfg '"NORMFGCOLOR"' " \
"-selbg '"SELBGCOLOR"' -selfg '"SELFGCOLOR"')\" && exec $exe" } }, \
{ MODKEY, XK_j, focusnext, { 0 } }, \
{ MODKEY, XK_k, focusprev, { 0 } }, \
{ MODKEY, XK_Return, zoom, { 0 } }, \
{ MODKEY, XK_m, togglemax, { 0 } }, \
{ MODKEY, XK_g, resizecol, { .i = 20 } }, \
{ MODKEY, XK_s, resizecol, { .i = -20 } }, \
{ MODKEY|ShiftMask, XK_1, tag, { .i = 0 } }, \
@ -61,7 +61,7 @@ static Key key[] = { \
#define RULES \
static Rule rule[] = { \
/* class:instance:title regex tags regex isfloat */ \
{ "Firefox.*", "net", False }, \
{ "Firefox.*", "net", True}, \
{ "Gimp.*", NULL, True}, \
{ "MPlayer.*", NULL, True}, \
{ "Acroread.*", NULL, True}, \

View File

@ -11,15 +11,15 @@ const char *tags[] = { "1", "2", "3", "4", "5", NULL };
#define TILESYMBOL "[]="
#define FONT "fixed"
#define SELBGCOLOR "#666699"
#define SELFGCOLOR "#eeeeee"
#define NORMBGCOLOR "#333366"
#define NORMFGCOLOR "#cccccc"
#define SELBGCOLOR "#666699"
#define SELFGCOLOR "#eeeeee"
#define STATUSBGCOLOR "#dddddd"
#define STATUSFGCOLOR "#222222"
#define MODKEY Mod1Mask
#define MASTERW 60 /* percent */
#define MODKEY Mod1Mask
#define KEYS \
static Key key[] = { \
@ -28,7 +28,6 @@ static Key key[] = { \
{ MODKEY, XK_Tab, focusnext, { 0 } }, \
{ MODKEY|ShiftMask, XK_Tab, focusprev, { 0 } }, \
{ MODKEY, XK_Return, zoom, { 0 } }, \
{ MODKEY, XK_m, togglemax, { 0 } }, \
{ MODKEY, XK_g, resizecol, { .i = 20 } }, \
{ MODKEY, XK_s, resizecol, { .i = -20 } }, \
{ MODKEY|ShiftMask, XK_1, tag, { .i = 0 } }, \

View File

@ -1,5 +1,5 @@
# dwm version
VERSION = 1.5
VERSION = 1.7
# Customize below to fit your system

29
draw.c
View File

@ -10,8 +10,7 @@
/* static */
static unsigned int
textnw(const char *text, unsigned int len)
{
textnw(const char *text, unsigned int len) {
XRectangle r;
if(dc.font.set) {
@ -22,8 +21,7 @@ textnw(const char *text, unsigned int len)
}
static void
drawtext(const char *text, unsigned long col[ColLast], Bool highlight)
{
drawtext(const char *text, unsigned long col[ColLast], Bool highlight) {
int x, y, w, h;
static char buf[256];
unsigned int len, olen;
@ -82,8 +80,7 @@ drawtext(const char *text, unsigned long col[ColLast], Bool highlight)
/* extern */
void
drawall()
{
drawall(void) {
Client *c;
for(c = clients; c; c = getnext(c->next))
@ -92,8 +89,7 @@ drawall()
}
void
drawstatus()
{
drawstatus(void) {
int i, x;
dc.x = dc.y = 0;
@ -108,7 +104,7 @@ drawstatus()
}
dc.w = bmw;
drawtext(arrange == dotile ? TILESYMBOL : FLOATSYMBOL, dc.status, False);
drawtext(arrange == dofloat ? FLOATSYMBOL : TILESYMBOL, dc.status, False);
x = dc.x + dc.w;
dc.w = textw(stext);
@ -131,8 +127,7 @@ drawstatus()
}
void
drawtitle(Client *c)
{
drawtitle(Client *c) {
if(c == sel && issel) {
drawstatus();
XUnmapWindow(dpy, c->twin);
@ -150,18 +145,17 @@ drawtitle(Client *c)
}
unsigned long
getcolor(const char *colstr)
{
getcolor(const char *colstr) {
Colormap cmap = DefaultColormap(dpy, screen);
XColor color;
XAllocNamedColor(dpy, cmap, colstr, &color, &color);
if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
eprint("error, cannot allocate color '%s'\n", colstr);
return color.pixel;
}
void
setfont(const char *fontstr)
{
setfont(const char *fontstr) {
char **missing, *def;
int i, n;
@ -211,7 +205,6 @@ setfont(const char *fontstr)
}
unsigned int
textw(const char *text)
{
textw(const char *text) {
return textnw(text, strlen(text)) + dc.font.height;
}

7
dwm.1
View File

@ -16,7 +16,7 @@ resized and moved freely. Dialog windows are always managed floating,
regardless of the mode selected.
.P
Windows are grouped by tags. Each window can be tagged with one or multiple
tags. Selecting certain tags displays all windows with that tag.
tags. Selecting certain tags displays all windows with these tags.
.P
dwm contains a small status bar which displays all available tags, the mode,
the title of the focused window, and the text read from standard input. The
@ -60,10 +60,7 @@ Focus next window.
Focus previous window.
.TP
.B Mod1-Return
Zoom current window to the master column (tiling mode only).
.TP
.B Mod1-m
Maximize current window.
Zooms/cycles current window to/from master column (tiling mode), toggles maximization current window (floating mode).
.TP
.B Mod1-g
Grow current column (tiling mode only).

175
dwm.h
View File

@ -1,6 +1,35 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*
* dynamic window manager is designed like any other X client as well. It is
* driven through handling X events. In contrast to other X clients, a window
* manager selects for SubstructureRedirectMask on the root window, to receive
* events about window (dis-)appearance. Only one X connection at a time is
* allowed to select for this event mask.
*
* Calls to fetch an X event from the event queue are blocking. Due reading
* status text from standard input, a select()-driven main loop has been
* implemented which selects for reads on the X connection and STDIN_FILENO to
* handle all data smoothly. The event handlers of dwm are organized in an
* array which is accessed whenever a new event has been fetched. This allows
* event dispatching in O(1) time.
*
* Each child of the root window is called a client, except windows which have
* set the override_redirect flag. Clients are organized in a global
* doubly-linked client list, the focus history is remembered through a global
* stack list. Each client contains an array of Bools of the same size as the
* global tags array to indicate the tags of a client. For each client dwm
* creates a small title window, which is resized whenever the (_NET_)WM_NAME
* properties are updated or the client is moved/resized.
*
* Keys and tagging rules are organized as arrays and defined in the config.h
* file. These arrays are kept static in event.o and tag.o respectively,
* because no other part of dwm needs access to them. The current mode is
* represented by the arrange() function pointer, which wether points to
* dofloat() or dotile().
*
* To understand everything else, start reading main.c:main().
*/
#include "config.h"
@ -11,23 +40,19 @@
#define MOUSEMASK (BUTTONMASK | PointerMotionMask)
#define PROTODELWIN 1
enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMLast }; /* default atoms */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
enum { ColFG, ColBG, ColLast }; /* color */
typedef enum {
TopLeft, TopRight, BotLeft, BotRight
} Corner; /* window corners */
typedef union {
const char *cmd;
int i;
} Arg;
/* atoms */
enum { NetSupported, NetWMName, NetLast };
enum { WMProtocols, WMDelete, WMLast };
/* cursor */
enum { CurNormal, CurResize, CurMove, CurLast };
/* color */
enum { ColFG, ColBG, ColLast };
/* window corners */
typedef enum { TopLeft, TopRight, BotLeft, BotRight } Corner;
} Arg; /* argument type */
typedef struct {
int ascent;
@ -37,7 +62,7 @@ typedef struct {
XFontStruct *xfont;
} Fnt;
typedef struct { /* draw context */
typedef struct {
int x, y, w, h;
unsigned long norm[ColLast];
unsigned long sel[ColLast];
@ -45,19 +70,20 @@ typedef struct { /* draw context */
Drawable drawable;
Fnt font;
GC gc;
} DC;
} DC; /* draw context */
typedef struct Client Client;
struct Client {
char name[256];
int proto;
int x, y, w, h;
int tx, ty, tw, th; /* title */
int rx, ry, rw, rh; /* revert geometry */
int tx, ty, tw, th; /* title window geometry */
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
int grav;
long flags;
unsigned int border, weight;
Bool isfloat;
Bool isfloat, ismax;
Bool *tags;
Client *next;
Client *prev;
@ -66,77 +92,78 @@ struct Client {
Window twin;
};
extern const char *tags[];
extern char stext[1024];
extern int bx, by, bw, bh, bmw, mw, screen, sx, sy, sw, sh;
extern unsigned int ntags, numlockmask;
extern void (*handler[LASTEvent])(XEvent *);
extern void (*arrange)(Arg *);
extern const char *tags[]; /* all tags */
extern char stext[1024]; /* status text */
extern int bx, by, bw, bh, bmw; /* bar geometry, bar mode label width */
extern int mw, screen, sx, sy, sw, sh; /* screen geometry, master width */
extern unsigned int ntags, numlockmask; /* number of tags, dynamic lock mask */
extern void (*handler[LASTEvent])(XEvent *); /* event handler */
extern void (*arrange)(Arg *); /* arrange function, indicates mode */
extern Atom wmatom[WMLast], netatom[NetLast];
extern Bool running, issel, maximized, *seltag;
extern Client *clients, *sel, *stack;
extern Bool running, issel, *seltag; /* seltag is array of Bool */
extern Client *clients, *sel, *stack; /* global client list and stack */
extern Cursor cursor[CurLast];
extern DC dc;
extern DC dc; /* global draw context */
extern Display *dpy;
extern Window root, barwin;
/* client.c */
extern void ban(Client *c);
extern void focus(Client *c);
extern Client *getclient(Window w);
extern Client *getctitle(Window w);
extern void gravitate(Client *c, Bool invert);
extern void killclient(Arg *arg);
extern void manage(Window w, XWindowAttributes *wa);
extern void resize(Client *c, Bool sizehints, Corner sticky);
extern void setsize(Client *c);
extern void settitle(Client *c);
extern void togglemax(Arg *arg);
extern void unmanage(Client *c);
extern void ban(Client *c); /* ban c from screen */
extern void configure(Client *c); /* send synthetic configure event */
extern void focus(Client *c); /* focus c, c may be NULL */
extern Client *getclient(Window w); /* return client of w */
extern Client *getctitle(Window w); /* return client of title window */
extern void gravitate(Client *c, Bool invert); /* gravitate c */
extern void killclient(Arg *arg); /* kill c nicely */
extern void manage(Window w, XWindowAttributes *wa); /* manage new client */
extern void resize(Client *c, Bool sizehints, Corner sticky); /* resize c*/
extern void updatesize(Client *c); /* update the size structs of c */
extern void updatetitle(Client *c); /* update the name of c */
extern void unmanage(Client *c); /* destroy c */
/* draw.c */
extern void drawall();
extern void drawstatus();
extern void drawtitle(Client *c);
extern unsigned long getcolor(const char *colstr);
extern void setfont(const char *fontstr);
extern unsigned int textw(const char *text);
extern void drawall(void); /* draw all visible client titles and the bar */
extern void drawstatus(void); /* draw the bar */
extern void drawtitle(Client *c); /* draw title of c */
extern unsigned long getcolor(const char *colstr); /* return color of colstr */
extern void setfont(const char *fontstr); /* set the font for DC */
extern unsigned int textw(const char *text); /* return the width of text in px*/
/* event.c */
extern void grabkeys();
extern void procevent();
extern void grabkeys(void); /* grab all keys defined in config.h */
extern void procevent(void); /* process pending X events */
/* main.c */
extern int getproto(Window w);
extern void quit(Arg *arg);
extern void sendevent(Window w, Atom a, long value);
extern int xerror(Display *dsply, XErrorEvent *ee);
extern int getproto(Window w); /* return protocol mask of WMProtocols property of w */
extern void quit(Arg *arg); /* quit dwm nicely */
extern void sendevent(Window w, Atom a, long value); /* send synthetic event to w */
extern int xerror(Display *dsply, XErrorEvent *ee); /* dwm's X error handler */
/* tag.c */
extern void initrregs();
extern Client *getnext(Client *c);
extern Client *getprev(Client *c);
extern void settags(Client *c, Client *trans);
extern void tag(Arg *arg);
extern void toggletag(Arg *arg);
extern void initrregs(void); /* initialize regexps of rules defined in config.h */
extern Client *getnext(Client *c); /* returns next visible client */
extern Client *getprev(Client *c); /* returns previous visible client */
extern void settags(Client *c, Client *trans); /* sets tags of c */
extern void tag(Arg *arg); /* tags c with arg's index */
extern void toggletag(Arg *arg); /* toggles c tags with arg's index */
/* util.c */
extern void *emallocz(unsigned int size);
extern void eprint(const char *errstr, ...);
extern void *erealloc(void *ptr, unsigned int size);
extern void spawn(Arg *arg);
extern void *emallocz(unsigned int size); /* allocates zero-initialized memory, exits on error */
extern void eprint(const char *errstr, ...); /* prints errstr and exits with 1 */
extern void *erealloc(void *ptr, unsigned int size); /* reallocates memory, exits on error */
extern void spawn(Arg *arg); /* forks a new subprocess with to arg's cmd */
/* view.c */
extern void detach(Client *c);
extern void dofloat(Arg *arg);
extern void dotile(Arg *arg);
extern void focusnext(Arg *arg);
extern void focusprev(Arg *arg);
extern Bool isvisible(Client *c);
extern void resizecol(Arg *arg);
extern void restack();
extern void togglemode(Arg *arg);
extern void toggleview(Arg *arg);
extern void view(Arg *arg);
extern void viewall(Arg *arg);
extern void zoom(Arg *arg);
extern void detach(Client *c); /* detaches c from global client list */
extern void dofloat(Arg *arg); /* arranges all windows floating, arg is ignored */
extern void dotile(Arg *arg); /* arranges all windows, arg is ignored */
extern void focusnext(Arg *arg); /* focuses next visible client, arg is ignored */
extern void focusprev(Arg *arg); /* focuses previous visible client, arg is ignored */
extern Bool isvisible(Client *c); /* returns True if client is visible */
extern void resizecol(Arg *arg); /* resizes the master width with arg's index value */
extern void restack(void); /* restores z layers of all clients */
extern void togglemode(Arg *arg); /* toggles global arrange function (dotile/dofloat) */
extern void toggleview(Arg *arg); /* toggles the tag with arg's index (in)visible */
extern void view(Arg *arg); /* views the tag with arg's index */
extern void viewall(Arg *arg); /* views all tags, arg is ignored */
extern void zoom(Arg *arg); /* zooms the focused client to master column, arg is ignored */

111
event.c
View File

@ -21,8 +21,7 @@ KEYS
#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
static void
movemouse(Client *c)
{
movemouse(Client *c) {
int x1, y1, ocx, ocy, di;
unsigned int dui;
Window dummy;
@ -33,11 +32,15 @@ movemouse(Client *c)
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurMove], CurrentTime) != GrabSuccess)
return;
c->ismax = False;
XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
for(;;) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask, &ev);
switch (ev.type) {
default: break;
case ButtonRelease:
resize(c, True, TopLeft);
XUngrabPointer(dpy, CurrentTime);
return;
case Expose:
handler[Expose](&ev);
break;
@ -47,16 +50,12 @@ movemouse(Client *c)
c->y = ocy + (ev.xmotion.y - y1);
resize(c, False, TopLeft);
break;
case ButtonRelease:
XUngrabPointer(dpy, CurrentTime);
return;
}
}
}
static void
resizemouse(Client *c)
{
resizemouse(Client *c) {
int ocx, ocy;
int nw, nh;
Corner sticky;
@ -67,20 +66,24 @@ resizemouse(Client *c)
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurResize], CurrentTime) != GrabSuccess)
return;
c->ismax = False;
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w, c->h);
for(;;) {
XMaskEvent(dpy, MOUSEMASK | ExposureMask, &ev);
switch(ev.type) {
default: break;
case ButtonRelease:
resize(c, True, TopLeft);
XUngrabPointer(dpy, CurrentTime);
return;
case Expose:
handler[Expose](&ev);
break;
case MotionNotify:
XSync(dpy, False);
if((nw = abs(ocx - ev.xmotion.x)))
c->w = abs(ocx - ev.xmotion.x);
c->w = nw;
if((nh = abs(ocy - ev.xmotion.y)))
c->h = abs(ocy - ev.xmotion.y);
c->h = nh;
c->x = (ocx <= ev.xmotion.x) ? ocx : ocx - c->w;
c->y = (ocy <= ev.xmotion.y) ? ocy : ocy - c->h;
if(ocx <= ev.xmotion.x)
@ -89,16 +92,12 @@ resizemouse(Client *c)
sticky = (ocy <= ev.xmotion.y) ? TopRight : BotRight;
resize(c, True, sticky);
break;
case ButtonRelease:
XUngrabPointer(dpy, CurrentTime);
return;
}
}
}
static void
buttonpress(XEvent *e)
{
buttonpress(XEvent *e) {
int x;
Arg a;
Client *c;
@ -131,53 +130,31 @@ buttonpress(XEvent *e)
}
else if((c = getclient(ev->window))) {
focus(c);
if(maximized || CLEANMASK(ev->state) != MODKEY)
if(CLEANMASK(ev->state) != MODKEY)
return;
if(ev->button == Button1 && (arrange == dofloat || c->isfloat)) {
restack(c);
restack();
movemouse(c);
}
else if(ev->button == Button2)
zoom(NULL);
else if(ev->button == Button3 && (arrange == dofloat || c->isfloat)) {
restack(c);
restack();
resizemouse(c);
}
}
}
static void
synconfig(Client *c, int x, int y, int w, int h, unsigned int border)
{
XEvent synev;
synev.type = ConfigureNotify;
synev.xconfigure.display = dpy;
synev.xconfigure.event = c->win;
synev.xconfigure.window = c->win;
synev.xconfigure.x = x;
synev.xconfigure.y = y;
synev.xconfigure.width = w;
synev.xconfigure.height = h;
synev.xconfigure.border_width = border;
synev.xconfigure.above = None;
XSendEvent(dpy, c->win, True, NoEventMask, &synev);
}
static void
configurerequest(XEvent *e)
{
configurerequest(XEvent *e) {
unsigned long newmask;
Client *c;
XConfigureRequestEvent *ev = &e->xconfigurerequest;
XEvent synev;
XWindowChanges wc;
if((c = getclient(ev->window))) {
if((c == sel) && !c->isfloat && (arrange != dofloat) && maximized) {
synconfig(c, sx, sy + bh, sw - 2, sh - 2 - bh, ev->border_width);
XSync(dpy, False);
return;
}
c->ismax = False;
gravitate(c, True);
if(ev->value_mask & CWX)
c->x = ev->x;
@ -198,7 +175,7 @@ configurerequest(XEvent *e)
if(newmask)
XConfigureWindow(dpy, c->win, newmask, &wc);
else
synconfig(c, c->x, c->y, c->w, c->h, c->border);
configure(c);
XSync(dpy, False);
if(c->isfloat)
resize(c, False, TopLeft);
@ -219,8 +196,7 @@ configurerequest(XEvent *e)
}
static void
destroynotify(XEvent *e)
{
destroynotify(XEvent *e) {
Client *c;
XDestroyWindowEvent *ev = &e->xdestroywindow;
@ -229,15 +205,14 @@ destroynotify(XEvent *e)
}
static void
enternotify(XEvent *e)
{
enternotify(XEvent *e) {
Client *c;
XCrossingEvent *ev = &e->xcrossing;
if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
return;
if((c = getclient(ev->window)) || (c = getctitle(ev->window)))
if(((c = getclient(ev->window)) || (c = getctitle(ev->window))) && isvisible(c))
focus(c);
else if(ev->window == root) {
issel = True;
@ -247,8 +222,7 @@ enternotify(XEvent *e)
}
static void
expose(XEvent *e)
{
expose(XEvent *e) {
Client *c;
XExposeEvent *ev = &e->xexpose;
@ -261,8 +235,7 @@ expose(XEvent *e)
}
static void
keypress(XEvent *e)
{
keypress(XEvent *e) {
static unsigned int len = sizeof(key) / sizeof(key[0]);
unsigned int i;
KeySym keysym;
@ -270,8 +243,8 @@ keypress(XEvent *e)
keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
for(i = 0; i < len; i++) {
if(keysym == key[i].keysym &&
CLEANMASK(key[i].mod) == CLEANMASK(ev->state))
if(keysym == key[i].keysym
&& CLEANMASK(key[i].mod) == CLEANMASK(ev->state))
{
if(key[i].func)
key[i].func(&key[i].arg);
@ -281,8 +254,7 @@ keypress(XEvent *e)
}
static void
leavenotify(XEvent *e)
{
leavenotify(XEvent *e) {
XCrossingEvent *ev = &e->xcrossing;
if((ev->window == root) && !ev->same_screen) {
@ -292,8 +264,7 @@ leavenotify(XEvent *e)
}
static void
mappingnotify(XEvent *e)
{
mappingnotify(XEvent *e) {
XMappingEvent *ev = &e->xmapping;
XRefreshKeyboardMapping(ev);
@ -302,8 +273,7 @@ mappingnotify(XEvent *e)
}
static void
maprequest(XEvent *e)
{
maprequest(XEvent *e) {
static XWindowAttributes wa;
XMapRequestEvent *ev = &e->xmaprequest;
@ -321,8 +291,7 @@ maprequest(XEvent *e)
}
static void
propertynotify(XEvent *e)
{
propertynotify(XEvent *e) {
Client *c;
Window trans;
XPropertyEvent *ev = &e->xproperty;
@ -343,19 +312,18 @@ propertynotify(XEvent *e)
arrange(NULL);
break;
case XA_WM_NORMAL_HINTS:
setsize(c);
updatesize(c);
break;
}
if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
settitle(c);
updatetitle(c);
drawtitle(c);
}
}
}
static void
unmapnotify(XEvent *e)
{
unmapnotify(XEvent *e) {
Client *c;
XUnmapEvent *ev = &e->xunmap;
@ -380,8 +348,7 @@ void (*handler[LASTEvent]) (XEvent *) = {
};
void
grabkeys()
{
grabkeys(void) {
static unsigned int len = sizeof(key) / sizeof(key[0]);
unsigned int i;
KeyCode code;
@ -401,8 +368,7 @@ grabkeys()
}
void
procevent()
{
procevent(void) {
XEvent ev;
while(XPending(dpy)) {
@ -411,4 +377,3 @@ procevent()
(handler[ev.type])(&ev); /* call handler */
}
}

38
main.c
View File

@ -24,7 +24,6 @@ unsigned int ntags, numlockmask;
Atom wmatom[WMLast], netatom[NetLast];
Bool running = True;
Bool issel = True;
Bool maximized = False;
Client *clients = NULL;
Client *sel = NULL;
Client *stack = NULL;
@ -39,8 +38,7 @@ static int (*xerrorxlib)(Display *, XErrorEvent *);
static Bool otherwm, readin;
static void
cleanup()
{
cleanup(void) {
close(STDIN_FILENO);
while(sel) {
resize(sel, True, TopLeft);
@ -60,8 +58,7 @@ cleanup()
}
static void
scan()
{
scan(void) {
unsigned int i, num;
Window *wins, d1, d2;
XWindowAttributes wa;
@ -82,8 +79,7 @@ scan()
}
static void
setup()
{
setup(void) {
int i, j;
unsigned int mask;
Window w;
@ -112,7 +108,8 @@ setup()
}
XFree(modmap);
wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask | EnterWindowMask | LeaveWindowMask;
wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
| EnterWindowMask | LeaveWindowMask;
wa.cursor = cursor[CurNormal];
XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
@ -163,8 +160,7 @@ setup()
* is already running.
*/
static int
xerrorstart(Display *dsply, XErrorEvent *ee)
{
xerrorstart(Display *dsply, XErrorEvent *ee) {
otherwm = True;
return -1;
}
@ -172,8 +168,7 @@ xerrorstart(Display *dsply, XErrorEvent *ee)
/* extern */
int
getproto(Window w)
{
getproto(Window w) {
int i, format, protos, status;
unsigned long extra, res;
Atom *protocols, real;
@ -191,8 +186,7 @@ getproto(Window w)
}
void
sendevent(Window w, Atom a, long value)
{
sendevent(Window w, Atom a, long value) {
XEvent e;
e.type = ClientMessage;
@ -206,35 +200,33 @@ sendevent(Window w, Atom a, long value)
}
void
quit(Arg *arg)
{
quit(Arg *arg) {
readin = running = False;
}
/*
* There's no way to check accesses to destroyed windows, thus those cases are
* ignored (especially on UnmapNotify's). Other types of errors call Xlibs
* default error handler, which calls exit().
* default error handler, which may call exit.
*/
int
xerror(Display *dpy, XErrorEvent *ee)
{
xerror(Display *dpy, XErrorEvent *ee) {
if(ee->error_code == BadWindow
|| (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
|| (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
|| (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
|| (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
|| (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
|| (ee->request_code == X_GrabKey && ee->error_code == BadAccess))
|| (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
|| (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
return 0;
fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
ee->request_code, ee->error_code);
return xerrorxlib(dpy, ee); /* may call exit() */
return xerrorxlib(dpy, ee); /* may call exit */
}
int
main(int argc, char *argv[])
{
main(int argc, char *argv[]) {
int r, xfd;
fd_set rd;

18
tag.c
View File

@ -33,22 +33,19 @@ static unsigned int len = 0;
/* extern */
Client *
getnext(Client *c)
{
getnext(Client *c) {
for(; c && !isvisible(c); c = c->next);
return c;
}
Client *
getprev(Client *c)
{
getprev(Client *c) {
for(; c && !isvisible(c); c = c->prev);
return c;
}
void
initrregs()
{
initrregs(void) {
unsigned int i;
regex_t *reg;
@ -76,8 +73,7 @@ initrregs()
}
void
settags(Client *c, Client *trans)
{
settags(Client *c, Client *trans) {
char prop[512];
unsigned int i, j;
regmatch_t tmp;
@ -114,8 +110,7 @@ settags(Client *c, Client *trans)
}
void
tag(Arg *arg)
{
tag(Arg *arg) {
unsigned int i;
if(!sel)
@ -129,8 +124,7 @@ tag(Arg *arg)
}
void
toggletag(Arg *arg)
{
toggletag(Arg *arg) {
unsigned int i;
if(!sel)

15
util.c
View File

@ -12,8 +12,7 @@
/* extern */
void *
emallocz(unsigned int size)
{
emallocz(unsigned int size) {
void *res = calloc(1, size);
if(!res)
@ -22,8 +21,7 @@ emallocz(unsigned int size)
}
void
eprint(const char *errstr, ...)
{
eprint(const char *errstr, ...) {
va_list ap;
va_start(ap, errstr);
@ -33,8 +31,7 @@ eprint(const char *errstr, ...)
}
void *
erealloc(void *ptr, unsigned int size)
{
erealloc(void *ptr, unsigned int size) {
void *res = realloc(ptr, size);
if(!res)
eprint("fatal: could not malloc() %u bytes\n", size);
@ -42,8 +39,7 @@ erealloc(void *ptr, unsigned int size)
}
void
spawn(Arg *arg)
{
spawn(Arg *arg) {
static char *shell = NULL;
if(!shell && !(shell = getenv("SHELL")))
@ -51,7 +47,8 @@ spawn(Arg *arg)
if(!arg->cmd)
return;
/* the double-fork construct avoids zombie processes */
/* The double-fork construct avoids zombie processes and keeps the code
* clean from stupid signal handlers. */
if(fork() == 0) {
if(fork() == 0) {
if(dpy)

97
view.c
View File

@ -3,13 +3,11 @@
* See LICENSE file for license details.
*/
#include "dwm.h"
#include <stdio.h>
/* static */
static Client *
minclient()
{
minclient(void) {
Client *c, *min;
if((clients && clients->isfloat) || arrange == dofloat)
@ -20,9 +18,14 @@ minclient()
return min;
}
static Client *
nexttiled(Client *c) {
for(c = getnext(c); c && c->isfloat; c = getnext(c->next));
return c;
}
static void
reorder()
{
reorder(void) {
Client *c, *newclients, *tail;
newclients = tail = NULL;
@ -39,11 +42,24 @@ reorder()
clients = newclients;
}
static Client *
nexttiled(Client *c)
static void
togglemax(Client *c)
{
for(c = getnext(c); c && c->isfloat; c = getnext(c->next));
return c;
XEvent ev;
if((c->ismax = !c->ismax)) {
c->rx = c->x; c->x = sx;
c->ry = c->y; c->y = bh;
c->rw = c->w; c->w = sw;
c->rh = c->h; c->h = sh - bh - 2;
}
else {
c->x = c->rx;
c->y = c->ry;
c->w = c->rw;
c->h = c->rh;
}
resize(c, True, TopLeft);
while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
/* extern */
@ -51,8 +67,7 @@ nexttiled(Client *c)
void (*arrange)(Arg *) = DEFMODE;
void
detach(Client *c)
{
detach(Client *c) {
if(c->prev)
c->prev->next = c->next;
if(c->next)
@ -63,12 +78,9 @@ detach(Client *c)
}
void
dofloat(Arg *arg)
{
dofloat(Arg *arg) {
Client *c;
maximized = False;
for(c = clients; c; c = c->next) {
if(isvisible(c)) {
resize(c, True, TopLeft);
@ -84,17 +96,13 @@ dofloat(Arg *arg)
}
void
dotile(Arg *arg)
{
dotile(Arg *arg) {
int h, i, n, w;
Client *c;
maximized = False;
w = sw - mw;
for(n = 0, c = clients; c; c = c->next)
if(isvisible(c) && !c->isfloat)
n++;
for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
n++;
if(n > 1)
h = (sh - bh) / (n - 1);
@ -107,6 +115,7 @@ dotile(Arg *arg)
resize(c, True, TopLeft);
continue;
}
c->ismax = False;
if(n == 1) {
c->x = sx;
c->y = sy + bh;
@ -148,8 +157,7 @@ dotile(Arg *arg)
}
void
focusnext(Arg *arg)
{
focusnext(Arg *arg) {
Client *c;
if(!sel)
@ -164,8 +172,7 @@ focusnext(Arg *arg)
}
void
focusprev(Arg *arg)
{
focusprev(Arg *arg) {
Client *c;
if(!sel)
@ -182,8 +189,7 @@ focusprev(Arg *arg)
}
Bool
isvisible(Client *c)
{
isvisible(Client *c) {
unsigned int i;
for(i = 0; i < ntags; i++)
@ -193,15 +199,14 @@ isvisible(Client *c)
}
void
resizecol(Arg *arg)
{
resizecol(Arg *arg) {
unsigned int n;
Client *c;
for(n = 0, c = clients; c; c = c->next)
if(isvisible(c) && !c->isfloat)
n++;
if(!sel || sel->isfloat || n < 2 || (arrange != dotile) || maximized)
if(!sel || sel->isfloat || n < 2 || (arrange == dofloat))
return;
if(sel == getnext(clients)) {
@ -218,11 +223,10 @@ resizecol(Arg *arg)
}
void
restack()
{
restack(void) {
Client *c;
XEvent ev;
if(!sel) {
drawstatus();
return;
@ -242,8 +246,7 @@ restack()
}
void
togglemode(Arg *arg)
{
togglemode(Arg *arg) {
arrange = (arrange == dofloat) ? dotile : dofloat;
if(sel)
arrange(NULL);
@ -252,8 +255,7 @@ togglemode(Arg *arg)
}
void
toggleview(Arg *arg)
{
toggleview(Arg *arg) {
unsigned int i;
seltag[arg->i] = !seltag[arg->i];
@ -265,8 +267,7 @@ toggleview(Arg *arg)
}
void
view(Arg *arg)
{
view(Arg *arg) {
unsigned int i;
for(i = 0; i < ntags; i++)
@ -277,8 +278,7 @@ view(Arg *arg)
}
void
viewall(Arg *arg)
{
viewall(Arg *arg) {
unsigned int i;
for(i = 0; i < ntags; i++)
@ -288,15 +288,22 @@ viewall(Arg *arg)
}
void
zoom(Arg *arg)
{
zoom(Arg *arg) {
unsigned int n;
Client *c;
if(!sel)
return;
if(sel->isfloat || (arrange == dofloat)) {
togglemax(sel);
return;
}
for(n = 0, c = clients; c; c = c->next)
if(isvisible(c) && !c->isfloat)
n++;
if(!sel || sel->isfloat || n < 2 || (arrange != dotile) || maximized)
if(n < 2 || (arrange == dofloat))
return;
if((c = sel) == nexttiled(clients))