dwm.c
changeset 1407 4cbf60555bd8
parent 1406 b561ed2a0fc1
child 1408 2215f7f11dd9
equal deleted inserted replaced
1406:b561ed2a0fc1 1407:4cbf60555bd8
       
     1 /* TODO: cleanup nexttiled, ISVISIBLE, etc */
     1 /* See LICENSE file for copyright and license details.
     2 /* See LICENSE file for copyright and license details.
     2  *
     3  *
     3  * dynamic window manager is designed like any other X client as well. It is
     4  * dynamic window manager is designed like any other X client as well. It is
     4  * driven through handling X events. In contrast to other X clients, a window
     5  * driven through handling X events. In contrast to other X clients, a window
     5  * manager selects for SubstructureRedirectMask on the root window, to receive
     6  * manager selects for SubstructureRedirectMask on the root window, to receive
    42 
    43 
    43 /* macros */
    44 /* macros */
    44 #define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask)
    45 #define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask)
    45 #define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask))
    46 #define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask))
    46 #define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
    47 #define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
    47 #define ISVISIBLE(M, C)         ((M) == (C->m) && (C->tags & M->tagset[M->seltags]))
    48 #define ISVISIBLE(M, C)         ((M) == (C->mon) && (C->tags & M->tagset[M->seltags]))
    48 #define LENGTH(X)               (sizeof X / sizeof X[0])
    49 #define LENGTH(X)               (sizeof X / sizeof X[0])
    49 #define MAX(A, B)               ((A) > (B) ? (A) : (B))
    50 #define MAX(A, B)               ((A) > (B) ? (A) : (B))
    50 #define MIN(A, B)               ((A) < (B) ? (A) : (B))
    51 #define MIN(A, B)               ((A) < (B) ? (A) : (B))
    51 #define MOUSEMASK               (BUTTONMASK|PointerMotionMask)
    52 #define MOUSEMASK               (BUTTONMASK|PointerMotionMask)
    52 #define WIDTH(X)                ((X)->w + 2 * (X)->bw)
    53 #define WIDTH(X)                ((X)->w + 2 * (X)->bw)
    87 	int bw, oldbw;
    88 	int bw, oldbw;
    88 	unsigned int tags;
    89 	unsigned int tags;
    89 	Bool isfixed, isfloating, isurgent;
    90 	Bool isfixed, isfloating, isurgent;
    90 	Client *next;
    91 	Client *next;
    91 	Client *snext;
    92 	Client *snext;
    92 	Monitor *m;
    93 	Monitor *mon;
    93 	Window win;
    94 	Window win;
    94 };
    95 };
    95 
    96 
    96 typedef struct {
    97 typedef struct {
    97 	int x, y, w, h;
    98 	int x, y, w, h;
   129 	unsigned int seltags;
   130 	unsigned int seltags;
   130 	unsigned int sellt;
   131 	unsigned int sellt;
   131 	unsigned int tagset[2];
   132 	unsigned int tagset[2];
   132 	Bool showbar;
   133 	Bool showbar;
   133 	Bool topbar;
   134 	Bool topbar;
       
   135 	Client *clients;
       
   136 	Client *sel;
       
   137 	Client *stack;
       
   138 	Monitor *next;
   134 	Window barwin;
   139 	Window barwin;
   135 	Monitor *next;
       
   136 };
   140 };
   137 
   141 
   138 typedef struct {
   142 typedef struct {
   139 	const char *class;
   143 	const char *class;
   140 	const char *instance;
   144 	const char *instance;
   249 	[UnmapNotify] = unmapnotify
   253 	[UnmapNotify] = unmapnotify
   250 };
   254 };
   251 static Atom wmatom[WMLast], netatom[NetLast];
   255 static Atom wmatom[WMLast], netatom[NetLast];
   252 static Bool otherwm;
   256 static Bool otherwm;
   253 static Bool running = True;
   257 static Bool running = True;
   254 static Client *clients = NULL;
       
   255 static Client *sel = NULL;
       
   256 static Client *stack = NULL;
       
   257 static Cursor cursor[CurLast];
   258 static Cursor cursor[CurLast];
   258 static Display *dpy;
   259 static Display *dpy;
   259 static DC dc;
   260 static DC dc;
   260 static Layout *lt[] = { NULL, NULL };
   261 static Layout *lt[] = { NULL, NULL };
   261 static Monitor *mons = NULL, *selmon = NULL;
   262 static Monitor *mons = NULL, *selmon = NULL;
   288 		if(ch.res_class)
   289 		if(ch.res_class)
   289 			XFree(ch.res_class);
   290 			XFree(ch.res_class);
   290 		if(ch.res_name)
   291 		if(ch.res_name)
   291 			XFree(ch.res_name);
   292 			XFree(ch.res_name);
   292 	}
   293 	}
   293 	c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->m->tagset[c->m->seltags];
   294 	c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
   294 }
   295 }
   295 
   296 
   296 Bool
   297 Bool
   297 applysizehints(Client *c, int *x, int *y, int *w, int *h) {
   298 applysizehints(Client *c, int *x, int *y, int *w, int *h) {
   298 	Bool baseismin;
   299 	Bool baseismin;
   360 
   361 
   361 void
   362 void
   362 arrange(void) {
   363 arrange(void) {
   363 	Monitor *m;
   364 	Monitor *m;
   364 
   365 
   365 	showhide(stack);
   366 	/* optimise two loops into one, check focus(NULL) */
       
   367 	for(m = mons; m; m = m->next)
       
   368 		showhide(m->stack);
   366 	focus(NULL);
   369 	focus(NULL);
   367 	for(m = mons; m; m = m->next) {
   370 	for(m = mons; m; m = m->next) {
   368 		if(lt[m->sellt]->arrange)
   371 		if(lt[m->sellt]->arrange)
   369 			lt[m->sellt]->arrange(m);
   372 			lt[m->sellt]->arrange(m);
   370 		restack(m);
   373 		restack(m);
   371 	}
   374 	}
   372 }
   375 }
   373 
   376 
   374 void
   377 void
   375 attach(Client *c) {
   378 attach(Client *c) {
   376 	c->next = clients;
   379 	c->next = selmon->clients;
   377 	clients = c;
   380 	selmon->clients = c;
   378 }
   381 }
   379 
   382 
   380 void
   383 void
   381 attachstack(Client *c) {
   384 attachstack(Client *c) {
   382 	c->snext = stack;
   385 	c->snext = selmon->stack;
   383 	stack = c;
   386 	selmon->stack = c;
   384 }
   387 }
   385 
   388 
   386 void
   389 void
   387 buttonpress(XEvent *e) {
   390 buttonpress(XEvent *e) {
   388 	unsigned int i, x, click;
   391 	unsigned int i, x, click;
   435 
   438 
   436 void
   439 void
   437 cleanup(void) {
   440 cleanup(void) {
   438 	Arg a = {.ui = ~0};
   441 	Arg a = {.ui = ~0};
   439 	Layout foo = { "", NULL };
   442 	Layout foo = { "", NULL };
       
   443 	Monitor *m;
   440 
   444 
   441 	view(&a);
   445 	view(&a);
   442 	lt[selmon->sellt] = &foo;
   446 	lt[selmon->sellt] = &foo;
   443 	while(stack)
   447 
   444 		unmanage(stack);
   448 	/* TODO: consider simplifying cleanup code of the stack, perhaps do that in cleanmons() ? */
       
   449 	for(m = mons; m; m = m->next)
       
   450 		while(m->stack)
       
   451 			unmanage(m->stack);
   445 	if(dc.font.set)
   452 	if(dc.font.set)
   446 		XFreeFontSet(dpy, dc.font.set);
   453 		XFreeFontSet(dpy, dc.font.set);
   447 	else
   454 	else
   448 		XFreeFont(dpy, dc.font.xfont);
   455 		XFreeFont(dpy, dc.font.xfont);
   449 	XUngrabKey(dpy, AnyKey, AnyModifier, root);
   456 	XUngrabKey(dpy, AnyKey, AnyModifier, root);
   541 				c->x = sx + (sw / 2 - c->w / 2); /* center in x direction */
   548 				c->x = sx + (sw / 2 - c->w / 2); /* center in x direction */
   542 			if((c->y - sy + c->h) > sh && c->isfloating)
   549 			if((c->y - sy + c->h) > sh && c->isfloating)
   543 				c->y = sy + (sh / 2 - c->h / 2); /* center in y direction */
   550 				c->y = sy + (sh / 2 - c->h / 2); /* center in y direction */
   544 			if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
   551 			if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
   545 				configure(c);
   552 				configure(c);
   546 			if(ISVISIBLE((c->m), c))
   553 			if(ISVISIBLE((c->mon), c))
   547 				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
   554 				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
   548 		}
   555 		}
   549 		else
   556 		else
   550 			configure(c);
   557 			configure(c);
   551 	}
   558 	}
   573 
   580 
   574 void
   581 void
   575 detach(Client *c) {
   582 detach(Client *c) {
   576 	Client **tc;
   583 	Client **tc;
   577 
   584 
   578 	for(tc = &clients; *tc && *tc != c; tc = &(*tc)->next);
   585 	for(tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
   579 	*tc = c->next;
   586 	*tc = c->next;
   580 }
   587 }
   581 
   588 
   582 void
   589 void
   583 detachstack(Client *c) {
   590 detachstack(Client *c) {
   584 	Client **tc;
   591 	Client **tc;
   585 
   592 
   586 	for(tc = &stack; *tc && *tc != c; tc = &(*tc)->snext);
   593 	for(tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
   587 	*tc = c->snext;
   594 	*tc = c->snext;
   588 }
   595 }
   589 
   596 
   590 void
   597 void
   591 die(const char *errstr, ...) {
   598 die(const char *errstr, ...) {
   602 	int x;
   609 	int x;
   603 	unsigned int i, occ = 0, urg = 0;
   610 	unsigned int i, occ = 0, urg = 0;
   604 	unsigned long *col;
   611 	unsigned long *col;
   605 	Client *c;
   612 	Client *c;
   606 
   613 
   607 	for(c = clients; c; c = c->next) {
   614 	for(c = m->clients; c; c = c->next) {
   608 		if(m == c->m) {
   615 		occ |= c->tags;
   609 			occ |= c->tags;
   616 		if(c->isurgent)
   610 			if(c->isurgent)
   617 			urg |= c->tags;
   611 				urg |= c->tags;
       
   612 		}
       
   613 	}
   618 	}
   614 
   619 
   615 	dc.x = 0;
   620 	dc.x = 0;
   616 #ifdef XINERAMA
   621 #ifdef XINERAMA
   617 	{
   622 	{
   626 	m->btx = dc.x;
   631 	m->btx = dc.x;
   627 	for(i = 0; i < LENGTH(tags); i++) {
   632 	for(i = 0; i < LENGTH(tags); i++) {
   628 		dc.w = TEXTW(tags[i]);
   633 		dc.w = TEXTW(tags[i]);
   629 		col = m->tagset[m->seltags] & 1 << i ? dc.sel : dc.norm;
   634 		col = m->tagset[m->seltags] & 1 << i ? dc.sel : dc.norm;
   630 		drawtext(tags[i], col, urg & 1 << i);
   635 		drawtext(tags[i], col, urg & 1 << i);
   631 		drawsquare(m == selmon && sel && sel->tags & 1 << i,
   636 		drawsquare(m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
   632 		           occ & 1 << i, urg & 1 << i, col);
   637 		           occ & 1 << i, urg & 1 << i, col);
   633 		dc.x += dc.w;
   638 		dc.x += dc.w;
   634 	}
   639 	}
   635 	if(blw > 0) {
   640 	if(blw > 0) {
   636 		dc.w = blw;
   641 		dc.w = blw;
   647 			dc.w = m->ww - x;
   652 			dc.w = m->ww - x;
   648 		}
   653 		}
   649 		drawtext(stext, dc.norm, False);
   654 		drawtext(stext, dc.norm, False);
   650 		if((dc.w = dc.x - x) > bh) {
   655 		if((dc.w = dc.x - x) > bh) {
   651 			dc.x = x;
   656 			dc.x = x;
   652 			if(sel) {
   657 			if(selmon->sel) {
   653 				drawtext(sel->name, dc.sel, False);
   658 				drawtext(selmon->sel->name, dc.sel, False);
   654 				drawsquare(sel->isfixed, sel->isfloating, False, dc.sel);
   659 				drawsquare(selmon->sel->isfixed, selmon->sel->isfloating, False, dc.sel);
   655 			}
   660 			}
   656 			else
   661 			else
   657 				drawtext(NULL, dc.norm, False);
   662 				drawtext(NULL, dc.norm, False);
   658 		}
   663 		}
   659 	}
   664 	}
   749 			}
   754 			}
   750 }
   755 }
   751 
   756 
   752 void
   757 void
   753 focus(Client *c) {
   758 focus(Client *c) {
   754 	if(!c || !ISVISIBLE((c->m), c))
   759 	if(!c || !ISVISIBLE((c->mon), c))
   755 		for(c = stack; c && !ISVISIBLE(selmon, c); c = c->snext);
   760 		for(c = selmon->stack; c && !ISVISIBLE(selmon, c); c = c->snext);
   756 	if(sel && sel != c) {
   761 	if(selmon->sel && selmon->sel != c) {
   757 		grabbuttons(sel, False);
   762 		grabbuttons(selmon->sel, False);
   758 		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
   763 		XSetWindowBorder(dpy, selmon->sel->win, dc.norm[ColBorder]);
   759 	}
   764 	}
   760 	if(c) {
   765 	if(c) {
   761 		if(c->isurgent)
   766 		if(c->isurgent)
   762 			clearurgent(c);
   767 			clearurgent(c);
   763 		detachstack(c);
   768 		detachstack(c);
   766 		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
   771 		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
   767 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
   772 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
   768 	}
   773 	}
   769 	else
   774 	else
   770 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
   775 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
   771 	sel = c;
   776 	selmon->sel = c;
   772 	drawbars();
   777 	drawbars();
   773 }
   778 }
   774 
   779 
   775 void
   780 void
   776 focusin(XEvent *e) { /* there are some broken focus acquiring clients */
   781 focusin(XEvent *e) { /* there are some broken focus acquiring clients */
   777 	XFocusChangeEvent *ev = &e->xfocus;
   782 	XFocusChangeEvent *ev = &e->xfocus;
   778 
   783 
   779 	if(sel && ev->window != sel->win)
   784 	if(selmon->sel && ev->window != selmon->sel->win)
   780 		XSetInputFocus(dpy, sel->win, RevertToPointerRoot, CurrentTime);
   785 		XSetInputFocus(dpy, selmon->sel->win, RevertToPointerRoot, CurrentTime);
   781 }
   786 }
   782 
   787 
   783 #ifdef XINERAMA
   788 #ifdef XINERAMA
   784 void
   789 void
   785 focusmon(const Arg *arg) {
   790 focusmon(const Arg *arg) {
   798 
   803 
   799 void
   804 void
   800 focusstack(const Arg *arg) {
   805 focusstack(const Arg *arg) {
   801 	Client *c = NULL, *i;
   806 	Client *c = NULL, *i;
   802 
   807 
   803 	if(!sel)
   808 	if(!selmon->sel)
   804 		return;
   809 		return;
   805 	if(arg->i > 0) {
   810 	if(arg->i > 0) {
   806 		for(c = sel->next; c && !ISVISIBLE(selmon, c); c = c->next);
   811 		for(c = selmon->sel->next; c && !ISVISIBLE(selmon, c); c = c->next);
   807 		if(!c)
   812 		if(!c)
   808 			for(c = clients; c && !ISVISIBLE(selmon, c); c = c->next);
   813 			for(c = selmon->clients; c && !ISVISIBLE(selmon, c); c = c->next);
   809 	}
   814 	}
   810 	else {
   815 	else {
   811 		for(i = clients; i != sel; i = i->next)
   816 		for(i = selmon->clients; i != selmon->sel; i = i->next)
   812 			if(ISVISIBLE(selmon, i))
   817 			if(ISVISIBLE(selmon, i))
   813 				c = i;
   818 				c = i;
   814 		if(!c)
   819 		if(!c)
   815 			for(; i; i = i->next)
   820 			for(; i; i = i->next)
   816 				if(ISVISIBLE(selmon, i))
   821 				if(ISVISIBLE(selmon, i))
   822 	}
   827 	}
   823 }
   828 }
   824 
   829 
   825 Client *
   830 Client *
   826 getclient(Window w) {
   831 getclient(Window w) {
   827 	Client *c;
   832 	Client *c = NULL;
   828 
   833 	Monitor *m;
   829 	for(c = clients; c && c->win != w; c = c->next);
   834 
       
   835 	for(m = mons; m; m = m->next)
       
   836 		for(c = m->clients; c && c->win != w; c = c->next);
   830 	return c;
   837 	return c;
   831 }
   838 }
   832 
   839 
   833 unsigned long
   840 unsigned long
   834 getcolor(const char *colstr) {
   841 getcolor(const char *colstr) {
   990 
   997 
   991 void
   998 void
   992 killclient(const Arg *arg) {
   999 killclient(const Arg *arg) {
   993 	XEvent ev;
  1000 	XEvent ev;
   994 
  1001 
   995 	if(!sel)
  1002 	if(!selmon->sel)
   996 		return;
  1003 		return;
   997 	if(isprotodel(sel)) {
  1004 	if(isprotodel(selmon->sel)) {
   998 		ev.type = ClientMessage;
  1005 		ev.type = ClientMessage;
   999 		ev.xclient.window = sel->win;
  1006 		ev.xclient.window = selmon->sel->win;
  1000 		ev.xclient.message_type = wmatom[WMProtocols];
  1007 		ev.xclient.message_type = wmatom[WMProtocols];
  1001 		ev.xclient.format = 32;
  1008 		ev.xclient.format = 32;
  1002 		ev.xclient.data.l[0] = wmatom[WMDelete];
  1009 		ev.xclient.data.l[0] = wmatom[WMDelete];
  1003 		ev.xclient.data.l[1] = CurrentTime;
  1010 		ev.xclient.data.l[1] = CurrentTime;
  1004 		XSendEvent(dpy, sel->win, False, NoEventMask, &ev);
  1011 		XSendEvent(dpy, selmon->sel->win, False, NoEventMask, &ev);
  1005 	}
  1012 	}
  1006 	else
  1013 	else
  1007 		XKillClient(dpy, sel->win);
  1014 		XKillClient(dpy, selmon->sel->win);
  1008 }
  1015 }
  1009 
  1016 
  1010 void
  1017 void
  1011 manage(Window w, XWindowAttributes *wa) {
  1018 manage(Window w, XWindowAttributes *wa) {
  1012 	static Client cz;
  1019 	static Client cz;
  1016 
  1023 
  1017 	if(!(c = malloc(sizeof(Client))))
  1024 	if(!(c = malloc(sizeof(Client))))
  1018 		die("fatal: could not malloc() %u bytes\n", sizeof(Client));
  1025 		die("fatal: could not malloc() %u bytes\n", sizeof(Client));
  1019 	*c = cz;
  1026 	*c = cz;
  1020 	c->win = w;
  1027 	c->win = w;
  1021 	c->m = selmon;
  1028 	c->mon = selmon;
  1022 
  1029 
  1023 	/* geometry */
  1030 	/* geometry */
  1024 	c->x = wa->x;
  1031 	c->x = wa->x;
  1025 	c->y = wa->y;
  1032 	c->y = wa->y;
  1026 	c->w = wa->width;
  1033 	c->w = wa->width;
  1093 
  1100 
  1094 void
  1101 void
  1095 monocle(Monitor *m) {
  1102 monocle(Monitor *m) {
  1096 	Client *c;
  1103 	Client *c;
  1097 
  1104 
  1098 	for(c = nexttiled(m, clients); c; c = nexttiled(m, c->next))
  1105 	for(c = nexttiled(m, selmon->clients); c; c = nexttiled(m, c->next))
  1099 		resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw);
  1106 		resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw);
  1100 }
  1107 }
  1101 
  1108 
  1102 void
  1109 void
  1103 movemouse(const Arg *arg) {
  1110 movemouse(const Arg *arg) {
  1105 	unsigned int dui;
  1112 	unsigned int dui;
  1106 	Client *c;
  1113 	Client *c;
  1107 	Window dummy;
  1114 	Window dummy;
  1108 	XEvent ev;
  1115 	XEvent ev;
  1109 
  1116 
  1110 	if(!(c = sel))
  1117 	if(!(c = selmon->sel))
  1111 		return;
  1118 		return;
  1112 	restack(selmon);
  1119 	restack(selmon);
  1113 	ocx = c->x;
  1120 	ocx = c->x;
  1114 	ocy = c->y;
  1121 	ocy = c->y;
  1115 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1122 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1183 			drawbars();
  1190 			drawbars();
  1184 			break;
  1191 			break;
  1185 		}
  1192 		}
  1186 		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
  1193 		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
  1187 			updatetitle(c);
  1194 			updatetitle(c);
  1188 			if(c == sel)
  1195 			if(c == selmon->sel)
  1189 				drawbars();
  1196 				drawbars();
  1190 		}
  1197 		}
  1191 	}
  1198 	}
  1192 }
  1199 }
  1193 
  1200 
  1218 	int ocx, ocy;
  1225 	int ocx, ocy;
  1219 	int nw, nh;
  1226 	int nw, nh;
  1220 	Client *c;
  1227 	Client *c;
  1221 	XEvent ev;
  1228 	XEvent ev;
  1222 
  1229 
  1223 	if(!(c = sel))
  1230 	if(!(c = selmon->sel))
  1224 		return;
  1231 		return;
  1225 	restack(selmon);
  1232 	restack(selmon);
  1226 	ocx = c->x;
  1233 	ocx = c->x;
  1227 	ocy = c->y;
  1234 	ocy = c->y;
  1228 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1235 	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
  1263 	Client *c;
  1270 	Client *c;
  1264 	XEvent ev;
  1271 	XEvent ev;
  1265 	XWindowChanges wc;
  1272 	XWindowChanges wc;
  1266 
  1273 
  1267 	drawbars();
  1274 	drawbars();
  1268 	if(!sel)
  1275 	if(!selmon->sel)
  1269 		return;
  1276 		return;
  1270 	if(m == selmon && (sel->isfloating || !lt[m->sellt]->arrange))
  1277 	if(m == selmon && (selmon->sel->isfloating || !lt[m->sellt]->arrange))
  1271 		XRaiseWindow(dpy, sel->win);
  1278 		XRaiseWindow(dpy, selmon->sel->win);
  1272 	if(lt[m->sellt]->arrange) {
  1279 	if(lt[m->sellt]->arrange) {
  1273 		wc.stack_mode = Below;
  1280 		wc.stack_mode = Below;
  1274 		wc.sibling = m->barwin;
  1281 		wc.sibling = m->barwin;
  1275 		for(c = stack; c; c = c->snext)
  1282 		for(c = m->stack; c; c = c->snext)
  1276 			if(!c->isfloating && ISVISIBLE(m, c)) {
  1283 			if(!c->isfloating && ISVISIBLE(m, c)) {
  1277 				XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
  1284 				XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
  1278 				wc.sibling = c->win;
  1285 				wc.sibling = c->win;
  1279 			}
  1286 			}
  1280 	}
  1287 	}
  1332 setlayout(const Arg *arg) {
  1339 setlayout(const Arg *arg) {
  1333 	if(!arg || !arg->v || arg->v != lt[selmon->sellt])
  1340 	if(!arg || !arg->v || arg->v != lt[selmon->sellt])
  1334 		selmon->sellt ^= 1;
  1341 		selmon->sellt ^= 1;
  1335 	if(arg && arg->v)
  1342 	if(arg && arg->v)
  1336 		lt[selmon->sellt] = (Layout *)arg->v;
  1343 		lt[selmon->sellt] = (Layout *)arg->v;
  1337 	if(sel)
  1344 	if(selmon->sel)
  1338 		arrange();
  1345 		arrange();
  1339 	else
  1346 	else
  1340 		drawbars();
  1347 		drawbars();
  1341 }
  1348 }
  1342 
  1349 
  1423 
  1430 
  1424 void
  1431 void
  1425 showhide(Client *c) {
  1432 showhide(Client *c) {
  1426 	if(!c)
  1433 	if(!c)
  1427 		return;
  1434 		return;
  1428 	if(ISVISIBLE((c->m), c)) { /* show clients top down */
  1435 	if(ISVISIBLE((c->mon), c)) { /* show clients top down */
  1429 		XMoveWindow(dpy, c->win, c->x, c->y);
  1436 		XMoveWindow(dpy, c->win, c->x, c->y);
  1430 		if(!lt[c->m->sellt]->arrange || c->isfloating)
  1437 		if(!lt[c->mon->sellt]->arrange || c->isfloating)
  1431 			resize(c, c->x, c->y, c->w, c->h);
  1438 			resize(c, c->x, c->y, c->w, c->h);
  1432 		showhide(c->snext);
  1439 		showhide(c->snext);
  1433 	}
  1440 	}
  1434 	else { /* hide clients bottom up */
  1441 	else { /* hide clients bottom up */
  1435 		showhide(c->snext);
  1442 		showhide(c->snext);
  1457 	}
  1464 	}
  1458 }
  1465 }
  1459 
  1466 
  1460 void
  1467 void
  1461 tag(const Arg *arg) {
  1468 tag(const Arg *arg) {
  1462 	if(sel && arg->ui & TAGMASK) {
  1469 	if(selmon->sel && arg->ui & TAGMASK) {
  1463 		sel->tags = arg->ui & TAGMASK;
  1470 		selmon->sel->tags = arg->ui & TAGMASK;
  1464 		arrange();
  1471 		arrange();
  1465 	}
  1472 	}
  1466 }
  1473 }
  1467 
  1474 
  1468 #ifdef XINERAMA
  1475 #ifdef XINERAMA
  1471 	unsigned int i;
  1478 	unsigned int i;
  1472 	Monitor *m;
  1479 	Monitor *m;
  1473 
  1480 
  1474 	for(i = 0, m = mons; m; m = m->next, i++)
  1481 	for(i = 0, m = mons; m; m = m->next, i++)
  1475 		if(i == arg->ui) {
  1482 		if(i == arg->ui) {
  1476 			sel->m = m;
  1483 			selmon->sel->m = m;
  1477 			arrange();
  1484 			arrange();
  1478 			break;
  1485 			break;
  1479 		}
  1486 		}
  1480 }
  1487 }
  1481 #endif /* XINERAMA */
  1488 #endif /* XINERAMA */
  1495 tile(Monitor *m) {
  1502 tile(Monitor *m) {
  1496 	int x, y, h, w, mw;
  1503 	int x, y, h, w, mw;
  1497 	unsigned int i, n;
  1504 	unsigned int i, n;
  1498 	Client *c;
  1505 	Client *c;
  1499 
  1506 
  1500 	for(n = 0, c = nexttiled(m, clients); c; c = nexttiled(m, c->next), n++);
  1507 	for(n = 0, c = nexttiled(m, m->clients); c; c = nexttiled(m, c->next), n++);
  1501 	if(n == 0)
  1508 	if(n == 0)
  1502 		return;
  1509 		return;
  1503 
  1510 
  1504 	/* master */
  1511 	/* master */
  1505 	c = nexttiled(m, clients);
  1512 	c = nexttiled(m, m->clients);
  1506 	mw = m->mfact * m->ww;
  1513 	mw = m->mfact * m->ww;
  1507 	resize(c, m->wx, m->wy, (n == 1 ? m->ww : mw) - 2 * c->bw, m->wh - 2 * c->bw);
  1514 	resize(c, m->wx, m->wy, (n == 1 ? m->ww : mw) - 2 * c->bw, m->wh - 2 * c->bw);
  1508 
  1515 
  1509 	if(--n == 0)
  1516 	if(--n == 0)
  1510 		return;
  1517 		return;
  1533 	arrange();
  1540 	arrange();
  1534 }
  1541 }
  1535 
  1542 
  1536 void
  1543 void
  1537 togglefloating(const Arg *arg) {
  1544 togglefloating(const Arg *arg) {
  1538 	if(!sel)
  1545 	if(!selmon->sel)
  1539 		return;
  1546 		return;
  1540 	sel->isfloating = !sel->isfloating || sel->isfixed;
  1547 	selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
  1541 	if(sel->isfloating)
  1548 	if(selmon->sel->isfloating)
  1542 		resize(sel, sel->x, sel->y, sel->w, sel->h);
  1549 		resize(selmon->sel, selmon->sel->x, selmon->sel->y, selmon->sel->w, selmon->sel->h);
  1543 	arrange();
  1550 	arrange();
  1544 }
  1551 }
  1545 
  1552 
  1546 void
  1553 void
  1547 toggletag(const Arg *arg) {
  1554 toggletag(const Arg *arg) {
  1548 	unsigned int mask;
  1555 	unsigned int mask;
  1549 
  1556 
  1550 	if(!sel)
  1557 	if(!selmon->sel)
  1551 		return;
  1558 		return;
  1552 	
  1559 	
  1553 	mask = sel->tags ^ (arg->ui & TAGMASK);
  1560 	mask = selmon->sel->tags ^ (arg->ui & TAGMASK);
  1554 	if(mask) {
  1561 	if(mask) {
  1555 		sel->tags = mask;
  1562 		selmon->sel->tags = mask;
  1556 		arrange();
  1563 		arrange();
  1557 	}
  1564 	}
  1558 }
  1565 }
  1559 
  1566 
  1560 void
  1567 void
  1576 	XGrabServer(dpy);
  1583 	XGrabServer(dpy);
  1577 	XSetErrorHandler(xerrordummy);
  1584 	XSetErrorHandler(xerrordummy);
  1578 	XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
  1585 	XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
  1579 	detach(c);
  1586 	detach(c);
  1580 	detachstack(c);
  1587 	detachstack(c);
  1581 	if(sel == c)
  1588 	if(selmon->sel == c)
  1582 		focus(NULL);
  1589 		focus(NULL);
  1583 	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  1590 	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  1584 	setclientstate(c, WithdrawnState);
  1591 	setclientstate(c, WithdrawnState);
  1585 	free(c);
  1592 	free(c);
  1586 	XSync(dpy, False);
  1593 	XSync(dpy, False);
  1632 
  1639 
  1633 void
  1640 void
  1634 updategeom(void) {
  1641 updategeom(void) {
  1635 	int i, n = 1;
  1642 	int i, n = 1;
  1636 	Client *c;
  1643 	Client *c;
  1637 	Monitor *newmons = NULL, *m;
  1644 	Monitor *newmons = NULL, *m, *tm;
  1638 
  1645 
  1639 #ifdef XINERAMA
  1646 #ifdef XINERAMA
  1640 	XineramaScreenInfo *info = NULL;
  1647 	XineramaScreenInfo *info = NULL;
  1641 
  1648 
  1642 	if(XineramaIsActive(dpy))
  1649 	if(XineramaIsActive(dpy))
  1673 	}
  1680 	}
  1674 
  1681 
  1675 	/* bar geometry setup */
  1682 	/* bar geometry setup */
  1676 	for(m = newmons; m; m = m->next) {
  1683 	for(m = newmons; m; m = m->next) {
  1677 		/* TODO: consider removing the following values from config.h */
  1684 		/* TODO: consider removing the following values from config.h */
       
  1685 		m->clients = NULL;
       
  1686 		m->sel = NULL;
       
  1687 		m->stack = NULL;
  1678 		m->seltags = 0;
  1688 		m->seltags = 0;
  1679 		m->sellt = 0;
  1689 		m->sellt = 0;
  1680 		m->tagset[0] = m->tagset[1] = 1;
  1690 		m->tagset[0] = m->tagset[1] = 1;
  1681 		m->mfact = mfact;
  1691 		m->mfact = mfact;
  1682 		m->showbar = showbar;
  1692 		m->showbar = showbar;
  1683 		m->topbar = topbar;
  1693 		m->topbar = topbar;
  1684 		updatebarpos(m);
  1694 		updatebarpos(m);
  1685 		/* reassign all clients with same screen number */
  1695 		/* reassign all clients with same screen number */
  1686 		for(c = clients; c; c = c->next)
  1696 		for(tm = mons; tm; tm = tm->next)
  1687 			if(c->m->screen_number == m->screen_number)
  1697 			if(tm->screen_number == m->screen_number) {
  1688 				c->m = m;
  1698 				m->clients = tm->clients;
  1689 	}
  1699 				m->stack = tm->stack;
  1690 
  1700 				tm->clients = NULL;
  1691 	/* reassign left over clients with disappeared screen number */
  1701 				tm->stack = NULL;
  1692 	for(c = clients; c; c = c->next)
  1702 				for(c = m->clients; c; c = c->next)
  1693 		if(c->m->screen_number >= n)
  1703 					c->mon = m;
  1694 			c->m = newmons;
  1704 			}
       
  1705 	}
       
  1706 
       
  1707 	/* reassign left over clients of disappeared monitors */
       
  1708 	for(tm = mons; tm; tm = tm->next) {
       
  1709 		while(tm->clients) {
       
  1710 			c = tm->clients->next;
       
  1711 			tm->clients->next = newmons->clients;
       
  1712 			tm->clients->mon = newmons;
       
  1713 			newmons->clients = tm->clients;
       
  1714 			tm->clients = c;
       
  1715 		}
       
  1716 		while(tm->stack) {
       
  1717 			c = tm->stack->snext;
       
  1718 			tm->stack->snext = newmons->stack;
       
  1719 			newmons->stack = tm->stack;
       
  1720 			tm->stack = c;
       
  1721 		}
       
  1722 	}
  1695 
  1723 
  1696 	/* select focused monitor */
  1724 	/* select focused monitor */
  1697 	if(!selmon) {
  1725 	if(!selmon) {
  1698 		selmon = newmons;
  1726 		selmon = newmons;
  1699 		int di, x, y;
  1727 		int di, x, y;
  1793 void
  1821 void
  1794 updatewmhints(Client *c) {
  1822 updatewmhints(Client *c) {
  1795 	XWMHints *wmh;
  1823 	XWMHints *wmh;
  1796 
  1824 
  1797 	if((wmh = XGetWMHints(dpy, c->win))) {
  1825 	if((wmh = XGetWMHints(dpy, c->win))) {
  1798 		if(c == sel && wmh->flags & XUrgencyHint) {
  1826 		if(c == selmon->sel && wmh->flags & XUrgencyHint) {
  1799 			wmh->flags &= ~XUrgencyHint;
  1827 			wmh->flags &= ~XUrgencyHint;
  1800 			XSetWMHints(dpy, c->win, wmh);
  1828 			XSetWMHints(dpy, c->win, wmh);
  1801 		}
  1829 		}
  1802 		else
  1830 		else
  1803 			c->isurgent = (wmh->flags & XUrgencyHint) ? True : False;
  1831 			c->isurgent = (wmh->flags & XUrgencyHint) ? True : False;
  1849 	return -1;
  1877 	return -1;
  1850 }
  1878 }
  1851 
  1879 
  1852 void
  1880 void
  1853 zoom(const Arg *arg) {
  1881 zoom(const Arg *arg) {
  1854 	Client *c = sel;
  1882 	Client *c = selmon->sel;
  1855 
  1883 
  1856 	if(!lt[selmon->sellt]->arrange || lt[selmon->sellt]->arrange == monocle || (sel && sel->isfloating))
  1884 	if(!lt[selmon->sellt]->arrange || lt[selmon->sellt]->arrange == monocle || (selmon->sel && selmon->sel->isfloating))
  1857 		return;
  1885 		return;
  1858 	if(c == nexttiled(selmon, clients))
  1886 	if(c == nexttiled(selmon, selmon->clients))
  1859 		if(!c || !(c = nexttiled(selmon, c->next)))
  1887 		if(!c || !(c = nexttiled(selmon, c->next)))
  1860 			return;
  1888 			return;
  1861 	detach(c);
  1889 	detach(c);
  1862 	attach(c);
  1890 	attach(c);
  1863 	focus(c);
  1891 	focus(c);