# HG changeset patch # User meillo@marmaro.de # Date 1212095550 -7200 # Node ID 4c12dccc288d1fd36c364ef044a7076aa519d6c1 # Parent c459e05a61a8ba4efa882f6d5d9c80f0267ed32f this is the (second) begin of aewl - my personal stipped down dwm diff -r c459e05a61a8 -r 4c12dccc288d Makefile --- a/Makefile Sat Jun 16 21:49:51 2007 +0200 +++ b/Makefile Thu May 29 23:12:30 2008 +0200 @@ -3,8 +3,6 @@ include config.mk -SRC = client.c draw.c event.c main.c tag.c util.c view.c -OBJ = ${SRC:.c=.o} all: options dwm @@ -14,19 +12,13 @@ @echo "LDFLAGS = ${LDFLAGS}" @echo "CC = ${CC}" -.c.o: +dwm.o: dwm.c config.h config.mk @echo CC $< @${CC} -c ${CFLAGS} $< -${OBJ}: dwm.h config.h config.mk - -config.h: config.meillo.h - @echo creating $@ from config.meillo.h - @cp config.meillo.h $@ - -dwm: ${OBJ} +dwm: dwm.o @echo CC -o $@ - @${CC} -o $@ ${OBJ} ${LDFLAGS} + @${CC} -o $@ dwm.o ${LDFLAGS} @strip $@ clean: diff -r c459e05a61a8 -r 4c12dccc288d client.c --- a/client.c Sat Jun 16 21:49:51 2007 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,356 +0,0 @@ -/* (C)opyright MMVI-MMVII Anselm R. Garbe - * See LICENSE file for license details. - */ -#include "dwm.h" -#include -#include -#include -#include - -/* static */ - -static void -detachstack(Client *c) { - Client **tc; - for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext); - *tc = c->snext; -} - -static void -grabbuttons(Client *c, Bool focused) { - XUngrabButton(dpy, AnyButton, AnyModifier, c->win); - - if(focused) { - XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK, - GrabModeAsync, GrabModeSync, None, None); - XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK, - GrabModeAsync, GrabModeSync, None, None); - XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK, - GrabModeAsync, GrabModeSync, None, None); - XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK, - GrabModeAsync, GrabModeSync, None, None); - - XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK, - GrabModeAsync, GrabModeSync, None, None); - XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK, - GrabModeAsync, GrabModeSync, None, None); - XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK, - GrabModeAsync, GrabModeSync, None, None); - XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK, - GrabModeAsync, GrabModeSync, None, None); - - XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK, - GrabModeAsync, GrabModeSync, None, None); - XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK, - GrabModeAsync, GrabModeSync, None, None); - XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK, - GrabModeAsync, GrabModeSync, None, None); - XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK, - GrabModeAsync, GrabModeSync, None, None); - } - else - XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK, - GrabModeAsync, GrabModeSync, None, None); -} - -static void -setclientstate(Client *c, long state) { - long data[] = {state, None}; - XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, - PropModeReplace, (unsigned char *)data, 2); -} - -static int -xerrordummy(Display *dsply, XErrorEvent *ee) { - return 0; -} - -/* extern */ - -void -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) { - if(c && !isvisible(c)) - return; - if(sel && sel != c) { - grabbuttons(sel, False); - XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]); - } - if(c) { - detachstack(c); - c->snext = stack; - stack = c; - grabbuttons(c, True); - } - sel = c; - drawstatus(); - if(!selscreen) - return; - if(c) { - XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]); - XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); - } - else - XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); -} - -Client * -getclient(Window w) { - Client *c; - - for(c = clients; c; c = c->next) - if(c->win == w) - return c; - return NULL; -} - -Bool -isprotodel(Client *c) { - int i, n; - Atom *protocols; - Bool ret = False; - - if(XGetWMProtocols(dpy, c->win, &protocols, &n)) { - for(i = 0; !ret && i < n; i++) - if(protocols[i] == wmatom[WMDelete]) - ret = True; - XFree(protocols); - } - return ret; -} - -void -killclient(Arg *arg) { - if(!sel) - return; - if(isprotodel(sel)) - sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]); - else - XKillClient(dpy, sel->win); -} - -void -manage(Window w, XWindowAttributes *wa) { - Client *c; - Window trans; - - c = emallocz(sizeof(Client)); - c->tags = emallocz(ntags * sizeof(Bool)); - c->win = w; - c->x = wa->x; - c->y = wa->y; - c->w = wa->width; - c->h = wa->height; - if(c->w == sw && c->h == sh) { - c->border = 0; - c->x = sx; - c->y = sy; - } - else { - c->border = BORDERPX; - if(c->x + c->w + 2 * c->border > wax + waw) - c->x = wax + waw - c->w - 2 * c->border; - if(c->y + c->h + 2 * c->border > way + wah) - c->y = way + wah - c->h - 2 * c->border; - if(c->x < wax) - c->x = wax; - if(c->y < way) - c->y = way; - } - updatesizehints(c); - XSelectInput(dpy, c->win, - StructureNotifyMask | PropertyChangeMask | EnterWindowMask); - XGetTransientForHint(dpy, c->win, &trans); - grabbuttons(c, False); - XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]); - updatetitle(c); - settags(c, getclient(trans)); - if(!c->isfloat) - c->isfloat = trans || c->isfixed; - if(clients) - clients->prev = c; - c->next = clients; - c->snext = stack; - stack = clients = c; - XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); - XMapWindow(dpy, c->win); - setclientstate(c, NormalState); - if(isvisible(c)) - focus(c); - arrange(); -} - -void -resize(Client *c, Bool sizehints) { - float actual, dx, dy, max, min; - XWindowChanges wc; - - if(c->w <= 0 || c->h <= 0) - return; - if(sizehints) { - if(c->minw && c->w < c->minw) - c->w = c->minw; - if(c->minh && c->h < c->minh) - c->h = c->minh; - if(c->maxw && c->w > c->maxw) - c->w = c->maxw; - if(c->maxh && c->h > c->maxh) - c->h = c->maxh; - /* inspired by algorithm from fluxbox */ - if(c->minay > 0 && c->maxay && (c->h - c->baseh) > 0) { - dx = (float)(c->w - c->basew); - dy = (float)(c->h - c->baseh); - min = (float)(c->minax) / (float)(c->minay); - max = (float)(c->maxax) / (float)(c->maxay); - actual = dx / dy; - if(max > 0 && min > 0 && actual > 0) { - if(actual < min) { - dy = (dx * min + dy) / (min * min + 1); - dx = dy * min; - c->w = (int)dx + c->basew; - c->h = (int)dy + c->baseh; - } - else if(actual > max) { - dy = (dx * min + dy) / (max * max + 1); - dx = dy * min; - c->w = (int)dx + c->basew; - c->h = (int)dy + c->baseh; - } - } - } - if(c->incw) - c->w -= (c->w - c->basew) % c->incw; - if(c->inch) - c->h -= (c->h - c->baseh) % c->inch; - } - if(c->w == sw && c->h == sh) - c->border = 0; - else - c->border = BORDERPX; - /* offscreen appearance fixes */ - if(c->x > sw) - c->x = sw - c->w - 2 * c->border; - if(c->y > sh) - c->y = sh - c->h - 2 * c->border; - if(c->x + c->w + 2 * c->border < sx) - c->x = sx; - if(c->y + c->h + 2 * c->border < sy) - c->y = sy; - wc.x = c->x; - wc.y = c->y; - wc.width = c->w; - wc.height = c->h; - wc.border_width = c->border; - XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc); - configure(c); - XSync(dpy, False); -} - -void -updatesizehints(Client *c) { - long msize; - XSizeHints size; - - if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags) - size.flags = PSize; - c->flags = size.flags; - if(c->flags & PBaseSize) { - c->basew = size.base_width; - c->baseh = size.base_height; - } - else - c->basew = c->baseh = 0; - if(c->flags & PResizeInc) { - c->incw = size.width_inc; - c->inch = size.height_inc; - } - else - c->incw = c->inch = 0; - if(c->flags & PMaxSize) { - c->maxw = size.max_width; - c->maxh = size.max_height; - } - else - c->maxw = c->maxh = 0; - if(c->flags & PMinSize) { - c->minw = size.min_width; - c->minh = size.min_height; - } - else - c->minw = c->minh = 0; - if(c->flags & PAspect) { - c->minax = size.min_aspect.x; - c->minay = size.min_aspect.y; - c->maxax = size.max_aspect.x; - c->maxay = size.max_aspect.y; - } - else - c->minax = c->minay = c->maxax = c->maxay = 0; - c->isfixed = (c->maxw && c->minw && c->maxh && c->minh && - c->maxw == c->minw && c->maxh == c->minh); -} - -void -updatetitle(Client *c) { - char **list = NULL; - int n; - XTextProperty name; - - name.nitems = 0; - c->name[0] = 0; - XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]); - if(!name.nitems) - XGetWMName(dpy, c->win, &name); - if(!name.nitems) - return; - if(name.encoding == XA_STRING) - strncpy(c->name, (char *)name.value, sizeof c->name); - else { - if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success - && n > 0 && *list) - { - strncpy(c->name, *list, sizeof c->name); - XFreeStringList(list); - } - } - XFree(name.value); -} - -void -unmanage(Client *c) { - Client *nc; - - /* The server grab construct avoids race conditions. */ - XGrabServer(dpy); - XSetErrorHandler(xerrordummy); - detach(c); - detachstack(c); - if(sel == c) { - for(nc = stack; nc && !isvisible(nc); nc = nc->snext); - focus(nc); - } - XUngrabButton(dpy, AnyButton, AnyModifier, c->win); - setclientstate(c, WithdrawnState); - free(c->tags); - free(c); - XSync(dpy, False); - XSetErrorHandler(xerror); - XUngrabServer(dpy); - arrange(); -} diff -r c459e05a61a8 -r 4c12dccc288d config.arg.h --- a/config.arg.h Sat Jun 16 21:49:51 2007 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* (C)opyright MMVI-MMVII Anselm R. Garbe - * See LICENSE file for license details. - */ - -#define TAGS \ -const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL }; - -#define BORDERPX 1 -#define DEFMODE dotile /* dofloat */ -#define FLOATSYMBOL "><>" -#define TILESYMBOL "[]=" - -#define FONT "-*-terminus-medium-r-*-*-14-*-*-*-*-*-*-*" -#define NORMBORDERCOLOR "#333" -#define NORMBGCOLOR "#222" -#define NORMFGCOLOR "#ccc" -#define SELBORDERCOLOR "#69c" -#define SELBGCOLOR "#555" -#define SELFGCOLOR "#fff" - -#define MASTER 600 /* per thousand */ -#define MODKEY Mod1Mask -#define NMASTER 1 /* clients in master area */ -#define SNAP 40 /* pixel */ -#define TOPBAR True /* False */ - -#define KEYS \ -static Key key[] = { \ - /* modifier key function argument */ \ - { MODKEY|ShiftMask, XK_Return, spawn, \ - { .cmd = "exec uxterm -bg '#222' -fg '#eee' -cr '#eee' +sb -fn '"FONT"'" } }, \ - { MODKEY, XK_p, spawn, \ - { .cmd = "exe=\"$(lsx `echo $PATH | sed 's/:/ /g'` | sort -u " \ - " | dmenu -fn '"FONT"' -nb '"NORMBGCOLOR"' -nf '"NORMFGCOLOR"' " \ - "-sb '"SELBGCOLOR"' -sf '"SELFGCOLOR"')\" && exec $exe" } }, \ - { MODKEY, XK_j, focusnext, { 0 } }, \ - { MODKEY, XK_k, focusprev, { 0 } }, \ - { MODKEY, XK_Return, zoom, { 0 } }, \ - { MODKEY, XK_g, resizemaster, { .i = 15 } }, \ - { MODKEY, XK_s, resizemaster, { .i = -15 } }, \ - { MODKEY, XK_i, incnmaster, { .i = 1 } }, \ - { MODKEY, XK_d, incnmaster, { .i = -1 } }, \ - { MODKEY|ShiftMask, XK_0, tag, { .i = -1 } }, \ - { MODKEY|ShiftMask, XK_1, tag, { .i = 0 } }, \ - { MODKEY|ShiftMask, XK_2, tag, { .i = 1 } }, \ - { MODKEY|ShiftMask, XK_3, tag, { .i = 2 } }, \ - { MODKEY|ShiftMask, XK_4, tag, { .i = 3 } }, \ - { MODKEY|ShiftMask, XK_5, tag, { .i = 4 } }, \ - { MODKEY|ShiftMask, XK_6, tag, { .i = 5 } }, \ - { MODKEY|ShiftMask, XK_7, tag, { .i = 6 } }, \ - { MODKEY|ShiftMask, XK_8, tag, { .i = 7 } }, \ - { MODKEY|ShiftMask, XK_9, tag, { .i = 8 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_1, toggletag, { .i = 0 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_2, toggletag, { .i = 1 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_3, toggletag, { .i = 2 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_4, toggletag, { .i = 3 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_5, toggletag, { .i = 4 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_6, toggletag, { .i = 5 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_7, toggletag, { .i = 6 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_8, toggletag, { .i = 7 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_9, toggletag, { .i = 8 } }, \ - { MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \ - { MODKEY, XK_space, togglemode, { 0 } }, \ - { MODKEY|ShiftMask, XK_space, togglefloat, { 0 } }, \ - { MODKEY, XK_0, view, { .i = -1 } }, \ - { MODKEY, XK_1, view, { .i = 0 } }, \ - { MODKEY, XK_2, view, { .i = 1 } }, \ - { MODKEY, XK_3, view, { .i = 2 } }, \ - { MODKEY, XK_4, view, { .i = 3 } }, \ - { MODKEY, XK_5, view, { .i = 4 } }, \ - { MODKEY, XK_6, view, { .i = 5 } }, \ - { MODKEY, XK_7, view, { .i = 6 } }, \ - { MODKEY, XK_8, view, { .i = 7 } }, \ - { MODKEY, XK_9, view, { .i = 8 } }, \ - { MODKEY|ControlMask, XK_1, toggleview, { .i = 0 } }, \ - { MODKEY|ControlMask, XK_2, toggleview, { .i = 1 } }, \ - { MODKEY|ControlMask, XK_3, toggleview, { .i = 2 } }, \ - { MODKEY|ControlMask, XK_4, toggleview, { .i = 3 } }, \ - { MODKEY|ControlMask, XK_5, toggleview, { .i = 4 } }, \ - { MODKEY|ControlMask, XK_6, toggleview, { .i = 5 } }, \ - { MODKEY|ControlMask, XK_7, toggleview, { .i = 6 } }, \ - { MODKEY|ControlMask, XK_8, toggleview, { .i = 7 } }, \ - { MODKEY|ControlMask, XK_9, toggleview, { .i = 8 } }, \ - { MODKEY|ShiftMask, XK_q, quit, { 0 } }, \ -}; - -#define RULES \ -static Rule rule[] = { \ - /* class:instance:title regex tags regex isfloat */ \ - { "Firefox.*", "3", False }, \ - { "Gimp.*", NULL, True }, \ - { "MPlayer.*", NULL, True }, \ - { "Acroread.*", NULL, True }, \ -}; diff -r c459e05a61a8 -r 4c12dccc288d config.default.h --- a/config.default.h Sat Jun 16 21:49:51 2007 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* (C)opyright MMVI-MMVII Anselm R. Garbe - * See LICENSE file for license details. - */ - -#define TAGS \ -const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL }; - -#define BORDERPX 1 -#define DEFMODE dotile /* dofloat */ -#define FLOATSYMBOL "><>" -#define TILESYMBOL "[]=" - -#define FONT "-*-fixed-medium-r-normal-*-13-*-*-*-*-*-*-*" -#define NORMBORDERCOLOR "#dddddd" -#define NORMBGCOLOR "#eeeeee" -#define NORMFGCOLOR "#222222" -#define SELBORDERCOLOR "#ff0000" -#define SELBGCOLOR "#006699" -#define SELFGCOLOR "#ffffff" - -#define MASTER 600 /* per thousand */ -#define MODKEY Mod1Mask -#define NMASTER 1 /* clients in master area */ -#define SNAP 20 /* pixel */ -#define TOPBAR True /* False */ - -#define KEYS \ -static Key key[] = { \ - /* modifier key function argument */ \ - { MODKEY|ShiftMask, XK_Return, spawn, { .cmd = "exec xterm" } }, \ - { MODKEY, XK_Tab, focusnext, { 0 } }, \ - { MODKEY|ShiftMask, XK_Tab, focusprev, { 0 } }, \ - { MODKEY, XK_Return, zoom, { 0 } }, \ - { MODKEY, XK_g, resizemaster, { .i = 15 } }, \ - { MODKEY, XK_s, resizemaster, { .i = -15 } }, \ - { MODKEY, XK_i, incnmaster, { .i = 1 } }, \ - { MODKEY, XK_d, incnmaster, { .i = -1 } }, \ - { MODKEY|ShiftMask, XK_0, tag, { .i = -1 } }, \ - { MODKEY|ShiftMask, XK_1, tag, { .i = 0 } }, \ - { MODKEY|ShiftMask, XK_2, tag, { .i = 1 } }, \ - { MODKEY|ShiftMask, XK_3, tag, { .i = 2 } }, \ - { MODKEY|ShiftMask, XK_4, tag, { .i = 3 } }, \ - { MODKEY|ShiftMask, XK_5, tag, { .i = 4 } }, \ - { MODKEY|ShiftMask, XK_6, tag, { .i = 5 } }, \ - { MODKEY|ShiftMask, XK_7, tag, { .i = 6 } }, \ - { MODKEY|ShiftMask, XK_8, tag, { .i = 7 } }, \ - { MODKEY|ShiftMask, XK_9, tag, { .i = 8 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_1, toggletag, { .i = 0 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_2, toggletag, { .i = 1 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_3, toggletag, { .i = 2 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_4, toggletag, { .i = 3 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_5, toggletag, { .i = 4 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_6, toggletag, { .i = 5 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_7, toggletag, { .i = 6 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_8, toggletag, { .i = 7 } }, \ - { MODKEY|ControlMask|ShiftMask, XK_9, toggletag, { .i = 8 } }, \ - { MODKEY|ShiftMask, XK_c, killclient, { 0 } }, \ - { MODKEY, XK_space, togglemode, { 0 } }, \ - { MODKEY|ShiftMask, XK_space, togglefloat, { 0 } }, \ - { MODKEY, XK_0, view, { .i = -1 } }, \ - { MODKEY, XK_1, view, { .i = 0 } }, \ - { MODKEY, XK_2, view, { .i = 1 } }, \ - { MODKEY, XK_3, view, { .i = 2 } }, \ - { MODKEY, XK_4, view, { .i = 3 } }, \ - { MODKEY, XK_5, view, { .i = 4 } }, \ - { MODKEY, XK_6, view, { .i = 5 } }, \ - { MODKEY, XK_7, view, { .i = 6 } }, \ - { MODKEY, XK_8, view, { .i = 7 } }, \ - { MODKEY, XK_9, view, { .i = 8 } }, \ - { MODKEY|ControlMask, XK_1, toggleview, { .i = 0 } }, \ - { MODKEY|ControlMask, XK_2, toggleview, { .i = 1 } }, \ - { MODKEY|ControlMask, XK_3, toggleview, { .i = 2 } }, \ - { MODKEY|ControlMask, XK_4, toggleview, { .i = 3 } }, \ - { MODKEY|ControlMask, XK_5, toggleview, { .i = 4 } }, \ - { MODKEY|ControlMask, XK_6, toggleview, { .i = 5 } }, \ - { MODKEY|ControlMask, XK_7, toggleview, { .i = 6 } }, \ - { MODKEY|ControlMask, XK_8, toggleview, { .i = 7 } }, \ - { MODKEY|ControlMask, XK_9, toggleview, { .i = 8 } }, \ - { MODKEY|ShiftMask, XK_q, quit, { 0 } }, \ -}; - -/* Query class:instance:title for regex matching info with following command: - * xprop | awk -F '"' '/^WM_CLASS/ { printf("%s:%s:",$4,$2) }; /^WM_NAME/ { printf("%s\n",$2) }' */ -#define RULES \ -static Rule rule[] = { \ - /* class:instance:title regex tags regex isfloat */ \ - { "Gimp.*", NULL, True }, \ - { "MPlayer.*", NULL, True }, \ - { "Acroread.*", NULL, True }, \ -}; diff -r c459e05a61a8 -r 4c12dccc288d config.meillo.h --- a/config.meillo.h Sat Jun 16 21:49:51 2007 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* (C)opyright MMVI-MMVII Anselm R. Garbe - * See LICENSE file for license details. - */ - -#define TAGS \ -const char *tags[] = { "Das Alles", "Das Nichts", NULL }; - -#define BORDERPX 1 -#define DEFMODE domax /* dotile */ -#define FLOATSYMBOL "" -#define TILESYMBOL "" - -#define FONT "-*-terminus-medium-*-*-*-12-*-*-*-*-*-*-*" -#define NORMBGCOLOR "#333333" -#define NORMFGCOLOR "#bbbbbb" -#define SELBGCOLOR "#eec900" -#define SELFGCOLOR "#000000" -#define NORMBORDERCOLOR NORMBGCOLOR -#define SELBORDERCOLOR SELBGCOLOR - -#define MASTER 500 /* per thousand */ -#define MODKEY Mod1Mask -#define NMASTER 1 /* clients in master area */ -#define SNAP 5 /* pixel */ -#define TOPBAR True /* False */ - -#define KEYS \ -static Key key[] = { \ - /* modifier key function argument */ \ - { MODKEY|ShiftMask, XK_Return, spawn, { .cmd = "exec urxvt" } }, \ - { MODKEY, XK_F1, viewnext, { .i = 0 } }, \ - { MODKEY, XK_Tab, focusnext, { 0 } }, \ - { MODKEY, XK_asciicircum, spawn, \ - { .cmd = "exe=\"$(lsx `echo $PATH | sed 's/:/ /g'` | sort -u " \ - " | dmenu -font '"FONT"' -normbg '"NORMBGCOLOR"' -normfg '"NORMFGCOLOR"' " \ - "-selbg '"SELBGCOLOR"' -selfg '"SELFGCOLOR"')\" && exec $exe" } }, \ - { MODKEY, XK_1, zoom, { 0 } }, \ - { MODKEY, XK_2, killclient, { 0 } }, \ - { MODKEY|ShiftMask, XK_q, quit, { 0 } }, \ - { MODKEY|ShiftMask, XK_F4, spawn, { .cmd = "sudo /sbin/shutdown -t 3 now" } }, \ - { MODKEY, XK_space, togglemode, { 0 } }, \ - { MODKEY|ShiftMask, XK_space, togglefloat, { 0 } }, \ - { MODKEY, XK_g, resizemaster, { .i = 15 } }, \ - { MODKEY, XK_s, resizemaster, { .i = -15 } }, \ - { MODKEY, XK_i, incnmaster, { .i = 1 } }, \ - { MODKEY, XK_d, incnmaster, { .i = -1 } }, \ - { MODKEY|ShiftMask, XK_1, tag, { .i = 0 } }, \ - { MODKEY|ShiftMask, XK_2, tag, { .i = 1 } }, \ -}; - -/* Query class:instance:title for regex matching info with following command: - * xprop | awk -F '"' '/^WM_CLASS/ { printf("%s:%s:",$4,$2) }; /^WM_NAME/ { printf("%s\n",$2) }' */ -#define RULES \ -static Rule rule[] = { \ - /* class:instance:title regex tags regex isfloat */ \ - { "URxvt.*", "Das Nichts", False }, \ - { "MPlayer.*", NULL, True }, \ - { "qiv.*", NULL, False }, \ - { "Gimp.*", "Das Alles", True }, \ - { ".*", "Das Alles", False }, \ -}; diff -r c459e05a61a8 -r 4c12dccc288d config.mk --- a/config.mk Sat Jun 16 21:49:51 2007 +0200 +++ b/config.mk Thu May 29 23:12:30 2008 +0200 @@ -1,5 +1,5 @@ # dwm version -VERSION = 3.5 +VERSION = 4.4.1 # Customize below to fit your system @@ -15,7 +15,7 @@ LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 # flags -CFLAGS = -Os ${INCS} -DVERSION=\"${VERSION}\" +CFLAGS = -Os ${INCS} -DVERSION=\"${VERSION}\" -W -Wall LDFLAGS = ${LIBS} #CFLAGS = -g -Wall -O2 ${INCS} -DVERSION=\"${VERSION}\" #LDFLAGS = -g ${LIBS} diff -r c459e05a61a8 -r 4c12dccc288d draw.c --- a/draw.c Sat Jun 16 21:49:51 2007 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,164 +0,0 @@ -/* (C)opyright MMIV-MMVII Anselm R. Garbe - * See LICENSE file for license details. - */ -#include "dwm.h" -#include -#include - -/* static */ - -static Bool -isoccupied(unsigned int t) -{ - Client *c; - for(c = clients; c; c = c->next) - if(c->tags[t]) - return True; - return False; -} - -static unsigned int -textnw(const char *text, unsigned int len) { - XRectangle r; - - if(dc.font.set) { - XmbTextExtents(dc.font.set, text, len, NULL, &r); - return r.width; - } - return XTextWidth(dc.font.xfont, text, len); -} - -static void -drawtext(const char *text, unsigned long col[ColLast], Bool filledsquare, Bool emptysquare) { - int x, y, w, h; - static char buf[256]; - unsigned int len, olen; - XGCValues gcv; - XRectangle r = { dc.x, dc.y, dc.w, dc.h }; - - XSetForeground(dpy, dc.gc, col[ColBG]); - XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); - if(!text) - return; - w = 0; - olen = len = strlen(text); - if(len >= sizeof buf) - len = sizeof buf - 1; - memcpy(buf, text, len); - buf[len] = 0; - h = dc.font.ascent + dc.font.descent; - y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; - x = dc.x + (h / 2); - /* shorten text if necessary */ - while(len && (w = textnw(buf, len)) > dc.w - h) - buf[--len] = 0; - if(len < olen) { - if(len > 1) - buf[len - 1] = '.'; - if(len > 2) - buf[len - 2] = '.'; - if(len > 3) - buf[len - 3] = '.'; - } - if(w > dc.w) - return; /* too long */ - gcv.foreground = col[ColFG]; - if(dc.font.set) { - XChangeGC(dpy, dc.gc, GCForeground, &gcv); - XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len); - } - else { - gcv.font = dc.font.xfont->fid; - XChangeGC(dpy, dc.gc, GCForeground | GCFont, &gcv); - XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); - } -} - -/* extern */ - -void -drawstatus(void) { - int i, x; - - dc.x = dc.y = 0; - for(i = 0; i < ntags; i++) { - dc.w = textw(tags[i]); - if(seltag[i]) - drawtext(tags[i], dc.sel, sel && sel->tags[i], isoccupied(i)); - else - drawtext(tags[i], dc.norm, sel && sel->tags[i], isoccupied(i)); - dc.x += dc.w + 1; - } - dc.w = bmw; - drawtext("", dc.norm, False, False); - x = dc.x + dc.w; - dc.w = textw(stext); - dc.x = sw - dc.w; - if(dc.x < x) { - dc.x = x; - dc.w = sw - x; - } - drawtext(stext, dc.norm, False, False); - if((dc.w = dc.x - x) > bh) { - dc.x = x; - drawtext(sel ? sel->name : NULL, dc.norm, False, False); - } - XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0); - XSync(dpy, False); -} - -unsigned long -getcolor(const char *colstr) { - Colormap cmap = DefaultColormap(dpy, screen); - XColor color; - - if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) - eprint("error, cannot allocate color '%s'\n", colstr); - return color.pixel; -} - -void -setfont(const char *fontstr) { - char *def, **missing; - int i, n; - - missing = NULL; - if(dc.font.set) - XFreeFontSet(dpy, dc.font.set); - dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); - if(missing) { - while(n--) - fprintf(stderr, "missing fontset: %s\n", missing[n]); - XFreeStringList(missing); - } - if(dc.font.set) { - XFontSetExtents *font_extents; - XFontStruct **xfonts; - char **font_names; - dc.font.ascent = dc.font.descent = 0; - font_extents = XExtentsOfFontSet(dc.font.set); - n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); - for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) { - if(dc.font.ascent < (*xfonts)->ascent) - dc.font.ascent = (*xfonts)->ascent; - if(dc.font.descent < (*xfonts)->descent) - dc.font.descent = (*xfonts)->descent; - xfonts++; - } - } - else { - if(dc.font.xfont) - XFreeFont(dpy, dc.font.xfont); - dc.font.xfont = NULL; - if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))) - eprint("error, cannot load font: '%s'\n", fontstr); - dc.font.ascent = dc.font.xfont->ascent; - dc.font.descent = dc.font.xfont->descent; - } - dc.font.height = dc.font.ascent + dc.font.descent; -} - -unsigned int -textw(const char *text) { - return textnw(text, strlen(text)) + dc.font.height; -} diff -r c459e05a61a8 -r 4c12dccc288d dwm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwm.c Thu May 29 23:12:30 2008 +0200 @@ -0,0 +1,1846 @@ +/* (C)opyright MMVI-MMVII Anselm R. Garbe + * 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" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* mask shorthands, used in event.c and client.c */ +#define BUTTONMASK (ButtonPressMask | ButtonReleaseMask) + +enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */ +enum { WMProtocols, WMDelete, WMState, WMLast }; /* default atoms */ +enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ +enum { ColBorder, ColFG, ColBG, ColLast }; /* color */ + +typedef union { + const char *cmd; + int i; +} Arg; /* argument type */ + +typedef struct { + int ascent; + int descent; + int height; + XFontSet set; + XFontStruct *xfont; +} Fnt; + +typedef struct { + int x, y, w, h; + unsigned long norm[ColLast]; + unsigned long sel[ColLast]; + Drawable drawable; + Fnt font; + GC gc; +} DC; /* draw context */ + +typedef struct Client Client; +struct Client { + char name[256]; + int x, y, w, h; + int rx, ry, rw, rh; /* revert geometry */ + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int minax, minay, maxax, maxay; + long flags; + unsigned int border; + Bool isfixed, isfloat, ismax; + Bool *tags; + Client *next; + Client *prev; + Client *snext; + Window win; +}; + +typedef struct { + const char *clpattern; + const char *tpattern; + Bool isfloat; +} Rule; + +typedef struct { + regex_t *clregex; + regex_t *tregex; +} RReg; + + +typedef struct { + unsigned long mod; + KeySym keysym; + void (*func)(Arg *arg); + Arg arg; +} Key; + + +#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask)) +#define MOUSEMASK (BUTTONMASK | PointerMotionMask) + + + +const char *tags[]; /* all tags */ +char stext[256]; /* status text */ +int bh, bmw; /* bar height, bar mode label width */ +int screen, sx, sy, sw, sh; /* screen geometry */ +int wax, way, wah, waw; /* windowarea geometry */ +unsigned int nmaster; /* number of master clients */ +unsigned int ntags, numlockmask; /* number of tags, dynamic lock mask */ +void (*handler[LASTEvent])(XEvent *); /* event handler */ +void (*arrange)(void); /* arrange function, indicates mode */ +Atom wmatom[WMLast], netatom[NetLast]; +Bool running, selscreen, *seltag; /* seltag is array of Bool */ +Client *clients, *sel, *stack; /* global client list and stack */ +Cursor cursor[CurLast]; +DC dc; /* global draw context */ +Display *dpy; +Window root, barwin; + +Bool running = True; +Bool selscreen = True; +Client *clients = NULL; +Client *sel = NULL; +Client *stack = NULL; +DC dc = {0}; + +static int (*xerrorxlib)(Display *, XErrorEvent *); +static Bool otherwm, readin; +static RReg *rreg = NULL; +static unsigned int len = 0; + + +TAGS +RULES + + +/* client.c */ +void configure(Client *c); /* send synthetic configure event */ +void focus(Client *c); /* focus c, c may be NULL */ +Client *getclient(Window w); /* return client of w */ +Bool isprotodel(Client *c); /* returns True if c->win supports wmatom[WMDelete] */ +void killclient(Arg *arg); /* kill c nicely */ +void manage(Window w, XWindowAttributes *wa); /* manage new client */ +void resize(Client *c, Bool sizehints); /* resize c*/ +void updatesizehints(Client *c); /* update the size hint variables of c */ +void updatetitle(Client *c); /* update the name of c */ +void unmanage(Client *c); /* destroy c */ + +/* draw.c */ +void drawstatus(void); /* draw the bar */ +unsigned long getcolor(const char *colstr); /* return color of colstr */ +void setfont(const char *fontstr); /* set the font for DC */ +unsigned int textw(const char *text); /* return the width of text in px*/ + +/* event.c */ +void grabkeys(void); /* grab all keys defined in config.h */ +void procevent(void); /* process pending X events */ + +/* main.c */ +void quit(Arg *arg); /* quit dwm nicely */ +void sendevent(Window w, Atom a, long value); /* send synthetic event to w */ +int xerror(Display *dsply, XErrorEvent *ee); /* dwm's X error handler */ + +/* tag.c */ +void initrregs(void); /* initialize regexps of rules defined in config.h */ +Client *getnext(Client *c); /* returns next visible client */ +Client *getprev(Client *c); /* returns previous visible client */ +void settags(Client *c, Client *trans); /* sets tags of c */ +void tag(Arg *arg); /* tags c with arg's index */ +void toggletag(Arg *arg); /* toggles c tags with arg's index */ +void viewnext(Arg *arg); /* view next tag(s) */ + +/* util.c */ +void *emallocz(unsigned int size); /* allocates zero-initialized memory, exits on error */ +void eprint(const char *errstr, ...); /* prints errstr and exits with 1 */ +void spawn(Arg *arg); /* forks a new subprocess with to arg's cmd */ + +/* view.c */ +void detach(Client *c); /* detaches c from global client list */ +void dofloat(void); /* arranges all windows floating */ +void dotile(void); /* arranges all windows tiled */ +void domax(void); /* arranges all windows fullscreen */ +void focusnext(Arg *arg); /* focuses next visible client, arg is ignored */ +void incnmaster(Arg *arg); /* increments nmaster with arg's index value */ +Bool isvisible(Client *c); /* returns True if client is visible */ +void restack(void); /* restores z layers of all clients */ +void togglefloat(Arg *arg); /* toggles focusesd client between floating/non-floating state */ +void togglemode(Arg *arg); /* toggles global arrange function (dotile/dofloat) */ +void view(Arg *arg); /* views the tag with arg's index */ +void zoom(Arg *arg); /* zooms the focused client to master area, arg is ignored */ + + + + + + + + + + +/* from view.c */ +/* static */ + +static Client * +nexttiled(Client *c) { + for(c = getnext(c); c && c->isfloat; c = getnext(c->next)); + return c; +} + +static void +togglemax(Client *c) { + XEvent ev; + + if(c->isfixed) + return; + + if((c->ismax = !c->ismax)) { + c->rx = c->x; c->x = wax; + c->ry = c->y; c->y = way; + c->rw = c->w; c->w = waw - 2 * BORDERPX; + c->rh = c->h; c->h = wah - 2 * BORDERPX; + } + else { + c->x = c->rx; + c->y = c->ry; + c->w = c->rw; + c->h = c->rh; + } + resize(c, True); + while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); +} + + + +void (*arrange)(void) = DEFMODE; + +void +detach(Client *c) { + if(c->prev) + c->prev->next = c->next; + if(c->next) + c->next->prev = c->prev; + if(c == clients) + clients = c->next; + c->next = c->prev = NULL; +} + +void +dofloat(void) { + Client *c; + + for(c = clients; c; c = c->next) { + if(isvisible(c)) { + resize(c, True); + } + else + XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); + } + if(!sel || !isvisible(sel)) { + for(c = stack; c && !isvisible(c); c = c->snext); + focus(c); + } + restack(); +} + +void +dotile(void) { + unsigned int i, n, mw, mh, tw, th; + Client *c; + + for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)) + n++; + /* window geoms */ + mh = (n > nmaster) ? wah / nmaster : wah / (n > 0 ? n : 1); + mw = (n > nmaster) ? waw / 2 : waw; + th = (n > nmaster) ? wah / (n - nmaster) : 0; + tw = waw - mw; + + for(i = 0, c = clients; c; c = c->next) + if(isvisible(c)) { + if(c->isfloat) { + resize(c, True); + continue; + } + c->ismax = False; + c->x = wax; + c->y = way; + if(i < nmaster) { + c->y += i * mh; + c->w = mw - 2 * BORDERPX; + c->h = mh - 2 * BORDERPX; + } + else { /* tile window */ + c->x += mw; + c->w = tw - 2 * BORDERPX; + if(th > 2 * BORDERPX) { + c->y += (i - nmaster) * th; + c->h = th - 2 * BORDERPX; + } + else /* fallback if th <= 2 * BORDERPX */ + c->h = wah - 2 * BORDERPX; + } + resize(c, False); + i++; + } + else + XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); + if(!sel || !isvisible(sel)) { + for(c = stack; c && !isvisible(c); c = c->snext); + focus(c); + } + restack(); +} + +/* begin code by mitch */ +void +arrangemax(Client *c) { + if(c == sel) { + c->ismax = True; + c->x = sx; + c->y = bh; + c->w = sw - 2 * BORDERPX; + c->h = sh - bh - 2 * BORDERPX; + XRaiseWindow(dpy, c->win); + } else { + c->ismax = False; + XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); + XLowerWindow(dpy, c->win); + } +} + +void +domax(void) { + Client *c; + + for(c = clients; c; c = c->next) { + if(isvisible(c)) { + if(c->isfloat) { + resize(c, True); + continue; + } + arrangemax(c); + resize(c, False); + } else { + XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); + } + + } + if(!sel || !isvisible(sel)) { + for(c = stack; c && !isvisible(c); c = c->snext); + focus(c); + } + restack(); +} +/* end code by mitch */ + +void +focusnext(Arg *arg) { + Client *c; + + if(!sel) + return; + if(!(c = getnext(sel->next))) + c = getnext(clients); + if(c) { + focus(c); + restack(); + } +} + +void +incnmaster(Arg *arg) { + if((arrange == dofloat) || (nmaster + arg->i < 1) + || (wah / (nmaster + arg->i) <= 2 * BORDERPX)) + return; + nmaster += arg->i; + if(sel) + arrange(); + else + drawstatus(); +} + +Bool +isvisible(Client *c) { + unsigned int i; + + for(i = 0; i < ntags; i++) + if(c->tags[i] && seltag[i]) + return True; + return False; +} + +void +restack(void) { + Client *c; + XEvent ev; + + drawstatus(); + if(!sel) + return; + if(sel->isfloat || arrange == dofloat) + XRaiseWindow(dpy, sel->win); + + /* begin code by mitch */ + if(arrange == domax) { + for(c = nexttiled(clients); c; c = nexttiled(c->next)) { + arrangemax(c); + resize(c, False); + } + + } else if (arrange == dotile) { + /* end code by mitch */ + + if(!sel->isfloat) + XLowerWindow(dpy, sel->win); + for(c = nexttiled(clients); c; c = nexttiled(c->next)) { + if(c == sel) + continue; + XLowerWindow(dpy, c->win); + } + } + XSync(dpy, False); + while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); +} + +void +togglefloat(Arg *arg) { + if (!sel || arrange == dofloat) + return; + sel->isfloat = !sel->isfloat; + arrange(); +} + +void +togglemode(Arg *arg) { + /* only toggle between tile and max - float is just available through togglefloat */ + arrange = (arrange == dotile) ? domax : dotile; + if(sel) + arrange(); + else + drawstatus(); +} + +void +view(Arg *arg) { + unsigned int i; + + for(i = 0; i < ntags; i++) + seltag[i] = (arg->i == -1) ? True : False; + if(arg->i >= 0 && arg->i < ntags) + seltag[arg->i] = True; + arrange(); +} + +void +zoom(Arg *arg) { + unsigned int n; + Client *c; + + if(!sel) + return; + if(sel->isfloat || (arrange == dofloat)) { + togglemax(sel); + return; + } + for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)) + n++; + + if((c = sel) == nexttiled(clients)) + if(!(c = nexttiled(c->next))) + return; + detach(c); + if(clients) + clients->prev = c; + c->next = clients; + clients = c; + focus(c); + arrange(); +} + + + + + + + + + + + + + + + + +/* from util.c */ + + +void * +emallocz(unsigned int size) { + void *res = calloc(1, size); + + if(!res) + eprint("fatal: could not malloc() %u bytes\n", size); + return res; +} + +void +eprint(const char *errstr, ...) { + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +void +spawn(Arg *arg) { + static char *shell = NULL; + + if(!shell && !(shell = getenv("SHELL"))) + shell = "/bin/sh"; + if(!arg->cmd) + return; + /* The double-fork construct avoids zombie processes and keeps the code + * clean from stupid signal handlers. */ + if(fork() == 0) { + if(fork() == 0) { + if(dpy) + close(ConnectionNumber(dpy)); + setsid(); + execl(shell, shell, "-c", arg->cmd, (char *)NULL); + fprintf(stderr, "dwm: execl '%s -c %s'", shell, arg->cmd); + perror(" failed"); + } + exit(0); + } + wait(0); +} + + + + + + + + + + + + + +/* from tag.c */ + +/* static */ + +Client * +getnext(Client *c) { + for(; c && !isvisible(c); c = c->next); + return c; +} + +Client * +getprev(Client *c) { + for(; c && !isvisible(c); c = c->prev); + return c; +} + +void +initrregs(void) { + unsigned int i; + regex_t *reg; + + if(rreg) + return; + len = sizeof rule / sizeof rule[0]; + rreg = emallocz(len * sizeof(RReg)); + for(i = 0; i < len; i++) { + if(rule[i].clpattern) { + reg = emallocz(sizeof(regex_t)); + if(regcomp(reg, rule[i].clpattern, REG_EXTENDED)) + free(reg); + else + rreg[i].clregex = reg; + } + if(rule[i].tpattern) { + reg = emallocz(sizeof(regex_t)); + if(regcomp(reg, rule[i].tpattern, REG_EXTENDED)) + free(reg); + else + rreg[i].tregex = reg; + } + } +} + +void +settags(Client *c, Client *trans) { + char prop[512]; + unsigned int i, j; + regmatch_t tmp; + Bool matched = trans != NULL; + XClassHint ch = { 0 }; + + if(matched) { + for(i = 0; i < ntags; i++) + c->tags[i] = trans->tags[i]; + } + else { + XGetClassHint(dpy, c->win, &ch); + snprintf(prop, sizeof prop, "%s:%s:%s", + ch.res_class ? ch.res_class : "", + ch.res_name ? ch.res_name : "", c->name); + for(i = 0; i < len; i++) + if(rreg[i].clregex && !regexec(rreg[i].clregex, prop, 1, &tmp, 0)) { + c->isfloat = rule[i].isfloat; + for(j = 0; rreg[i].tregex && j < ntags; j++) { + if(!regexec(rreg[i].tregex, tags[j], 1, &tmp, 0)) { + matched = True; + c->tags[j] = True; + } + } + break; /* perform only the first rule matching */ + } + if(ch.res_class) + XFree(ch.res_class); + if(ch.res_name) + XFree(ch.res_name); + } + if(!matched) + for(i = 0; i < ntags; i++) + c->tags[i] = seltag[i]; +} + +void +tag(Arg *arg) { + unsigned int i; + + if(!sel) + return; + for(i = 0; i < ntags; i++) + sel->tags[i] = (arg->i == -1) ? True : False; + if(arg->i >= 0 && arg->i < ntags) + sel->tags[arg->i] = True; + arrange(); +} + +void +toggletag(Arg *arg) { + unsigned int i; + + if(!sel) + return; + sel->tags[arg->i] = !sel->tags[arg->i]; + for(i = 0; i < ntags && !sel->tags[i]; i++); + if(i == ntags) + sel->tags[arg->i] = True; + arrange(); +} + +/* begin code by jukka */ +void +viewnext(Arg *arg) { + unsigned int i; + Bool last = seltag[ntags-1]; + + for (i=ntags-1; i>0; --i) + seltag[i] = seltag[i-1]; + seltag[0] = last; + arrange(); +} +/* end code by jukka */ + + + + + + + + + + + + + + + + +/* from event.c */ +/* static */ + +KEYS + + + +static void +movemouse(Client *c) { + int x1, y1, ocx, ocy, di; + unsigned int dui; + Window dummy; + XEvent ev; + + ocx = c->x; + ocy = c->y; + 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 | SubstructureRedirectMask, &ev); + switch (ev.type) { + case ButtonRelease: + resize(c, True); + XUngrabPointer(dpy, CurrentTime); + return; + case ConfigureRequest: + case Expose: + case MapRequest: + handler[ev.type](&ev); + break; + case MotionNotify: + XSync(dpy, False); + c->x = ocx + (ev.xmotion.x - x1); + c->y = ocy + (ev.xmotion.y - y1); + if(abs(wax + c->x) < SNAP) + c->x = wax; + else if(abs((wax + waw) - (c->x + c->w + 2 * c->border)) < SNAP) + c->x = wax + waw - c->w - 2 * c->border; + if(abs(way - c->y) < SNAP) + c->y = way; + else if(abs((way + wah) - (c->y + c->h + 2 * c->border)) < SNAP) + c->y = way + wah - c->h - 2 * c->border; + resize(c, False); + break; + } + } +} + +static void +resizemouse(Client *c) { + int ocx, ocy; + int nw, nh; + XEvent ev; + + ocx = c->x; + ocy = c->y; + 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->border - 1, c->h + c->border - 1); + for(;;) { + XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev); + switch(ev.type) { + case ButtonRelease: + resize(c, True); + XUngrabPointer(dpy, CurrentTime); + return; + case ConfigureRequest: + case Expose: + case MapRequest: + handler[ev.type](&ev); + break; + case MotionNotify: + XSync(dpy, False); + nw = ev.xmotion.x - ocx - 2 * c->border + 1; + c->w = nw > 0 ? nw : 1; + nh = ev.xmotion.y - ocy - 2 * c->border + 1; + c->h = nh > 0 ? nh : 1; + resize(c, True); + break; + } + } +} + +static void +buttonpress(XEvent *e) { + int x; + Arg a; + Client *c; + XButtonPressedEvent *ev = &e->xbutton; + + if(barwin == ev->window) { + x = 0; + for(a.i = 0; a.i < ntags; a.i++) { + x += textw(tags[a.i]); + if(ev->x < x) { + if(ev->button == Button1) { + view(&a); + } + return; + } + } + if(ev->x < x + bmw) + if (ev->button == Button1) { + togglemode(NULL); + } + } + else if((c = getclient(ev->window))) { + focus(c); + if(CLEANMASK(ev->state) != MODKEY) + return; + if(ev->button == Button1 && (arrange == dofloat || c->isfloat)) { + restack(); + movemouse(c); + } + else if(ev->button == Button2) + zoom(NULL); + else if(ev->button == Button3 && (arrange == dofloat || c->isfloat) && + !c->isfixed) { + restack(); + resizemouse(c); + } + } +} + +static void +configurerequest(XEvent *e) { + unsigned long newmask; + Client *c; + XConfigureRequestEvent *ev = &e->xconfigurerequest; + XWindowChanges wc; + + if((c = getclient(ev->window))) { + c->ismax = False; + if(ev->value_mask & CWX) + c->x = ev->x; + if(ev->value_mask & CWY) + c->y = ev->y; + if(ev->value_mask & CWWidth) + c->w = ev->width; + if(ev->value_mask & CWHeight) + c->h = ev->height; + if(ev->value_mask & CWBorderWidth) + c->border = ev->border_width; + wc.x = c->x; + wc.y = c->y; + wc.width = c->w; + wc.height = c->h; + newmask = ev->value_mask & (~(CWSibling | CWStackMode | CWBorderWidth)); + if(newmask) + XConfigureWindow(dpy, c->win, newmask, &wc); + else + configure(c); + XSync(dpy, False); + if(c->isfloat) { + resize(c, False); + if(!isvisible(c)) + XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); + } + else + arrange(); + } + else { + wc.x = ev->x; + wc.y = ev->y; + wc.width = ev->width; + wc.height = ev->height; + wc.border_width = ev->border_width; + wc.sibling = ev->above; + wc.stack_mode = ev->detail; + XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); + XSync(dpy, False); + } +} + +static void +destroynotify(XEvent *e) { + Client *c; + XDestroyWindowEvent *ev = &e->xdestroywindow; + + if((c = getclient(ev->window))) + unmanage(c); +} + +static void +enternotify(XEvent *e) { + Client *c; + XCrossingEvent *ev = &e->xcrossing; + + if(ev->mode != NotifyNormal || ev->detail == NotifyInferior) + return; + if((c = getclient(ev->window)) && isvisible(c)) + focus(c); + else if(ev->window == root) { + selscreen = True; + for(c = stack; c && !isvisible(c); c = c->snext); + focus(c); + } +} + +static void +expose(XEvent *e) { + XExposeEvent *ev = &e->xexpose; + + if(ev->count == 0) { + if(barwin == ev->window) + drawstatus(); + } +} + +static void +keypress(XEvent *e) { + static unsigned int len = sizeof key / sizeof key[0]; + unsigned int i; + KeySym keysym; + XKeyEvent *ev = &e->xkey; + + 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(key[i].func) + key[i].func(&key[i].arg); + } + } +} + +static void +leavenotify(XEvent *e) { + XCrossingEvent *ev = &e->xcrossing; + + if((ev->window == root) && !ev->same_screen) { + selscreen = False; + focus(NULL); + } +} + +static void +mappingnotify(XEvent *e) { + XMappingEvent *ev = &e->xmapping; + + XRefreshKeyboardMapping(ev); + if(ev->request == MappingKeyboard) + grabkeys(); +} + +static void +maprequest(XEvent *e) { + static XWindowAttributes wa; + XMapRequestEvent *ev = &e->xmaprequest; + + if(!XGetWindowAttributes(dpy, ev->window, &wa)) + return; + if(wa.override_redirect) { + XSelectInput(dpy, ev->window, + (StructureNotifyMask | PropertyChangeMask)); + return; + } + if(!getclient(ev->window)) + manage(ev->window, &wa); +} + +static void +propertynotify(XEvent *e) { + Client *c; + Window trans; + XPropertyEvent *ev = &e->xproperty; + + if(ev->state == PropertyDelete) + return; /* ignore */ + if((c = getclient(ev->window))) { + switch (ev->atom) { + default: break; + case XA_WM_TRANSIENT_FOR: + XGetTransientForHint(dpy, c->win, &trans); + if(!c->isfloat && (c->isfloat = (trans != 0))) + arrange(); + break; + case XA_WM_NORMAL_HINTS: + updatesizehints(c); + break; + } + if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if(c == sel) + drawstatus(); + } + } +} + +static void +unmapnotify(XEvent *e) { + Client *c; + XUnmapEvent *ev = &e->xunmap; + + if((c = getclient(ev->window))) + unmanage(c); +} + + + +void (*handler[LASTEvent]) (XEvent *) = { + [ButtonPress] = buttonpress, + [ConfigureRequest] = configurerequest, + [DestroyNotify] = destroynotify, + [EnterNotify] = enternotify, + [LeaveNotify] = leavenotify, + [Expose] = expose, + [KeyPress] = keypress, + [MappingNotify] = mappingnotify, + [MapRequest] = maprequest, + [PropertyNotify] = propertynotify, + [UnmapNotify] = unmapnotify +}; + +void +grabkeys(void) { + static unsigned int len = sizeof key / sizeof key[0]; + unsigned int i; + KeyCode code; + + XUngrabKey(dpy, AnyKey, AnyModifier, root); + for(i = 0; i < len; i++) { + code = XKeysymToKeycode(dpy, key[i].keysym); + XGrabKey(dpy, code, key[i].mod, root, True, + GrabModeAsync, GrabModeAsync); + XGrabKey(dpy, code, key[i].mod | LockMask, root, True, + GrabModeAsync, GrabModeAsync); + XGrabKey(dpy, code, key[i].mod | numlockmask, root, True, + GrabModeAsync, GrabModeAsync); + XGrabKey(dpy, code, key[i].mod | numlockmask | LockMask, root, True, + GrabModeAsync, GrabModeAsync); + } +} + +void +procevent(void) { + XEvent ev; + + while(XPending(dpy)) { + XNextEvent(dpy, &ev); + if(handler[ev.type]) + (handler[ev.type])(&ev); /* call handler */ + } +} + + + + + + + + + + + + + + + +/* from draw.c */ +/* static */ + +static unsigned int +textnw(const char *text, unsigned int len) { + XRectangle r; + + if(dc.font.set) { + XmbTextExtents(dc.font.set, text, len, NULL, &r); + return r.width; + } + return XTextWidth(dc.font.xfont, text, len); +} + +static void +drawtext(const char *text, unsigned long col[ColLast]) { + int x, y, w, h; + static char buf[256]; + unsigned int len, olen; + XGCValues gcv; + XRectangle r = { dc.x, dc.y, dc.w, dc.h }; + + XSetForeground(dpy, dc.gc, col[ColBG]); + XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); + if(!text) + return; + w = 0; + olen = len = strlen(text); + if(len >= sizeof buf) + len = sizeof buf - 1; + memcpy(buf, text, len); + buf[len] = 0; + h = dc.font.ascent + dc.font.descent; + y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; + x = dc.x + (h / 2); + /* shorten text if necessary */ + while(len && (w = textnw(buf, len)) > dc.w - h) + buf[--len] = 0; + if(len < olen) { + if(len > 1) + buf[len - 1] = '.'; + if(len > 2) + buf[len - 2] = '.'; + if(len > 3) + buf[len - 3] = '.'; + } + if(w > dc.w) + return; /* too long */ + gcv.foreground = col[ColFG]; + if(dc.font.set) { + XChangeGC(dpy, dc.gc, GCForeground, &gcv); + XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len); + } else { + gcv.font = dc.font.xfont->fid; + XChangeGC(dpy, dc.gc, GCForeground | GCFont, &gcv); + XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); + } +} + + + +void +drawstatus(void) { + int i, x; + + dc.x = dc.y = 0; + for(i = 0; i < ntags; i++) { + dc.w = textw(tags[i]); + drawtext(tags[i], (seltag[i] ? dc.sel : dc.norm)); + dc.x += dc.w + 1; + } + dc.w = bmw; + drawtext("", dc.norm); + x = dc.x + dc.w; + dc.w = textw(stext); + dc.x = sw - dc.w; + if(dc.x < x) { + dc.x = x; + dc.w = sw - x; + } + drawtext(stext, dc.norm); + if((dc.w = dc.x - x) > bh) { + dc.x = x; + drawtext(sel ? sel->name : NULL, dc.norm); + } + XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0); + XSync(dpy, False); +} + +unsigned long +getcolor(const char *colstr) { + Colormap cmap = DefaultColormap(dpy, screen); + XColor color; + + if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) + eprint("error, cannot allocate color '%s'\n", colstr); + return color.pixel; +} + +void +setfont(const char *fontstr) { + char *def, **missing; + int i, n; + + missing = NULL; + if(dc.font.set) + XFreeFontSet(dpy, dc.font.set); + dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); + if(missing) { + while(n--) + fprintf(stderr, "missing fontset: %s\n", missing[n]); + XFreeStringList(missing); + } + if(dc.font.set) { + XFontSetExtents *font_extents; + XFontStruct **xfonts; + char **font_names; + dc.font.ascent = dc.font.descent = 0; + font_extents = XExtentsOfFontSet(dc.font.set); + n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); + for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) { + if(dc.font.ascent < (*xfonts)->ascent) + dc.font.ascent = (*xfonts)->ascent; + if(dc.font.descent < (*xfonts)->descent) + dc.font.descent = (*xfonts)->descent; + xfonts++; + } + } else { + if(dc.font.xfont) + XFreeFont(dpy, dc.font.xfont); + dc.font.xfont = NULL; + if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))) + eprint("error, cannot load font: '%s'\n", fontstr); + dc.font.ascent = dc.font.xfont->ascent; + dc.font.descent = dc.font.xfont->descent; + } + dc.font.height = dc.font.ascent + dc.font.descent; +} + +unsigned int +textw(const char *text) { + return textnw(text, strlen(text)) + dc.font.height; +} + + + + + + + + + + + +/* from client.c */ +/* static */ + +static void +detachstack(Client *c) { + Client **tc; + for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext); + *tc = c->snext; +} + +static void +grabbuttons(Client *c, Bool focused) { + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + + if(focused) { + XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + + XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + + XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + } else { + XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + } +} + +static void +setclientstate(Client *c, long state) { + long data[] = {state, None}; + XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, + PropModeReplace, (unsigned char *)data, 2); +} + +static int +xerrordummy(Display *dsply, XErrorEvent *ee) { + return 0; +} + + + +void +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) { + if(c && !isvisible(c)) + return; + if(sel && sel != c) { + grabbuttons(sel, False); + XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]); + } + if(c) { + detachstack(c); + c->snext = stack; + stack = c; + grabbuttons(c, True); + } + sel = c; + drawstatus(); + if(!selscreen) + return; + if(c) { + XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]); + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + } +} + +Client * +getclient(Window w) { + Client *c; + + for(c = clients; c; c = c->next) { + if(c->win == w) { + return c; + } + } + return NULL; +} + +Bool +isprotodel(Client *c) { + int i, n; + Atom *protocols; + Bool ret = False; + + if(XGetWMProtocols(dpy, c->win, &protocols, &n)) { + for(i = 0; !ret && i < n; i++) + if(protocols[i] == wmatom[WMDelete]) + ret = True; + XFree(protocols); + } + return ret; +} + +void +killclient(Arg *arg) { + if(!sel) + return; + if(isprotodel(sel)) + sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]); + else + XKillClient(dpy, sel->win); +} + +void +manage(Window w, XWindowAttributes *wa) { + Client *c; + Window trans; + + c = emallocz(sizeof(Client)); + c->tags = emallocz(ntags * sizeof(Bool)); + c->win = w; + c->x = wa->x; + c->y = wa->y; + c->w = wa->width; + c->h = wa->height; + if(c->w == sw && c->h == sh) { + c->border = 0; + c->x = sx; + c->y = sy; + } else { + c->border = BORDERPX; + if(c->x + c->w + 2 * c->border > wax + waw) + c->x = wax + waw - c->w - 2 * c->border; + if(c->y + c->h + 2 * c->border > way + wah) + c->y = way + wah - c->h - 2 * c->border; + if(c->x < wax) + c->x = wax; + if(c->y < way) + c->y = way; + } + updatesizehints(c); + XSelectInput(dpy, c->win, + StructureNotifyMask | PropertyChangeMask | EnterWindowMask); + XGetTransientForHint(dpy, c->win, &trans); + grabbuttons(c, False); + XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]); + updatetitle(c); + settags(c, getclient(trans)); + if(!c->isfloat) + c->isfloat = trans || c->isfixed; + if(clients) + clients->prev = c; + c->next = clients; + c->snext = stack; + stack = clients = c; + XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); + XMapWindow(dpy, c->win); + setclientstate(c, NormalState); + if(isvisible(c)) + focus(c); + arrange(); +} + +void +resize(Client *c, Bool sizehints) { + float actual, dx, dy, max, min; + XWindowChanges wc; + + if(c->w <= 0 || c->h <= 0) + return; + if(sizehints) { + if(c->minw && c->w < c->minw) + c->w = c->minw; + if(c->minh && c->h < c->minh) + c->h = c->minh; + if(c->maxw && c->w > c->maxw) + c->w = c->maxw; + if(c->maxh && c->h > c->maxh) + c->h = c->maxh; + /* inspired by algorithm from fluxbox */ + if(c->minay > 0 && c->maxay && (c->h - c->baseh) > 0) { + dx = (float)(c->w - c->basew); + dy = (float)(c->h - c->baseh); + min = (float)(c->minax) / (float)(c->minay); + max = (float)(c->maxax) / (float)(c->maxay); + actual = dx / dy; + if(max > 0 && min > 0 && actual > 0) { + if(actual < min) { + dy = (dx * min + dy) / (min * min + 1); + dx = dy * min; + c->w = (int)dx + c->basew; + c->h = (int)dy + c->baseh; + } + else if(actual > max) { + dy = (dx * min + dy) / (max * max + 1); + dx = dy * min; + c->w = (int)dx + c->basew; + c->h = (int)dy + c->baseh; + } + } + } + if(c->incw) + c->w -= (c->w - c->basew) % c->incw; + if(c->inch) + c->h -= (c->h - c->baseh) % c->inch; + } + if(c->w == sw && c->h == sh) + c->border = 0; + else + c->border = BORDERPX; + /* offscreen appearance fixes */ + if(c->x > sw) + c->x = sw - c->w - 2 * c->border; + if(c->y > sh) + c->y = sh - c->h - 2 * c->border; + if(c->x + c->w + 2 * c->border < sx) + c->x = sx; + if(c->y + c->h + 2 * c->border < sy) + c->y = sy; + wc.x = c->x; + wc.y = c->y; + wc.width = c->w; + wc.height = c->h; + wc.border_width = c->border; + XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc); + configure(c); + XSync(dpy, False); +} + +void +updatesizehints(Client *c) { + long msize; + XSizeHints size; + + if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags) + size.flags = PSize; + c->flags = size.flags; + if(c->flags & PBaseSize) { + c->basew = size.base_width; + c->baseh = size.base_height; + } else { + c->basew = c->baseh = 0; + } + if(c->flags & PResizeInc) { + c->incw = size.width_inc; + c->inch = size.height_inc; + } else { + c->incw = c->inch = 0; + } + if(c->flags & PMaxSize) { + c->maxw = size.max_width; + c->maxh = size.max_height; + } else { + c->maxw = c->maxh = 0; + } + if(c->flags & PMinSize) { + c->minw = size.min_width; + c->minh = size.min_height; + } else { + c->minw = c->minh = 0; + } + if(c->flags & PAspect) { + c->minax = size.min_aspect.x; + c->minay = size.min_aspect.y; + c->maxax = size.max_aspect.x; + c->maxay = size.max_aspect.y; + } else { + c->minax = c->minay = c->maxax = c->maxay = 0; + } + c->isfixed = (c->maxw && c->minw && c->maxh && c->minh && + c->maxw == c->minw && c->maxh == c->minh); +} + +void +updatetitle(Client *c) { + char **list = NULL; + int n; + XTextProperty name; + + name.nitems = 0; + c->name[0] = 0; + XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]); + if(!name.nitems) + XGetWMName(dpy, c->win, &name); + if(!name.nitems) + return; + if(name.encoding == XA_STRING) + strncpy(c->name, (char *)name.value, sizeof c->name); + else { + if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) { + strncpy(c->name, *list, sizeof c->name); + XFreeStringList(list); + } + } + XFree(name.value); +} + +void +unmanage(Client *c) { + Client *nc; + + /* The server grab construct avoids race conditions. */ + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + detach(c); + detachstack(c); + if(sel == c) { + for(nc = stack; nc && !isvisible(nc); nc = nc->snext); + focus(nc); + } + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + setclientstate(c, WithdrawnState); + free(c->tags); + free(c); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + arrange(); +} + + + + + + + + + + + + + + + + + + + +/* static */ + + +static void +cleanup(void) { + close(STDIN_FILENO); + while(stack) { + resize(stack, True); + unmanage(stack); + } + if(dc.font.set) + XFreeFontSet(dpy, dc.font.set); + else + XFreeFont(dpy, dc.font.xfont); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + XFreePixmap(dpy, dc.drawable); + XFreeGC(dpy, dc.gc); + XDestroyWindow(dpy, barwin); + XFreeCursor(dpy, cursor[CurNormal]); + XFreeCursor(dpy, cursor[CurResize]); + XFreeCursor(dpy, cursor[CurMove]); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + XSync(dpy, False); + free(seltag); +} + +static void +scan(void) { + unsigned int i, num; + Window *wins, d1, d2; + XWindowAttributes wa; + + wins = NULL; + if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { + for(i = 0; i < num; i++) { + if(!XGetWindowAttributes(dpy, wins[i], &wa)) + continue; + if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) + continue; + if(wa.map_state == IsViewable) + manage(wins[i], &wa); + } + } + if(wins) + XFree(wins); +} + +static void +setup(void) { + int i, j; + unsigned int mask; + Window w; + XModifierKeymap *modmap; + XSetWindowAttributes wa; + + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); + wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); + netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); + netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); + XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, + PropModeReplace, (unsigned char *) netatom, NetLast); + /* init cursors */ + cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); + cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); + cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); + /* init modifier map */ + numlockmask = 0; + modmap = XGetModifierMapping(dpy); + for (i = 0; i < 8; i++) { + for (j = 0; j < modmap->max_keypermod; j++) { + if(modmap->modifiermap[i * modmap->max_keypermod + j] == XKeysymToKeycode(dpy, XK_Num_Lock)) + numlockmask = (1 << i); + } + } + XFreeModifiermap(modmap); + /* select for events */ + wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask + | EnterWindowMask | LeaveWindowMask; + wa.cursor = cursor[CurNormal]; + XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); + grabkeys(); + initrregs(); + for(ntags = 0; tags[ntags]; ntags++); + seltag = emallocz(sizeof(Bool) * ntags); + seltag[0] = True; + /* style */ + dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR); + dc.norm[ColBG] = getcolor(NORMBGCOLOR); + dc.norm[ColFG] = getcolor(NORMFGCOLOR); + dc.sel[ColBorder] = getcolor(SELBORDERCOLOR); + dc.sel[ColBG] = getcolor(SELBGCOLOR); + dc.sel[ColFG] = getcolor(SELFGCOLOR); + setfont(FONT); + /* geometry */ + sx = sy = 0; + sw = DisplayWidth(dpy, screen); + sh = DisplayHeight(dpy, screen); + nmaster = NMASTER; + bmw = 1; + /* bar */ + dc.h = bh = dc.font.height + 2; + wa.override_redirect = 1; + wa.background_pixmap = ParentRelative; + wa.event_mask = ButtonPressMask | ExposureMask; + barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0, + DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); + XDefineCursor(dpy, barwin, cursor[CurNormal]); + XMapRaised(dpy, barwin); + strcpy(stext, "dwm-"VERSION); + /* windowarea */ + wax = sx; + way = sy + bh; + wah = sh - bh; + waw = sw; + /* pixmap for everything */ + dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); + dc.gc = XCreateGC(dpy, root, 0, 0); + XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); + /* multihead support */ + selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask); +} + +/* + * Startup Error handler to check if another window manager + * is already running. + */ +static int +xerrorstart(Display *dsply, XErrorEvent *ee) { + otherwm = True; + return -1; +} + + + +void +sendevent(Window w, Atom a, long value) { + XEvent e; + + e.type = ClientMessage; + e.xclient.window = w; + e.xclient.message_type = a; + e.xclient.format = 32; + e.xclient.data.l[0] = value; + e.xclient.data.l[1] = CurrentTime; + XSendEvent(dpy, w, False, NoEventMask, &e); + XSync(dpy, False); +} + +void +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 may call exit. + */ +int +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_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 */ +} + +int +main(int argc, char *argv[]) { + char *p; + int r, xfd; + fd_set rd; + + if(argc == 2 && !strncmp("-v", argv[1], 3)) { + fputs("dwm-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n", stdout); + exit(EXIT_SUCCESS); + } + else if(argc != 1) + eprint("usage: dwm [-v]\n"); + setlocale(LC_CTYPE, ""); + dpy = XOpenDisplay(0); + if(!dpy) + eprint("dwm: cannot open display\n"); + xfd = ConnectionNumber(dpy); + screen = DefaultScreen(dpy); + root = RootWindow(dpy, screen); + otherwm = False; + XSetErrorHandler(xerrorstart); + /* this causes an error if some other window manager is running */ + XSelectInput(dpy, root, SubstructureRedirectMask); + XSync(dpy, False); + if(otherwm) + eprint("dwm: another window manager is already running\n"); + + XSync(dpy, False); + XSetErrorHandler(NULL); + xerrorxlib = XSetErrorHandler(xerror); + XSync(dpy, False); + setup(); + drawstatus(); + scan(); + + /* main event loop, also reads status text from stdin */ + XSync(dpy, False); + procevent(); + readin = True; + while(running) { + FD_ZERO(&rd); + if(readin) + FD_SET(STDIN_FILENO, &rd); + FD_SET(xfd, &rd); + if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) { + if(errno == EINTR) + continue; + eprint("select failed\n"); + } + if(FD_ISSET(STDIN_FILENO, &rd)) { + switch(r = read(STDIN_FILENO, stext, sizeof stext - 1)) { + case -1: + strncpy(stext, strerror(errno), sizeof stext - 1); + stext[sizeof stext - 1] = '\0'; + readin = False; + break; + case 0: + strncpy(stext, "EOF", 4); + readin = False; + break; + default: + for(stext[r] = '\0', p = stext + strlen(stext) - 1; p >= stext && *p == '\n'; *p-- = '\0'); + for(; p >= stext && *p != '\n'; --p); + if(p > stext) + strncpy(stext, p + 1, sizeof stext); + } + drawstatus(); + } + if(FD_ISSET(xfd, &rd)) + procevent(); + } + cleanup(); + XCloseDisplay(dpy); + return 0; +} diff -r c459e05a61a8 -r 4c12dccc288d dwm.h --- a/dwm.h Sat Jun 16 21:49:51 2007 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,157 +0,0 @@ -/* (C)opyright MMVI-MMVII Anselm R. Garbe - * 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" -#include - -/* mask shorthands, used in event.c and client.c */ -#define BUTTONMASK (ButtonPressMask | ButtonReleaseMask) - -enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */ -enum { WMProtocols, WMDelete, WMState, WMLast }; /* default atoms */ -enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ -enum { ColBorder, ColFG, ColBG, ColLast }; /* color */ - -typedef union { - const char *cmd; - int i; -} Arg; /* argument type */ - -typedef struct { - int ascent; - int descent; - int height; - XFontSet set; - XFontStruct *xfont; -} Fnt; - -typedef struct { - int x, y, w, h; - unsigned long norm[ColLast]; - unsigned long sel[ColLast]; - Drawable drawable; - Fnt font; - GC gc; -} DC; /* draw context */ - -typedef struct Client Client; -struct Client { - char name[256]; - int x, y, w, h; - int rx, ry, rw, rh; /* revert geometry */ - int basew, baseh, incw, inch, maxw, maxh, minw, minh; - int minax, minay, maxax, maxay; - long flags; - unsigned int border; - Bool isfixed, isfloat, ismax; - Bool *tags; - Client *next; - Client *prev; - Client *snext; - Window win; -}; - -extern const char *tags[]; /* all tags */ -extern char stext[256]; /* status text */ -extern int bh, bmw; /* bar height, bar mode label width */ -extern int screen, sx, sy, sw, sh; /* screen geometry */ -extern int wax, way, wah, waw; /* windowarea geometry */ -extern unsigned int master, nmaster; /* master percent, number of master clients */ -extern unsigned int ntags, numlockmask; /* number of tags, dynamic lock mask */ -extern void (*handler[LASTEvent])(XEvent *); /* event handler */ -extern void (*arrange)(void); /* arrange function, indicates mode */ -extern Atom wmatom[WMLast], netatom[NetLast]; -extern Bool running, selscreen, *seltag; /* seltag is array of Bool */ -extern Client *clients, *sel, *stack; /* global client list and stack */ -extern Cursor cursor[CurLast]; -extern DC dc; /* global draw context */ -extern Display *dpy; -extern Window root, barwin; - -/* client.c */ -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 Bool isprotodel(Client *c); /* returns True if c->win supports wmatom[WMDelete] */ -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); /* resize c*/ -extern void updatesizehints(Client *c); /* update the size hint variables of c */ -extern void updatetitle(Client *c); /* update the name of c */ -extern void unmanage(Client *c); /* destroy c */ - -/* draw.c */ -extern void drawstatus(void); /* draw the bar */ -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(void); /* grab all keys defined in config.h */ -extern void procevent(void); /* process pending X events */ - -/* main.c */ -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(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 */ -extern void viewnext(Arg *arg); /* view next tag(s) */ - -/* util.c */ -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 spawn(Arg *arg); /* forks a new subprocess with to arg's cmd */ - -/* view.c */ -extern void detach(Client *c); /* detaches c from global client list */ -extern void dofloat(void); /* arranges all windows floating */ -extern void dotile(void); /* arranges all windows tiled */ -extern void domax(void); /* arranges all windows fullscreen */ -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 void incnmaster(Arg *arg); /* increments nmaster with arg's index value */ -extern Bool isvisible(Client *c); /* returns True if client is visible */ -extern void resizemaster(Arg *arg); /* resizes the master percent with arg's index value */ -extern void restack(void); /* restores z layers of all clients */ -extern void togglefloat(Arg *arg); /* toggles focusesd client between floating/non-floating state */ -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 zoom(Arg *arg); /* zooms the focused client to master area, arg is ignored */ diff -r c459e05a61a8 -r 4c12dccc288d event.c --- a/event.c Sat Jun 16 21:49:51 2007 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,384 +0,0 @@ -/* (C)opyright MMVI-MMVII Anselm R. Garbe - * See LICENSE file for license details. - */ -#include "dwm.h" -#include -#include -#include - -/* static */ - -typedef struct { - unsigned long mod; - KeySym keysym; - void (*func)(Arg *arg); - Arg arg; -} Key; - -KEYS - -#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask)) -#define MOUSEMASK (BUTTONMASK | PointerMotionMask) - -static void -movemouse(Client *c) { - int x1, y1, ocx, ocy, di; - unsigned int dui; - Window dummy; - XEvent ev; - - ocx = c->x; - ocy = c->y; - 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 | SubstructureRedirectMask, &ev); - switch (ev.type) { - case ButtonRelease: - resize(c, True); - XUngrabPointer(dpy, CurrentTime); - return; - case ConfigureRequest: - case Expose: - case MapRequest: - handler[ev.type](&ev); - break; - case MotionNotify: - XSync(dpy, False); - c->x = ocx + (ev.xmotion.x - x1); - c->y = ocy + (ev.xmotion.y - y1); - if(abs(wax + c->x) < SNAP) - c->x = wax; - else if(abs((wax + waw) - (c->x + c->w + 2 * c->border)) < SNAP) - c->x = wax + waw - c->w - 2 * c->border; - if(abs(way - c->y) < SNAP) - c->y = way; - else if(abs((way + wah) - (c->y + c->h + 2 * c->border)) < SNAP) - c->y = way + wah - c->h - 2 * c->border; - resize(c, False); - break; - } - } -} - -static void -resizemouse(Client *c) { - int ocx, ocy; - int nw, nh; - XEvent ev; - - ocx = c->x; - ocy = c->y; - 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->border - 1, c->h + c->border - 1); - for(;;) { - XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev); - switch(ev.type) { - case ButtonRelease: - resize(c, True); - XUngrabPointer(dpy, CurrentTime); - return; - case ConfigureRequest: - case Expose: - case MapRequest: - handler[ev.type](&ev); - break; - case MotionNotify: - XSync(dpy, False); - nw = ev.xmotion.x - ocx - 2 * c->border + 1; - c->w = nw > 0 ? nw : 1; - nh = ev.xmotion.y - ocy - 2 * c->border + 1; - c->h = nh > 0 ? nh : 1; - resize(c, True); - break; - } - } -} - -static void -buttonpress(XEvent *e) { - int x; - Arg a; - Client *c; - XButtonPressedEvent *ev = &e->xbutton; - - if(barwin == ev->window) { - x = 0; - for(a.i = 0; a.i < ntags; a.i++) { - x += textw(tags[a.i]); - if(ev->x < x) { - if(ev->button == Button1) { - if(ev->state & MODKEY) - tag(&a); - else - view(&a); - } - else if(ev->button == Button3) { - if(ev->state & MODKEY) - toggletag(&a); - else - toggleview(&a); - } - return; - } - } - if(ev->x < x + bmw) - switch(ev->button) { - case Button1: - togglemode(NULL); - break; - case Button4: - a.i = 1; - incnmaster(&a); - break; - case Button5: - a.i = -1; - incnmaster(&a); - break; - } - } - else if((c = getclient(ev->window))) { - focus(c); - if(CLEANMASK(ev->state) != MODKEY) - return; - if(ev->button == Button1 && (arrange == dofloat || c->isfloat)) { - restack(); - movemouse(c); - } - else if(ev->button == Button2) - zoom(NULL); - else if(ev->button == Button3 && (arrange == dofloat || c->isfloat) && - !c->isfixed) { - restack(); - resizemouse(c); - } - } -} - -static void -configurerequest(XEvent *e) { - unsigned long newmask; - Client *c; - XConfigureRequestEvent *ev = &e->xconfigurerequest; - XWindowChanges wc; - - if((c = getclient(ev->window))) { - c->ismax = False; - if(ev->value_mask & CWX) - c->x = ev->x; - if(ev->value_mask & CWY) - c->y = ev->y; - if(ev->value_mask & CWWidth) - c->w = ev->width; - if(ev->value_mask & CWHeight) - c->h = ev->height; - if(ev->value_mask & CWBorderWidth) - c->border = ev->border_width; - wc.x = c->x; - wc.y = c->y; - wc.width = c->w; - wc.height = c->h; - newmask = ev->value_mask & (~(CWSibling | CWStackMode | CWBorderWidth)); - if(newmask) - XConfigureWindow(dpy, c->win, newmask, &wc); - else - configure(c); - XSync(dpy, False); - if(c->isfloat) { - resize(c, False); - if(!isvisible(c)) - XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); - } - else - arrange(); - } - else { - wc.x = ev->x; - wc.y = ev->y; - wc.width = ev->width; - wc.height = ev->height; - wc.border_width = ev->border_width; - wc.sibling = ev->above; - wc.stack_mode = ev->detail; - XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); - XSync(dpy, False); - } -} - -static void -destroynotify(XEvent *e) { - Client *c; - XDestroyWindowEvent *ev = &e->xdestroywindow; - - if((c = getclient(ev->window))) - unmanage(c); -} - -static void -enternotify(XEvent *e) { - Client *c; - XCrossingEvent *ev = &e->xcrossing; - - if(ev->mode != NotifyNormal || ev->detail == NotifyInferior) - return; - if((c = getclient(ev->window)) && isvisible(c)) - focus(c); - else if(ev->window == root) { - selscreen = True; - for(c = stack; c && !isvisible(c); c = c->snext); - focus(c); - } -} - -static void -expose(XEvent *e) { - XExposeEvent *ev = &e->xexpose; - - if(ev->count == 0) { - if(barwin == ev->window) - drawstatus(); - } -} - -static void -keypress(XEvent *e) { - static unsigned int len = sizeof key / sizeof key[0]; - unsigned int i; - KeySym keysym; - XKeyEvent *ev = &e->xkey; - - 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(key[i].func) - key[i].func(&key[i].arg); - } - } -} - -static void -leavenotify(XEvent *e) { - XCrossingEvent *ev = &e->xcrossing; - - if((ev->window == root) && !ev->same_screen) { - selscreen = False; - focus(NULL); - } -} - -static void -mappingnotify(XEvent *e) { - XMappingEvent *ev = &e->xmapping; - - XRefreshKeyboardMapping(ev); - if(ev->request == MappingKeyboard) - grabkeys(); -} - -static void -maprequest(XEvent *e) { - static XWindowAttributes wa; - XMapRequestEvent *ev = &e->xmaprequest; - - if(!XGetWindowAttributes(dpy, ev->window, &wa)) - return; - if(wa.override_redirect) { - XSelectInput(dpy, ev->window, - (StructureNotifyMask | PropertyChangeMask)); - return; - } - if(!getclient(ev->window)) - manage(ev->window, &wa); -} - -static void -propertynotify(XEvent *e) { - Client *c; - Window trans; - XPropertyEvent *ev = &e->xproperty; - - if(ev->state == PropertyDelete) - return; /* ignore */ - if((c = getclient(ev->window))) { - switch (ev->atom) { - default: break; - case XA_WM_TRANSIENT_FOR: - XGetTransientForHint(dpy, c->win, &trans); - if(!c->isfloat && (c->isfloat = (trans != 0))) - arrange(); - break; - case XA_WM_NORMAL_HINTS: - updatesizehints(c); - break; - } - if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { - updatetitle(c); - if(c == sel) - drawstatus(); - } - } -} - -static void -unmapnotify(XEvent *e) { - Client *c; - XUnmapEvent *ev = &e->xunmap; - - if((c = getclient(ev->window))) - unmanage(c); -} - -/* extern */ - -void (*handler[LASTEvent]) (XEvent *) = { - [ButtonPress] = buttonpress, - [ConfigureRequest] = configurerequest, - [DestroyNotify] = destroynotify, - [EnterNotify] = enternotify, - [LeaveNotify] = leavenotify, - [Expose] = expose, - [KeyPress] = keypress, - [MappingNotify] = mappingnotify, - [MapRequest] = maprequest, - [PropertyNotify] = propertynotify, - [UnmapNotify] = unmapnotify -}; - -void -grabkeys(void) { - static unsigned int len = sizeof key / sizeof key[0]; - unsigned int i; - KeyCode code; - - XUngrabKey(dpy, AnyKey, AnyModifier, root); - for(i = 0; i < len; i++) { - code = XKeysymToKeycode(dpy, key[i].keysym); - XGrabKey(dpy, code, key[i].mod, root, True, - GrabModeAsync, GrabModeAsync); - XGrabKey(dpy, code, key[i].mod | LockMask, root, True, - GrabModeAsync, GrabModeAsync); - XGrabKey(dpy, code, key[i].mod | numlockmask, root, True, - GrabModeAsync, GrabModeAsync); - XGrabKey(dpy, code, key[i].mod | numlockmask | LockMask, root, True, - GrabModeAsync, GrabModeAsync); - } -} - -void -procevent(void) { - XEvent ev; - - while(XPending(dpy)) { - XNextEvent(dpy, &ev); - if(handler[ev.type]) - (handler[ev.type])(&ev); /* call handler */ - } -} diff -r c459e05a61a8 -r 4c12dccc288d main.c --- a/main.c Sat Jun 16 21:49:51 2007 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,288 +0,0 @@ -/* (C)opyright MMVI-MMVII Anselm R. Garbe - * See LICENSE file for license details. - */ - -#include "dwm.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* extern */ - -char stext[256]; -int bh, bmw, screen, sx, sy, sw, sh, wax, way, waw, wah; -unsigned int master, nmaster, ntags, numlockmask; -Atom wmatom[WMLast], netatom[NetLast]; -Bool running = True; -Bool *seltag; -Bool selscreen = True; -Client *clients = NULL; -Client *sel = NULL; -Client *stack = NULL; -Cursor cursor[CurLast]; -Display *dpy; -DC dc = {0}; -Window root, barwin; - -/* static */ - -static int (*xerrorxlib)(Display *, XErrorEvent *); -static Bool otherwm, readin; - -static void -cleanup(void) { - close(STDIN_FILENO); - while(stack) { - resize(stack, True); - unmanage(stack); - } - if(dc.font.set) - XFreeFontSet(dpy, dc.font.set); - else - XFreeFont(dpy, dc.font.xfont); - XUngrabKey(dpy, AnyKey, AnyModifier, root); - XFreePixmap(dpy, dc.drawable); - XFreeGC(dpy, dc.gc); - XDestroyWindow(dpy, barwin); - XFreeCursor(dpy, cursor[CurNormal]); - XFreeCursor(dpy, cursor[CurResize]); - XFreeCursor(dpy, cursor[CurMove]); - XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); - XSync(dpy, False); - free(seltag); -} - -static void -scan(void) { - unsigned int i, num; - Window *wins, d1, d2; - XWindowAttributes wa; - - wins = NULL; - if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { - for(i = 0; i < num; i++) { - if(!XGetWindowAttributes(dpy, wins[i], &wa)) - continue; - if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) - continue; - if(wa.map_state == IsViewable) - manage(wins[i], &wa); - } - } - if(wins) - XFree(wins); -} - -static void -setup(void) { - int i, j; - unsigned int mask; - Window w; - XModifierKeymap *modmap; - XSetWindowAttributes wa; - - /* init atoms */ - wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); - wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); - wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); - netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); - netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); - XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, - PropModeReplace, (unsigned char *) netatom, NetLast); - /* init cursors */ - cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); - cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); - cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); - /* init modifier map */ - numlockmask = 0; - modmap = XGetModifierMapping(dpy); - for (i = 0; i < 8; i++) { - for (j = 0; j < modmap->max_keypermod; j++) { - if(modmap->modifiermap[i * modmap->max_keypermod + j] == XKeysymToKeycode(dpy, XK_Num_Lock)) - numlockmask = (1 << i); - } - } - XFreeModifiermap(modmap); - /* select for events */ - wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask - | EnterWindowMask | LeaveWindowMask; - wa.cursor = cursor[CurNormal]; - XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); - grabkeys(); - initrregs(); - for(ntags = 0; tags[ntags]; ntags++); - seltag = emallocz(sizeof(Bool) * ntags); - seltag[0] = True; - /* style */ - dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR); - dc.norm[ColBG] = getcolor(NORMBGCOLOR); - dc.norm[ColFG] = getcolor(NORMFGCOLOR); - dc.sel[ColBorder] = getcolor(SELBORDERCOLOR); - dc.sel[ColBG] = getcolor(SELBGCOLOR); - dc.sel[ColFG] = getcolor(SELFGCOLOR); - setfont(FONT); - /* geometry */ - sx = sy = 0; - sw = DisplayWidth(dpy, screen); - sh = DisplayHeight(dpy, screen); - master = MASTER; - nmaster = NMASTER; - bmw = textw(TILESYMBOL) > textw(FLOATSYMBOL) ? textw(TILESYMBOL) : textw(FLOATSYMBOL); - /* bar */ - dc.h = bh = dc.font.height + 2; - wa.override_redirect = 1; - wa.background_pixmap = ParentRelative; - wa.event_mask = ButtonPressMask | ExposureMask; - barwin = XCreateWindow(dpy, root, sx, sy + (TOPBAR ? 0 : sh - bh), sw, bh, 0, - DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), - CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); - XDefineCursor(dpy, barwin, cursor[CurNormal]); - XMapRaised(dpy, barwin); - strcpy(stext, "dwm-"VERSION); - /* windowarea */ - wax = sx; - way = sy + (TOPBAR ? bh : 0); - wah = sh - bh; - waw = sw; - /* pixmap for everything */ - dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); - dc.gc = XCreateGC(dpy, root, 0, 0); - XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); - /* multihead support */ - selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask); -} - -/* - * Startup Error handler to check if another window manager - * is already running. - */ -static int -xerrorstart(Display *dsply, XErrorEvent *ee) { - otherwm = True; - return -1; -} - -/* extern */ - -void -sendevent(Window w, Atom a, long value) { - XEvent e; - - e.type = ClientMessage; - e.xclient.window = w; - e.xclient.message_type = a; - e.xclient.format = 32; - e.xclient.data.l[0] = value; - e.xclient.data.l[1] = CurrentTime; - XSendEvent(dpy, w, False, NoEventMask, &e); - XSync(dpy, False); -} - -void -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 may call exit. - */ -int -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_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 */ -} - -int -main(int argc, char *argv[]) { - char *p; - int r, xfd; - fd_set rd; - - if(argc == 2 && !strncmp("-v", argv[1], 3)) { - fputs("dwm-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n", stdout); - exit(EXIT_SUCCESS); - } - else if(argc != 1) - eprint("usage: dwm [-v]\n"); - setlocale(LC_CTYPE, ""); - dpy = XOpenDisplay(0); - if(!dpy) - eprint("dwm: cannot open display\n"); - xfd = ConnectionNumber(dpy); - screen = DefaultScreen(dpy); - root = RootWindow(dpy, screen); - otherwm = False; - XSetErrorHandler(xerrorstart); - /* this causes an error if some other window manager is running */ - XSelectInput(dpy, root, SubstructureRedirectMask); - XSync(dpy, False); - if(otherwm) - eprint("dwm: another window manager is already running\n"); - - XSync(dpy, False); - XSetErrorHandler(NULL); - xerrorxlib = XSetErrorHandler(xerror); - XSync(dpy, False); - setup(); - drawstatus(); - scan(); - - /* main event loop, also reads status text from stdin */ - XSync(dpy, False); - procevent(); - readin = True; - while(running) { - FD_ZERO(&rd); - if(readin) - FD_SET(STDIN_FILENO, &rd); - FD_SET(xfd, &rd); - if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) { - if(errno == EINTR) - continue; - eprint("select failed\n"); - } - if(FD_ISSET(STDIN_FILENO, &rd)) { - switch(r = read(STDIN_FILENO, stext, sizeof stext - 1)) { - case -1: - strncpy(stext, strerror(errno), sizeof stext - 1); - stext[sizeof stext - 1] = '\0'; - readin = False; - break; - case 0: - strncpy(stext, "EOF", 4); - readin = False; - break; - default: - for(stext[r] = '\0', p = stext + strlen(stext) - 1; p >= stext && *p == '\n'; *p-- = '\0'); - for(; p >= stext && *p != '\n'; --p); - if(p > stext) - strncpy(stext, p + 1, sizeof stext); - } - drawstatus(); - } - if(FD_ISSET(xfd, &rd)) - procevent(); - } - cleanup(); - XCloseDisplay(dpy); - return 0; -} diff -r c459e05a61a8 -r 4c12dccc288d tag.c --- a/tag.c Sat Jun 16 21:49:51 2007 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,148 +0,0 @@ -/* (C)opyright MMVI-MMVII Anselm R. Garbe - * See LICENSE file for license details. - */ -#include "dwm.h" -#include -#include -#include -#include -#include -#include - - -typedef struct { - const char *clpattern; - const char *tpattern; - Bool isfloat; -} Rule; - -typedef struct { - regex_t *clregex; - regex_t *tregex; -} RReg; - -/* static */ - -TAGS -RULES - -static RReg *rreg = NULL; -static unsigned int len = 0; - -/* extern */ - -Client * -getnext(Client *c) { - for(; c && !isvisible(c); c = c->next); - return c; -} - -Client * -getprev(Client *c) { - for(; c && !isvisible(c); c = c->prev); - return c; -} - -void -initrregs(void) { - unsigned int i; - regex_t *reg; - - if(rreg) - return; - len = sizeof rule / sizeof rule[0]; - rreg = emallocz(len * sizeof(RReg)); - for(i = 0; i < len; i++) { - if(rule[i].clpattern) { - reg = emallocz(sizeof(regex_t)); - if(regcomp(reg, rule[i].clpattern, REG_EXTENDED)) - free(reg); - else - rreg[i].clregex = reg; - } - if(rule[i].tpattern) { - reg = emallocz(sizeof(regex_t)); - if(regcomp(reg, rule[i].tpattern, REG_EXTENDED)) - free(reg); - else - rreg[i].tregex = reg; - } - } -} - -void -settags(Client *c, Client *trans) { - char prop[512]; - unsigned int i, j; - regmatch_t tmp; - Bool matched = trans != NULL; - XClassHint ch = { 0 }; - - if(matched) { - for(i = 0; i < ntags; i++) - c->tags[i] = trans->tags[i]; - } - else { - XGetClassHint(dpy, c->win, &ch); - snprintf(prop, sizeof prop, "%s:%s:%s", - ch.res_class ? ch.res_class : "", - ch.res_name ? ch.res_name : "", c->name); - for(i = 0; i < len; i++) - if(rreg[i].clregex && !regexec(rreg[i].clregex, prop, 1, &tmp, 0)) { - c->isfloat = rule[i].isfloat; - for(j = 0; rreg[i].tregex && j < ntags; j++) { - if(!regexec(rreg[i].tregex, tags[j], 1, &tmp, 0)) { - matched = True; - c->tags[j] = True; - } - } - break; /* perform only the first rule matching */ - } - if(ch.res_class) - XFree(ch.res_class); - if(ch.res_name) - XFree(ch.res_name); - } - if(!matched) - for(i = 0; i < ntags; i++) - c->tags[i] = seltag[i]; -} - -void -tag(Arg *arg) { - unsigned int i; - - if(!sel) - return; - for(i = 0; i < ntags; i++) - sel->tags[i] = (arg->i == -1) ? True : False; - if(arg->i >= 0 && arg->i < ntags) - sel->tags[arg->i] = True; - arrange(); -} - -void -toggletag(Arg *arg) { - unsigned int i; - - if(!sel) - return; - sel->tags[arg->i] = !sel->tags[arg->i]; - for(i = 0; i < ntags && !sel->tags[i]; i++); - if(i == ntags) - sel->tags[arg->i] = True; - arrange(); -} - -/* begin code by jukka */ -void -viewnext(Arg *arg) { - unsigned int i; - Bool last = seltag[ntags-1]; - - for (i=ntags-1; i>0; --i) - seltag[i] = seltag[i-1]; - seltag[0] = last; - arrange(); -} -/* end code by jukka */ diff -r c459e05a61a8 -r 4c12dccc288d util.c --- a/util.c Sat Jun 16 21:49:51 2007 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* (C)opyright MMVI-MMVII Anselm R. Garbe - * See LICENSE file for license details. - */ -#include "dwm.h" -#include -#include -#include -#include -#include - -/* extern */ - -void * -emallocz(unsigned int size) { - void *res = calloc(1, size); - - if(!res) - eprint("fatal: could not malloc() %u bytes\n", size); - return res; -} - -void -eprint(const char *errstr, ...) { - va_list ap; - - va_start(ap, errstr); - vfprintf(stderr, errstr, ap); - va_end(ap); - exit(EXIT_FAILURE); -} - -void -spawn(Arg *arg) { - static char *shell = NULL; - - if(!shell && !(shell = getenv("SHELL"))) - shell = "/bin/sh"; - if(!arg->cmd) - return; - /* The double-fork construct avoids zombie processes and keeps the code - * clean from stupid signal handlers. */ - if(fork() == 0) { - if(fork() == 0) { - if(dpy) - close(ConnectionNumber(dpy)); - setsid(); - execl(shell, shell, "-c", arg->cmd, (char *)NULL); - fprintf(stderr, "dwm: execl '%s -c %s'", shell, arg->cmd); - perror(" failed"); - } - exit(0); - } - wait(0); -} diff -r c459e05a61a8 -r 4c12dccc288d view.c --- a/view.c Sat Jun 16 21:49:51 2007 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,324 +0,0 @@ -/* (C)opyright MMVI-MMVII Anselm R. Garbe - * See LICENSE file for license details. - */ -#include "dwm.h" -#include - -/* static */ - -static Client * -nexttiled(Client *c) { - for(c = getnext(c); c && c->isfloat; c = getnext(c->next)); - return c; -} - -static void -togglemax(Client *c) { - XEvent ev; - - if(c->isfixed) - return; - - if((c->ismax = !c->ismax)) { - c->rx = c->x; c->x = wax; - c->ry = c->y; c->y = way; - c->rw = c->w; c->w = waw - 2 * BORDERPX; - c->rh = c->h; c->h = wah - 2 * BORDERPX; - } - else { - c->x = c->rx; - c->y = c->ry; - c->w = c->rw; - c->h = c->rh; - } - resize(c, True); - while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); -} - -/* extern */ - -void (*arrange)(void) = DEFMODE; - -void -detach(Client *c) { - if(c->prev) - c->prev->next = c->next; - if(c->next) - c->next->prev = c->prev; - if(c == clients) - clients = c->next; - c->next = c->prev = NULL; -} - -void -dofloat(void) { - Client *c; - - for(c = clients; c; c = c->next) { - if(isvisible(c)) { - resize(c, True); - } - else - XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); - } - if(!sel || !isvisible(sel)) { - for(c = stack; c && !isvisible(c); c = c->snext); - focus(c); - } - restack(); -} - -void -dotile(void) { - unsigned int i, n, mw, mh, tw, th; - Client *c; - - for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)) - n++; - /* window geoms */ - mh = (n > nmaster) ? wah / nmaster : wah / (n > 0 ? n : 1); - mw = (n > nmaster) ? (waw * master) / 1000 : waw; - th = (n > nmaster) ? wah / (n - nmaster) : 0; - tw = waw - mw; - - for(i = 0, c = clients; c; c = c->next) - if(isvisible(c)) { - if(c->isfloat) { - resize(c, True); - continue; - } - c->ismax = False; - c->x = wax; - c->y = way; - if(i < nmaster) { - c->y += i * mh; - c->w = mw - 2 * BORDERPX; - c->h = mh - 2 * BORDERPX; - } - else { /* tile window */ - c->x += mw; - c->w = tw - 2 * BORDERPX; - if(th > 2 * BORDERPX) { - c->y += (i - nmaster) * th; - c->h = th - 2 * BORDERPX; - } - else /* fallback if th <= 2 * BORDERPX */ - c->h = wah - 2 * BORDERPX; - } - resize(c, False); - i++; - } - else - XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); - if(!sel || !isvisible(sel)) { - for(c = stack; c && !isvisible(c); c = c->snext); - focus(c); - } - restack(); -} - -/* begin code by mitch */ -void -arrangemax(Client *c) { - if(c == sel) { - c->ismax = True; - c->x = sx; - c->y = bh; - c->w = sw - 2 * BORDERPX; - c->h = sh - bh - 2 * BORDERPX; - XRaiseWindow(dpy, c->win); - } else { - c->ismax = False; - XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); - XLowerWindow(dpy, c->win); - } -} - -void -domax(void) { - Client *c; - - for(c = clients; c; c = c->next) { - if(isvisible(c)) { - if(c->isfloat) { - resize(c, True); - continue; - } - arrangemax(c); - resize(c, False); - } else { - XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); - } - - } - if(!sel || !isvisible(sel)) { - for(c = stack; c && !isvisible(c); c = c->snext); - focus(c); - } - restack(); -} -/* end code by mitch */ - -void -focusnext(Arg *arg) { - Client *c; - - if(!sel) - return; - if(!(c = getnext(sel->next))) - c = getnext(clients); - if(c) { - focus(c); - restack(); - } -} - -void -focusprev(Arg *arg) { - Client *c; - - if(!sel) - return; - if(!(c = getprev(sel->prev))) { - for(c = clients; c && c->next; c = c->next); - c = getprev(c); - } - if(c) { - focus(c); - restack(); - } -} - -void -incnmaster(Arg *arg) { - if((arrange == dofloat) || (nmaster + arg->i < 1) - || (wah / (nmaster + arg->i) <= 2 * BORDERPX)) - return; - nmaster += arg->i; - if(sel) - arrange(); - else - drawstatus(); -} - -Bool -isvisible(Client *c) { - unsigned int i; - - for(i = 0; i < ntags; i++) - if(c->tags[i] && seltag[i]) - return True; - return False; -} - -void -resizemaster(Arg *arg) { - if(arg->i == 0) - master = MASTER; - else { - if(waw * (master + arg->i) / 1000 >= waw - 2 * BORDERPX - || waw * (master + arg->i) / 1000 <= 2 * BORDERPX) - return; - master += arg->i; - } - arrange(); -} - -void -restack(void) { - Client *c; - XEvent ev; - - drawstatus(); - if(!sel) - return; - if(sel->isfloat || arrange == dofloat) - XRaiseWindow(dpy, sel->win); - - /* begin code by mitch */ - if(arrange == domax) { - for(c = nexttiled(clients); c; c = nexttiled(c->next)) { - arrangemax(c); - resize(c, False); - } - - } else if (arrange == dotile) { - /* end code by mitch */ - - if(!sel->isfloat) - XLowerWindow(dpy, sel->win); - for(c = nexttiled(clients); c; c = nexttiled(c->next)) { - if(c == sel) - continue; - XLowerWindow(dpy, c->win); - } - } - XSync(dpy, False); - while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); -} - -void -togglefloat(Arg *arg) { - if (!sel || arrange == dofloat) - return; - sel->isfloat = !sel->isfloat; - arrange(); -} - -void -togglemode(Arg *arg) { - /* only toggle between tile and max - float is just available through togglefloat */ - arrange = (arrange == dotile) ? domax : dotile; - if(sel) - arrange(); - else - drawstatus(); -} - -void -toggleview(Arg *arg) { - unsigned int i; - - seltag[arg->i] = !seltag[arg->i]; - for(i = 0; i < ntags && !seltag[i]; i++); - if(i == ntags) - seltag[arg->i] = True; /* cannot toggle last view */ - arrange(); -} - -void -view(Arg *arg) { - unsigned int i; - - for(i = 0; i < ntags; i++) - seltag[i] = (arg->i == -1) ? True : False; - if(arg->i >= 0 && arg->i < ntags) - seltag[arg->i] = True; - arrange(); -} - -void -zoom(Arg *arg) { - unsigned int n; - Client *c; - - if(!sel) - return; - if(sel->isfloat || (arrange == dofloat)) { - togglemax(sel); - return; - } - for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)) - n++; - - if((c = sel) == nexttiled(clients)) - if(!(c = nexttiled(c->next))) - return; - detach(c); - if(clients) - clients->prev = c; - c->next = clients; - clients = c; - focus(c); - arrange(); -}