X-Git-Url: https://git.xinqibao.xyz/dwm.git/blobdiff_plain/5a04edecb1eb3a49f659938f7d2eba11d42760ae..d66ad1457e6b1e3fc18c01767fdb499acaef3c8e:/dwm.c

diff --git a/dwm.c b/dwm.c
index a27a1ca..0af37d6 100644
--- a/dwm.c
+++ b/dwm.c
@@ -17,16 +17,12 @@
  * 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.
+ * global tags array to indicate the tags of a client.  
  *
  * Keys and tagging rules are organized as arrays and defined in config.h.
  *
  * To understand everything else, start reading main().
  */
-#include "dwm.h"
-
 #include <errno.h>
 #include <locale.h>
 #include <stdarg.h>
@@ -41,15 +37,70 @@
 #include <X11/cursorfont.h>
 #include <X11/keysym.h>
 #include <X11/Xatom.h>
+#include <X11/Xlib.h>
 #include <X11/Xproto.h>
 #include <X11/Xutil.h>
 
 /* macros */
 #define BUTTONMASK		(ButtonPressMask | ButtonReleaseMask)
 #define CLEANMASK(mask)		(mask & ~(numlockmask | LockMask))
+#define LENGTH(x)		(sizeof x / sizeof x[0])
+#define MAXTAGLEN		16
 #define MOUSEMASK		(BUTTONMASK | PointerMotionMask)
 
-/* local typedefs */
+
+/* enums */
+enum { BarTop, BarBot, BarOff };			/* bar position */
+enum { CurNormal, CurResize, CurMove, CurLast };	/* cursor */
+enum { ColBorder, ColFG, ColBG, ColLast };		/* color */
+enum { NetSupported, NetWMName, NetLast };		/* EWMH atoms */
+enum { WMProtocols, WMDelete, WMName, WMState, WMLast };/* default atoms */
+
+/* typedefs */
+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, maxax, minay, maxay;
+	long flags;
+	unsigned int border, oldborder;
+	Bool isbanned, isfixed, ismax, isfloating, wasfloating;
+	Bool *tags;
+	Client *next;
+	Client *prev;
+	Client *snext;
+	Window win;
+};
+
+typedef struct {
+	int x, y, w, h;
+	unsigned long norm[ColLast];
+	unsigned long sel[ColLast];
+	Drawable drawable;
+	GC gc;
+	struct {
+		int ascent;
+		int descent;
+		int height;
+		XFontSet set;
+		XFontStruct *xfont;
+	} font;
+} DC; /* draw context */
+
+typedef struct {
+	unsigned long mod;
+	KeySym keysym;
+	void (*func)(const char *arg);
+	const char *arg;
+} Key;
+
+typedef struct {
+	const char *symbol;
+	void (*arrange)(void);
+} Layout;
+
 typedef struct {
 	const char *prop;
 	const char *tags;
@@ -61,6 +112,88 @@ typedef struct {
 	regex_t *tagregex;
 } Regs;
 
+/* function declarations */
+void applyrules(Client *c);
+void arrange(void);
+void attach(Client *c);
+void attachstack(Client *c);
+void ban(Client *c);
+void buttonpress(XEvent *e);
+void checkotherwm(void);
+void cleanup(void);
+void compileregs(void);
+void configure(Client *c);
+void configurenotify(XEvent *e);
+void configurerequest(XEvent *e);
+void destroynotify(XEvent *e);
+void detach(Client *c);
+void detachstack(Client *c);
+void drawbar(void);
+void drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]);
+void drawtext(const char *text, unsigned long col[ColLast]);
+void *emallocz(unsigned int size);
+void enternotify(XEvent *e);
+void eprint(const char *errstr, ...);
+void expose(XEvent *e);
+void floating(void); /* default floating layout */
+void focus(Client *c);
+void focusin(XEvent *e);
+void focusnext(const char *arg);
+void focusprev(const char *arg);
+Client *getclient(Window w);
+unsigned long getcolor(const char *colstr);
+long getstate(Window w);
+Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
+void grabbuttons(Client *c, Bool focused);
+void grabkeys(void);
+unsigned int idxoftag(const char *tag);
+void initfont(const char *fontstr);
+Bool isoccupied(unsigned int t);
+Bool isprotodel(Client *c);
+Bool isvisible(Client *c);
+void keypress(XEvent *e);
+void killclient(const char *arg);
+void leavenotify(XEvent *e);
+void manage(Window w, XWindowAttributes *wa);
+void mappingnotify(XEvent *e);
+void maprequest(XEvent *e);
+void movemouse(Client *c);
+Client *nexttiled(Client *c);
+void propertynotify(XEvent *e);
+void quit(const char *arg);
+void reapply(const char *arg);
+void resize(Client *c, int x, int y, int w, int h, Bool sizehints);
+void resizemouse(Client *c);
+void restack(void);
+void run(void);
+void scan(void);
+void setclientstate(Client *c, long state);
+void setlayout(const char *arg);
+void setmwfact(const char *arg);
+void setup(void);
+void spawn(const char *arg);
+void tag(const char *arg);
+unsigned int textnw(const char *text, unsigned int len);
+unsigned int textw(const char *text);
+void tile(void);
+void togglebar(const char *arg);
+void togglefloating(const char *arg);
+void togglemax(const char *arg);
+void toggletag(const char *arg);
+void toggleview(const char *arg);
+void unban(Client *c);
+void unmanage(Client *c);
+void unmapnotify(XEvent *e);
+void updatebarpos(void);
+void updatesizehints(Client *c);
+void updatetitle(Client *c);
+void view(const char *arg);
+void viewprevtag(const char *arg);	/* views previous selected tags */
+int xerror(Display *dpy, XErrorEvent *ee);
+int xerrordummy(Display *dsply, XErrorEvent *ee);
+int xerrorstart(Display *dsply, XErrorEvent *ee);
+void zoom(const char *arg);
+
 /* variables */
 char stext[256];
 double mwfact;
@@ -68,9 +201,6 @@ int screen, sx, sy, sw, sh, wax, way, waw, wah;
 int (*xerrorxlib)(Display *, XErrorEvent *);
 unsigned int bh, bpos;
 unsigned int blw = 0;
-unsigned int ltidx = 0; /* default */
-unsigned int nlayouts = 0;
-unsigned int nrules = 0;
 unsigned int numlockmask = 0;
 void (*handler[LASTEvent]) (XEvent *) = {
 	[ButtonPress] = buttonpress,
@@ -78,15 +208,18 @@ void (*handler[LASTEvent]) (XEvent *) = {
 	[ConfigureNotify] = configurenotify,
 	[DestroyNotify] = destroynotify,
 	[EnterNotify] = enternotify,
-	[LeaveNotify] = leavenotify,
 	[Expose] = expose,
+	[FocusIn] = focusin,
 	[KeyPress] = keypress,
+	[LeaveNotify] = leavenotify,
 	[MappingNotify] = mappingnotify,
 	[MapRequest] = maprequest,
 	[PropertyNotify] = propertynotify,
 	[UnmapNotify] = unmapnotify
 };
 Atom wmatom[WMLast], netatom[NetLast];
+Bool domwfact = True;
+Bool dozoom = True;
 Bool otherwm, readin;
 Bool running = True;
 Bool selscreen = True;
@@ -96,18 +229,16 @@ Client *stack = NULL;
 Cursor cursor[CurLast];
 Display *dpy;
 DC dc = {0};
+Layout *layout = NULL;
 Window barwin, root;
 Regs *regs = NULL;
 
 /* configuration, allows nested code to access above variables */
 #include "config.h"
 
-/* Statically define the number of tags. */
-unsigned int ntags = sizeof tags / sizeof tags[0];
-Bool seltags[sizeof tags / sizeof tags[0]] = {[0] = True};
-Bool prevtags[sizeof tags / sizeof tags[0]] = {[0] = True};
+Bool prevtags[LENGTH(tags)];
 
-/* functions*/
+/* function implementations */
 void
 applyrules(Client *c) {
 	static char buf[512];
@@ -121,10 +252,10 @@ applyrules(Client *c) {
 	snprintf(buf, sizeof buf, "%s:%s:%s",
 			ch.res_class ? ch.res_class : "",
 			ch.res_name ? ch.res_name : "", c->name);
-	for(i = 0; i < nrules; i++)
+	for(i = 0; i < LENGTH(rules); i++)
 		if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &tmp, 0)) {
 			c->isfloating = rules[i].isfloating;
-			for(j = 0; regs[i].tagregex && j < ntags; j++) {
+			for(j = 0; regs[i].tagregex && j < LENGTH(tags); j++) {
 				if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) {
 					matched = True;
 					c->tags[j] = True;
@@ -148,7 +279,7 @@ arrange(void) {
 			unban(c);
 		else
 			ban(c);
-	layouts[ltidx].arrange();
+	layout->arrange();
 	focus(NULL);
 	restack();
 }
@@ -181,9 +312,9 @@ buttonpress(XEvent *e) {
 	Client *c;
 	XButtonPressedEvent *ev = &e->xbutton;
 
-	if(barwin == ev->window) {
+	if(ev->window == barwin) {
 		x = 0;
-		for(i = 0; i < ntags; i++) {
+		for(i = 0; i < LENGTH(tags); i++) {
 			x += textw(tags[i]);
 			if(ev->x < x) {
 				if(ev->button == Button1) {
@@ -209,20 +340,20 @@ buttonpress(XEvent *e) {
 		if(CLEANMASK(ev->state) != MODKEY)
 			return;
 		if(ev->button == Button1) {
-			if(isarrange(floating) || c->isfloating)
+			if((layout->arrange == floating) || c->isfloating)
 				restack();
 			else
 				togglefloating(NULL);
 			movemouse(c);
 		}
 		else if(ev->button == Button2) {
-			if(ISTILE && !c->isfixed && c->isfloating)
+			if((floating != layout->arrange) && c->isfloating)
 				togglefloating(NULL);
 			else
 				zoom(NULL);
 		}
 		else if(ev->button == Button3 && !c->isfixed) {
-			if(isarrange(floating) || c->isfloating)
+			if((floating == layout->arrange) || c->isfloating)
 				restack();
 			else
 				togglefloating(NULL);
@@ -276,9 +407,8 @@ compileregs(void) {
 
 	if(regs)
 		return;
-	nrules = sizeof rules / sizeof rules[0];
-	regs = emallocz(nrules * sizeof(Regs));
-	for(i = 0; i < nrules; i++) {
+	regs = emallocz(LENGTH(rules) * sizeof(Regs));
+	for(i = 0; i < LENGTH(rules); i++) {
 		if(rules[i].prop) {
 			reg = emallocz(sizeof(regex_t));
 			if(regcomp(reg, rules[i].prop, REG_EXTENDED))
@@ -339,7 +469,7 @@ configurerequest(XEvent *e) {
 		c->ismax = False;
 		if(ev->value_mask & CWBorderWidth)
 			c->border = ev->border_width;
-		if(c->isfixed || c->isfloating || isarrange(floating)) {
+		if(c->isfixed || c->isfloating || (floating == layout->arrange)) {
 			if(ev->value_mask & CWX)
 				c->x = ev->x;
 			if(ev->value_mask & CWY)
@@ -407,7 +537,7 @@ drawbar(void) {
 	int i, x;
 
 	dc.x = dc.y = 0;
-	for(i = 0; i < ntags; i++) {
+	for(i = 0; i < LENGTH(tags); i++) {
 		dc.w = textw(tags[i]);
 		if(seltags[i]) {
 			drawtext(tags[i], dc.sel);
@@ -420,7 +550,7 @@ drawbar(void) {
 		dc.x += dc.w;
 	}
 	dc.w = blw;
-	drawtext(layouts[ltidx].symbol, dc.norm);
+	drawtext(layout->symbol, dc.norm);
 	x = dc.x + dc.w;
 	dc.w = textw(stext);
 	dc.x = sw - dc.w;
@@ -542,7 +672,7 @@ expose(XEvent *e) {
 	XExposeEvent *ev = &e->xexpose;
 
 	if(ev->count == 0) {
-		if(barwin == ev->window)
+		if(ev->window == barwin)
 			drawbar();
 	}
 }
@@ -551,6 +681,7 @@ void
 floating(void) { /* default floating layout */
 	Client *c;
 
+	domwfact = dozoom = False;
 	for(c = clients; c; c = c->next)
 		if(isvisible(c))
 			resize(c, c->x, c->y, c->w, c->h, True);
@@ -581,6 +712,14 @@ focus(Client *c) {
 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
 }
 
+void
+focusin(XEvent *e) { /* there are some broken focus acquiring clients */
+	XFocusChangeEvent *ev = &e->xfocus;
+
+	if(sel && ev->window != sel->win)
+		XSetInputFocus(dpy, sel->win, RevertToPointerRoot, CurrentTime);
+}
+
 void
 focusnext(const char *arg) {
 	Client *c;
@@ -665,8 +804,7 @@ gettextprop(Window w, Atom atom, char *text, unsigned int size) {
 		strncpy(text, (char *)name.value, size - 1);
 	else {
 		if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
-		&& n > 0 && *list)
-		{
+		&& n > 0 && *list) {
 			strncpy(text, *list, size - 1);
 			XFreeStringList(list);
 		}
@@ -713,14 +851,31 @@ grabbuttons(Client *c, Bool focused) {
 				GrabModeAsync, GrabModeSync, None, None);
 }
 
+void
+grabkeys(void)  {
+	unsigned int i;
+	KeyCode code;
+
+	XUngrabKey(dpy, AnyKey, AnyModifier, root);
+	for(i = 0; i < LENGTH(keys); i++) {
+		code = XKeysymToKeycode(dpy, keys[i].keysym);
+		XGrabKey(dpy, code, keys[i].mod, root, True,
+				GrabModeAsync, GrabModeAsync);
+		XGrabKey(dpy, code, keys[i].mod | LockMask, root, True,
+				GrabModeAsync, GrabModeAsync);
+		XGrabKey(dpy, code, keys[i].mod | numlockmask, root, True,
+				GrabModeAsync, GrabModeAsync);
+		XGrabKey(dpy, code, keys[i].mod | numlockmask | LockMask, root, True,
+				GrabModeAsync, GrabModeAsync);
+	}
+}
+
 unsigned int
 idxoftag(const char *tag) {
 	unsigned int i;
 
-	for(i = 0; i < ntags; i++)
-		if(tags[i] == tag)
-			return i;
-	return 0;
+	for(i = 0; (i < LENGTH(tags)) && (tags[i] != tag); i++);
+	return (i < LENGTH(tags)) ? i : 0;
 }
 
 void
@@ -765,12 +920,6 @@ initfont(const char *fontstr) {
 	dc.font.height = dc.font.ascent + dc.font.descent;
 }
 
-Bool
-isarrange(void (*func)())
-{
-	return func == layouts[ltidx].arrange;
-}
-
 Bool
 isoccupied(unsigned int t) {
 	Client *c;
@@ -800,7 +949,7 @@ Bool
 isvisible(Client *c) {
 	unsigned int i;
 
-	for(i = 0; i < ntags; i++)
+	for(i = 0; i < LENGTH(tags); i++)
 		if(c->tags[i] && seltags[i])
 			return True;
 	return False;
@@ -808,31 +957,13 @@ isvisible(Client *c) {
 
 void
 keypress(XEvent *e) {
-	KEYS
-	unsigned int len = sizeof keys / sizeof keys[0];
 	unsigned int i;
-	KeyCode code;
 	KeySym keysym;
 	XKeyEvent *ev;
 
-	if(!e) { /* grabkeys */
-		XUngrabKey(dpy, AnyKey, AnyModifier, root);
-		for(i = 0; i < len; i++) {
-			code = XKeysymToKeycode(dpy, keys[i].keysym);
-			XGrabKey(dpy, code, keys[i].mod, root, True,
-					GrabModeAsync, GrabModeAsync);
-			XGrabKey(dpy, code, keys[i].mod | LockMask, root, True,
-					GrabModeAsync, GrabModeAsync);
-			XGrabKey(dpy, code, keys[i].mod | numlockmask, root, True,
-					GrabModeAsync, GrabModeAsync);
-			XGrabKey(dpy, code, keys[i].mod | numlockmask | LockMask, root, True,
-					GrabModeAsync, GrabModeAsync);
-		}
-		return;
-	}
 	ev = &e->xkey;
 	keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
-	for(i = 0; i < len; i++)
+	for(i = 0; i < LENGTH(keys); i++)
 		if(keysym == keys[i].keysym
 		&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state))
 		{
@@ -906,8 +1037,7 @@ manage(Window w, XWindowAttributes *wa) {
 	XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
 	configure(c); /* propagates border_width, if size doesn't change */
 	updatesizehints(c);
-	XSelectInput(dpy, w,
-		StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
+	XSelectInput(dpy, w, EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask);
 	grabbuttons(c, False);
 	updatetitle(c);
 	if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success))
@@ -932,7 +1062,7 @@ mappingnotify(XEvent *e) {
 
 	XRefreshKeyboardMapping(ev);
 	if(ev->request == MappingKeyboard)
-		keypress(NULL);
+		grabkeys();
 }
 
 void
@@ -1030,45 +1160,59 @@ quit(const char *arg) {
 	readin = running = False;
 }
 
+void
+reapply(const char *arg) {
+	static Bool zerotags[LENGTH(tags)] = { 0 };
+	Client *c;
+
+	for(c = clients; c; c = c->next) {
+		memcpy(c->tags, zerotags, sizeof zerotags);
+		applyrules(c);
+	}
+	arrange();
+}
+
 void
 resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
-	double dx, dy, max, min, ratio;
 	XWindowChanges wc;
 
 	if(sizehints) {
-		if(c->minay > 0 && c->maxay > 0 && (h - c->baseh) > 0 && (w - c->basew) > 0) {
-			dx = (double)(w - c->basew);
-			dy = (double)(h - c->baseh);
-			min = (double)(c->minax) / (double)(c->minay);
-			max = (double)(c->maxax) / (double)(c->maxay);
-			ratio = dx / dy;
-			if(max > 0 && min > 0 && ratio > 0) {
-				if(ratio < min) {
-					dy = (dx * min + dy) / (min * min + 1);
-					dx = dy * min;
-					w = (int)dx + c->basew;
-					h = (int)dy + c->baseh;
-				}
-				else if(ratio > max) {
-					dy = (dx * min + dy) / (max * max + 1);
-					dx = dy * min;
-					w = (int)dx + c->basew;
-					h = (int)dy + c->baseh;
-				}
-			}
+		/* set minimum possible */
+		if (w < 1)
+			w = 1;
+		if (h < 1)
+			h = 1;
+
+		/* temporarily remove base dimensions */
+		w -= c->basew;
+		h -= c->baseh;
+
+		/* adjust for aspect limits */
+		if (c->minay > 0 && c->maxay > 0 && c->minax > 0 && c->maxax > 0) {
+			if (w * c->maxay > h * c->maxax)
+				w = h * c->maxax / c->maxay;
+			else if (w * c->minay < h * c->minax)
+				h = w * c->minay / c->minax;
 		}
-		if(c->minw && w < c->minw)
+
+		/* adjust for increment value */
+		if(c->incw)
+			w -= w % c->incw;
+		if(c->inch)
+			h -= h % c->inch;
+
+		/* restore base dimensions */
+		w += c->basew;
+		h += c->baseh;
+
+		if(c->minw > 0 && w < c->minw)
 			w = c->minw;
-		if(c->minh && h < c->minh)
+		if(c->minh > 0 && h < c->minh)
 			h = c->minh;
-		if(c->maxw && w > c->maxw)
+		if(c->maxw > 0 && w > c->maxw)
 			w = c->maxw;
-		if(c->maxh && h > c->maxh)
+		if(c->maxh > 0 && h > c->maxh)
 			h = c->maxh;
-		if(c->incw)
-			w -= (w - c->basew) % c->incw;
-		if(c->inch)
-			h -= (h - c->baseh) % c->inch;
 	}
 	if(w <= 0 || h <= 0)
 		return;
@@ -1141,9 +1285,9 @@ restack(void) {
 	drawbar();
 	if(!sel)
 		return;
-	if(sel->isfloating || isarrange(floating))
+	if(sel->isfloating || (layout->arrange == floating))
 		XRaiseWindow(dpy, sel->win);
-	if(!isarrange(floating)) {
+	if(layout->arrange != floating) {
 		wc.stack_mode = Below;
 		wc.sibling = barwin;
 		if(!sel->isfloating) {
@@ -1164,14 +1308,19 @@ restack(void) {
 void
 run(void) {
 	char *p;
-	int r, xfd;
+	char buf[sizeof stext];
 	fd_set rd;
+	int r, xfd;
+	unsigned int len, offset;
 	XEvent ev;
 
 	/* main event loop, also reads status text from stdin */
 	XSync(dpy, False);
 	xfd = ConnectionNumber(dpy);
 	readin = True;
+	offset = 0;
+	len = sizeof stext - 1;
+	buf[len] = stext[len] = '\0'; /* 0-terminator is never touched */
 	while(running) {
 		FD_ZERO(&rd);
 		if(readin)
@@ -1183,10 +1332,9 @@ run(void) {
 			eprint("select failed\n");
 		}
 		if(FD_ISSET(STDIN_FILENO, &rd)) {
-			switch(r = read(STDIN_FILENO, stext, sizeof stext - 1)) {
+			switch((r = read(STDIN_FILENO, buf + offset, len - offset))) {
 			case -1:
-				strncpy(stext, strerror(errno), sizeof stext - 1);
-				stext[sizeof stext - 1] = '\0';
+				strncpy(stext, strerror(errno), len);
 				readin = False;
 				break;
 			case 0:
@@ -1194,10 +1342,18 @@ run(void) {
 				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);
+				for(p = buf + offset; r > 0; p++, r--, offset++)
+					if(*p == '\n' || *p == '\0') {
+						*p = '\0';
+						strncpy(stext, buf, len);
+						p += r - 1; /* p is buf + offset + r - 1 */
+						for(r = 0; *(p - r) && *(p - r) != '\n'; r++);
+						offset = r;
+						if(r)
+							memmove(buf, p - r + 1, r);
+						break;
+					}
+				break;
 			}
 			drawbar();
 		}
@@ -1249,16 +1405,16 @@ setlayout(const char *arg) {
 	unsigned int i;
 
 	if(!arg) {
-		if(++ltidx == nlayouts)
-			ltidx = 0;;
+		if(++layout == &layouts[LENGTH(layouts)])
+			layout = &layouts[0];
 	}
 	else {
-		for(i = 0; i < nlayouts; i++)
+		for(i = 0; i < LENGTH(layouts); i++)
 			if(!strcmp(arg, layouts[i].symbol))
 				break;
-		if(i == nlayouts)
+		if(i == LENGTH(layouts))
 			return;
-		ltidx = i;
+		layout = &layouts[i];
 	}
 	if(sel)
 		arrange();
@@ -1270,12 +1426,12 @@ void
 setmwfact(const char *arg) {
 	double delta;
 
-	if(!ISTILE)
+	if(!domwfact)
 		return;
 	/* arg handling, manipulate mwfact */
 	if(arg == NULL)
 		mwfact = MWFACT;
-	else if(1 == sscanf(arg, "%lf", &delta)) {
+	else if(sscanf(arg, "%lf", &delta) == 1) {
 		if(arg[0] == '+' || arg[0] == '-')
 			mwfact += delta;
 		else
@@ -1334,9 +1490,10 @@ setup(void) {
 	XSelectInput(dpy, root, wa.event_mask);
 
 	/* grab keys */
-	keypress(NULL);
+	grabkeys();
 
 	/* init tags */
+	memcpy(prevtags, seltags, sizeof seltags);
 	compileregs();
 
 	/* init appearance */
@@ -1351,8 +1508,8 @@ setup(void) {
 
 	/* init layouts */
 	mwfact = MWFACT;
-	nlayouts = sizeof layouts / sizeof layouts[0];
-	for(blw = i = 0; i < nlayouts; i++) {
+	layout = &layouts[0];
+	for(blw = i = 0; i < LENGTH(layouts); i++) {
 		j = textw(layouts[i].symbol);
 		if(j > blw)
 			blw = j;
@@ -1378,6 +1535,7 @@ setup(void) {
 
 	/* multihead support */
 	selscreen = XQueryPointer(dpy, root, &w, &w, &d, &d, &d, &d, &mask);
+
 }
 
 void
@@ -1410,11 +1568,9 @@ tag(const char *arg) {
 
 	if(!sel)
 		return;
-	for(i = 0; i < ntags; i++)
-		sel->tags[i] = arg == NULL;
-	i = idxoftag(arg);
-	if(i >= 0 && i < ntags)
-		sel->tags[i] = True;
+	for(i = 0; i < LENGTH(tags); i++)
+		sel->tags[i] = (NULL == arg);
+	sel->tags[idxoftag(arg)] = True;
 	arrange();
 }
 
@@ -1439,6 +1595,7 @@ tile(void) {
 	unsigned int i, n, nx, ny, nw, nh, mw, th;
 	Client *c, *mc;
 
+	domwfact = dozoom = True;
 	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
 		n++;
 
@@ -1469,6 +1626,9 @@ tile(void) {
 				nh = th - 2 * c->border;
 		}
 		resize(c, nx, ny, nw, nh, RESIZEHINTS);
+		if((RESIZEHINTS) && ((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw)))
+			/* client doesn't accept size constraints */
+			resize(c, nx, ny, nw, nh, False);
 		if(n > 1 && th != wah)
 			ny = c->y + c->h + 2 * c->border;
 	}
@@ -1501,7 +1661,7 @@ togglemax(const char *arg) {
 	if(!sel || sel->isfixed)
 		return;
 	if((sel->ismax = !sel->ismax)) {
-		if(isarrange(floating) || sel->isfloating)
+		if((layout->arrange == floating) || sel->isfloating)
 			sel->wasfloating = True;
 		else {
 			togglefloating(NULL);
@@ -1530,9 +1690,9 @@ toggletag(const char *arg) {
 		return;
 	i = idxoftag(arg);
 	sel->tags[i] = !sel->tags[i];
-	for(j = 0; j < ntags && !sel->tags[j]; j++);
-	if(j == ntags)
-		sel->tags[i] = True;
+	for(j = 0; j < LENGTH(tags) && !sel->tags[j]; j++);
+	if(j == LENGTH(tags))
+		sel->tags[i] = True; /* at least one tag must be enabled */
 	arrange();
 }
 
@@ -1542,8 +1702,8 @@ toggleview(const char *arg) {
 
 	i = idxoftag(arg);
 	seltags[i] = !seltags[i];
-	for(j = 0; j < ntags && !seltags[j]; j++);
-	if(j == ntags)
+	for(j = 0; j < LENGTH(tags) && !seltags[j]; j++);
+	if(j == LENGTH(tags))
 		seltags[i] = True; /* at least one tag must be viewed */
 	arrange();
 }
@@ -1709,21 +1869,19 @@ view(const char *arg) {
 	unsigned int i;
 
 	memcpy(prevtags, seltags, sizeof seltags);
-	for(i = 0; i < ntags; i++)
-		seltags[i] = arg == NULL;
-	i = idxoftag(arg);
-	if(i >= 0 && i < ntags)
-		seltags[i] = True;
+	for(i = 0; i < LENGTH(tags); i++)
+		seltags[i] = (NULL == arg);
+	seltags[idxoftag(arg)] = True;
 	arrange();
 }
 
 void
 viewprevtag(const char *arg) {
-	static Bool tmptags[sizeof tags / sizeof tags[0]];
+	static Bool tmp[LENGTH(tags)];
 
-	memcpy(tmptags, seltags, sizeof seltags);
+	memcpy(tmp, seltags, sizeof seltags);
 	memcpy(seltags, prevtags, sizeof seltags);
-	memcpy(prevtags, tmptags, sizeof seltags);
+	memcpy(prevtags, tmp, sizeof seltags);
 	arrange();
 }
 
@@ -1731,7 +1889,7 @@ void
 zoom(const char *arg) {
 	Client *c;
 
-	if(!sel || !ISTILE || sel->isfloating)
+	if(!sel || !dozoom || sel->isfloating)
 		return;
 	if((c = sel) == nexttiled(clients))
 		if(!(c = nexttiled(c->next)))
@@ -1745,7 +1903,8 @@ zoom(const char *arg) {
 int
 main(int argc, char *argv[]) {
 	if(argc == 2 && !strcmp("-v", argv[1]))
-		eprint("dwm-"VERSION", © 2006-2007 A. R. Garbe, S. van Dijk, J. Salmi, P. Hruby, S. Nagy\n");
+		eprint("dwm-"VERSION", © 2006-2007 Anselm R. Garbe, Sander van Dijk, "
+		       "Jukka Salmi, Premysl Hruby, Szabolcs Nagy\n");
 	else if(argc != 1)
 		eprint("usage: dwm [-v]\n");