dwm.c
changeset 997 8e721021e636
parent 996 b4d47b6a8ba8
child 998 854a324f5c92
equal deleted inserted replaced
996:b4d47b6a8ba8 997:8e721021e636
   110 typedef struct {
   110 typedef struct {
   111 	regex_t *propregex;
   111 	regex_t *propregex;
   112 	regex_t *tagregex;
   112 	regex_t *tagregex;
   113 } Regs;
   113 } Regs;
   114 
   114 
   115 /* functions */
   115 /* forward declarations */
   116 
       
   117 static void applyrules(Client *c);
   116 static void applyrules(Client *c);
   118 static void arrange(void);
   117 static void arrange(void);
   119 static void attach(Client *c);
   118 static void attach(Client *c);
   120 static void attachstack(Client *c);
   119 static void attachstack(Client *c);
   121 static void ban(Client *c);
   120 static void ban(Client *c);
   122 static void buttonpress(XEvent *e);
   121 static void buttonpress(XEvent *e);
       
   122 static void checkotherwm(void);
   123 static void cleanup(void);
   123 static void cleanup(void);
   124 static void compileregs(void);
   124 static void compileregs(void);
   125 static void configure(Client *c);
   125 static void configure(Client *c);
   126 static void configurenotify(XEvent *e);
   126 static void configurenotify(XEvent *e);
   127 static void configurerequest(XEvent *e);
   127 static void configurerequest(XEvent *e);
   138 static void floating(void); /* default floating layout */
   138 static void floating(void); /* default floating layout */
   139 static void focus(Client *c);
   139 static void focus(Client *c);
   140 static void focusnext(const char *arg);
   140 static void focusnext(const char *arg);
   141 static void focusprev(const char *arg);
   141 static void focusprev(const char *arg);
   142 static Client *getclient(Window w);
   142 static Client *getclient(Window w);
       
   143 static unsigned long getcolor(const char *colstr);
   143 static long getstate(Window w);
   144 static long getstate(Window w);
   144 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   145 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   145 static void grabbuttons(Client *c, Bool focused);
   146 static void grabbuttons(Client *c, Bool focused);
   146 static unsigned int idxoftag(const char *tag);
   147 static unsigned int idxoftag(const char *tag);
   147 static void initbar(void);
       
   148 static unsigned long initcolor(const char *colstr);
       
   149 static void initfont(const char *fontstr);
   148 static void initfont(const char *fontstr);
   150 static void initlayouts(void);
       
   151 static void initstyle(void);
       
   152 static Bool isarrange(void (*func)());
   149 static Bool isarrange(void (*func)());
   153 static Bool isfloating(void);
       
   154 static Bool isoccupied(unsigned int t);
   150 static Bool isoccupied(unsigned int t);
   155 static Bool isprotodel(Client *c);
   151 static Bool isprotodel(Client *c);
   156 static Bool isvisible(Client *c);
   152 static Bool isvisible(Client *c);
   157 static void keypress(XEvent *e);
   153 static void keypress(XEvent *e);
   158 static void killclient(const char *arg);
   154 static void killclient(const char *arg);
   165 static void propertynotify(XEvent *e);
   161 static void propertynotify(XEvent *e);
   166 static void quit(const char *arg);
   162 static void quit(const char *arg);
   167 static void resize(Client *c, int x, int y, int w, int h, Bool sizehints);
   163 static void resize(Client *c, int x, int y, int w, int h, Bool sizehints);
   168 static void resizemouse(Client *c);
   164 static void resizemouse(Client *c);
   169 static void restack(void);
   165 static void restack(void);
       
   166 static void run(void);
   170 static void scan(void);
   167 static void scan(void);
   171 static void setclientstate(Client *c, long state);
   168 static void setclientstate(Client *c, long state);
   172 static void setlayout(const char *arg);
   169 static void setlayout(const char *arg);
   173 static void setmwfact(const char *arg);
   170 static void setmwfact(const char *arg);
   174 static void setup(void);
   171 static void setup(void);
   234 static Regs *regs = NULL;
   231 static Regs *regs = NULL;
   235 
   232 
   236 /* configuration, allows nested code to access above variables */
   233 /* configuration, allows nested code to access above variables */
   237 #include "config.h"
   234 #include "config.h"
   238 
   235 
   239 /* implementation */
   236 /* functions*/
   240 static void
   237 static void
   241 applyrules(Client *c) {
   238 applyrules(Client *c) {
   242 	static char buf[512];
   239 	static char buf[512];
   243 	unsigned int i, j;
   240 	unsigned int i, j;
   244 	regmatch_t tmp;
   241 	regmatch_t tmp;
   336 	}
   333 	}
   337 	else if((c = getclient(ev->window))) {
   334 	else if((c = getclient(ev->window))) {
   338 		focus(c);
   335 		focus(c);
   339 		if(CLEANMASK(ev->state) != MODKEY)
   336 		if(CLEANMASK(ev->state) != MODKEY)
   340 			return;
   337 			return;
   341 		if(ev->button == Button1 && (isfloating() || c->isfloating)) {
   338 		if(ev->button == Button1 && (isarrange(floating) || c->isfloating)) {
   342 			restack();
   339 			restack();
   343 			movemouse(c);
   340 			movemouse(c);
   344 		}
   341 		}
   345 		else if(ev->button == Button2)
   342 		else if(ev->button == Button2)
   346 			zoom(NULL);
   343 			zoom(NULL);
   347 		else if(ev->button == Button3
   344 		else if(ev->button == Button3
   348 		&& (isfloating() || c->isfloating) && !c->isfixed)
   345 		&& (isarrange(floating) || c->isfloating) && !c->isfixed)
   349 		{
   346 		{
   350 			restack();
   347 			restack();
   351 			resizemouse(c);
   348 			resizemouse(c);
   352 		}
   349 		}
   353 	}
   350 	}
       
   351 }
       
   352 
       
   353 static void
       
   354 checkotherwm(void) {
       
   355 	otherwm = False;
       
   356 	XSetErrorHandler(xerrorstart);
       
   357 
       
   358 	/* this causes an error if some other window manager is running */
       
   359 	XSelectInput(dpy, root, SubstructureRedirectMask);
       
   360 	XSync(dpy, False);
       
   361 	if(otherwm)
       
   362 		eprint("dwm: another window manager is already running\n");
       
   363 	XSync(dpy, False);
       
   364 	XSetErrorHandler(NULL);
       
   365 	xerrorxlib = XSetErrorHandler(xerror);
       
   366 	XSync(dpy, False);
   354 }
   367 }
   355 
   368 
   356 static void
   369 static void
   357 cleanup(void) {
   370 cleanup(void) {
   358 	close(STDIN_FILENO);
   371 	close(STDIN_FILENO);
   444 
   457 
   445 	if((c = getclient(ev->window))) {
   458 	if((c = getclient(ev->window))) {
   446 		c->ismax = False;
   459 		c->ismax = False;
   447 		if(ev->value_mask & CWBorderWidth)
   460 		if(ev->value_mask & CWBorderWidth)
   448 			c->border = ev->border_width;
   461 			c->border = ev->border_width;
   449 		if(c->isfixed || c->isfloating || isfloating()) {
   462 		if(c->isfixed || c->isfloating || isarrange(floating)) {
   450 			if(ev->value_mask & CWX)
   463 			if(ev->value_mask & CWX)
   451 				c->x = ev->x;
   464 				c->x = ev->x;
   452 			if(ev->value_mask & CWY)
   465 			if(ev->value_mask & CWY)
   453 				c->y = ev->y;
   466 				c->y = ev->y;
   454 			if(ev->value_mask & CWWidth)
   467 			if(ev->value_mask & CWWidth)
   726 
   739 
   727 	for(c = clients; c && c->win != w; c = c->next);
   740 	for(c = clients; c && c->win != w; c = c->next);
   728 	return c;
   741 	return c;
   729 }
   742 }
   730 
   743 
       
   744 static unsigned long
       
   745 getcolor(const char *colstr) {
       
   746 	Colormap cmap = DefaultColormap(dpy, screen);
       
   747 	XColor color;
       
   748 
       
   749 	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
       
   750 		eprint("error, cannot allocate color '%s'\n", colstr);
       
   751 	return color.pixel;
       
   752 }
       
   753 
   731 static long
   754 static long
   732 getstate(Window w) {
   755 getstate(Window w) {
   733 	int format, status;
   756 	int format, status;
   734 	long result = -1;
   757 	long result = -1;
   735 	unsigned char *p = NULL;
   758 	unsigned char *p = NULL;
   819 			return i;
   842 			return i;
   820 	return 0;
   843 	return 0;
   821 }
   844 }
   822 
   845 
   823 static void
   846 static void
   824 initbar(void) {
       
   825 	XSetWindowAttributes wa;
       
   826 
       
   827 	wa.override_redirect = 1;
       
   828 	wa.background_pixmap = ParentRelative;
       
   829 	wa.event_mask = ButtonPressMask | ExposureMask;
       
   830 	barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0,
       
   831 			DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
       
   832 			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
       
   833 	XDefineCursor(dpy, barwin, cursor[CurNormal]);
       
   834 	updatebarpos();
       
   835 	XMapRaised(dpy, barwin);
       
   836 	strcpy(stext, "dwm-"VERSION);
       
   837 	dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
       
   838 	dc.gc = XCreateGC(dpy, root, 0, 0);
       
   839 	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
       
   840 	if(!dc.font.set)
       
   841 		XSetFont(dpy, dc.gc, dc.font.xfont->fid);
       
   842 }
       
   843 
       
   844 static unsigned long
       
   845 initcolor(const char *colstr) {
       
   846 	Colormap cmap = DefaultColormap(dpy, screen);
       
   847 	XColor color;
       
   848 
       
   849 	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
       
   850 		eprint("error, cannot allocate color '%s'\n", colstr);
       
   851 	return color.pixel;
       
   852 }
       
   853 
       
   854 static void
       
   855 initfont(const char *fontstr) {
   847 initfont(const char *fontstr) {
   856 	char *def, **missing;
   848 	char *def, **missing;
   857 	int i, n;
   849 	int i, n;
   858 
   850 
   859 	missing = NULL;
   851 	missing = NULL;
   891 		dc.font.descent = dc.font.xfont->descent;
   883 		dc.font.descent = dc.font.xfont->descent;
   892 	}
   884 	}
   893 	dc.font.height = dc.font.ascent + dc.font.descent;
   885 	dc.font.height = dc.font.ascent + dc.font.descent;
   894 }
   886 }
   895 
   887 
   896 static void
       
   897 initlayouts(void) {
       
   898 	unsigned int i, w;
       
   899 
       
   900 	nlayouts = sizeof layouts / sizeof layouts[0];
       
   901 	for(blw = i = 0; i < nlayouts; i++) {
       
   902 		w = textw(layouts[i].symbol);
       
   903 		if(w > blw)
       
   904 			blw = w;
       
   905 	}
       
   906 }
       
   907 
       
   908 static void
       
   909 initstyle(void) {
       
   910 	dc.norm[ColBorder] = initcolor(NORMBORDERCOLOR);
       
   911 	dc.norm[ColBG] = initcolor(NORMBGCOLOR);
       
   912 	dc.norm[ColFG] = initcolor(NORMFGCOLOR);
       
   913 	dc.sel[ColBorder] = initcolor(SELBORDERCOLOR);
       
   914 	dc.sel[ColBG] = initcolor(SELBGCOLOR);
       
   915 	dc.sel[ColFG] = initcolor(SELFGCOLOR);
       
   916 	initfont(FONT);
       
   917 	dc.h = bh = dc.font.height + 2;
       
   918 }
       
   919 
       
   920 static Bool
   888 static Bool
   921 isarrange(void (*func)())
   889 isarrange(void (*func)())
   922 {
   890 {
   923 	return func == layouts[ltidx].arrange;
   891 	return func == layouts[ltidx].arrange;
   924 }
       
   925 
       
   926 static Bool
       
   927 isfloating(void) {
       
   928 	return layouts[ltidx].arrange == floating;
       
   929 }
   892 }
   930 
   893 
   931 static Bool
   894 static Bool
   932 isoccupied(unsigned int t) {
   895 isoccupied(unsigned int t) {
   933 	Client *c;
   896 	Client *c;
  1298 	XWindowChanges wc;
  1261 	XWindowChanges wc;
  1299 
  1262 
  1300 	drawbar();
  1263 	drawbar();
  1301 	if(!sel)
  1264 	if(!sel)
  1302 		return;
  1265 		return;
  1303 	if(sel->isfloating || isfloating())
  1266 	if(sel->isfloating || isarrange(floating))
  1304 		XRaiseWindow(dpy, sel->win);
  1267 		XRaiseWindow(dpy, sel->win);
  1305 	if(!isfloating()) {
  1268 	if(!isarrange(floating)) {
  1306 		wc.stack_mode = Below;
  1269 		wc.stack_mode = Below;
  1307 		wc.sibling = barwin;
  1270 		wc.sibling = barwin;
  1308 		if(!sel->isfloating) {
  1271 		if(!sel->isfloating) {
  1309 			XConfigureWindow(dpy, sel->win, CWSibling | CWStackMode, &wc);
  1272 			XConfigureWindow(dpy, sel->win, CWSibling | CWStackMode, &wc);
  1310 			wc.sibling = sel->win;
  1273 			wc.sibling = sel->win;
  1319 	XSync(dpy, False);
  1282 	XSync(dpy, False);
  1320 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  1283 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  1321 }
  1284 }
  1322 
  1285 
  1323 static void
  1286 static void
  1324 scan(void) {
  1287 run(void) {
  1325 	unsigned int i, num;
       
  1326 	Window *wins, d1, d2;
       
  1327 	XWindowAttributes wa;
       
  1328 
       
  1329 	wins = NULL;
       
  1330 	if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
       
  1331 		for(i = 0; i < num; i++) {
       
  1332 			if(!XGetWindowAttributes(dpy, wins[i], &wa)
       
  1333 			|| wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
       
  1334 				continue;
       
  1335 			if(wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
       
  1336 				manage(wins[i], &wa);
       
  1337 		}
       
  1338 		for(i = 0; i < num; i++) { /* now the transients */
       
  1339 			if(!XGetWindowAttributes(dpy, wins[i], &wa))
       
  1340 				continue;
       
  1341 			if(XGetTransientForHint(dpy, wins[i], &d1)
       
  1342 			&& (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
       
  1343 				manage(wins[i], &wa);
       
  1344 		}
       
  1345 	}
       
  1346 	if(wins)
       
  1347 		XFree(wins);
       
  1348 }
       
  1349 
       
  1350 static void
       
  1351 setclientstate(Client *c, long state) {
       
  1352 	long data[] = {state, None};
       
  1353 
       
  1354 	XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
       
  1355 			PropModeReplace, (unsigned char *)data, 2);
       
  1356 }
       
  1357 
       
  1358 static void
       
  1359 setlayout(const char *arg) {
       
  1360 	unsigned int i;
       
  1361 
       
  1362 	if(!arg) {
       
  1363 		if(++ltidx == nlayouts)
       
  1364 			ltidx = 0;;
       
  1365 	}
       
  1366 	else {
       
  1367 		for(i = 0; i < nlayouts; i++)
       
  1368 			if(!strcmp(arg, layouts[i].symbol))
       
  1369 				break;
       
  1370 		if(i == nlayouts)
       
  1371 			return;
       
  1372 		ltidx = i;
       
  1373 	}
       
  1374 	if(sel)
       
  1375 		arrange();
       
  1376 	else
       
  1377 		drawbar();
       
  1378 }
       
  1379 
       
  1380 static void
       
  1381 setmwfact(const char *arg) {
       
  1382 	double delta;
       
  1383 
       
  1384 	if(!isarrange(tile))
       
  1385 		return;
       
  1386 	/* arg handling, manipulate mwfact */
       
  1387 	if(arg == NULL)
       
  1388 		mwfact = MWFACT;
       
  1389 	else if(1 == sscanf(arg, "%lf", &delta)) {
       
  1390 		if(arg[0] != '+' && arg[0] != '-')
       
  1391 			mwfact = delta;
       
  1392 		else
       
  1393 			mwfact += delta;
       
  1394 		if(mwfact < 0.1)
       
  1395 			mwfact = 0.1;
       
  1396 		else if(mwfact > 0.9)
       
  1397 			mwfact = 0.9;
       
  1398 	}
       
  1399 	arrange();
       
  1400 }
       
  1401 
       
  1402 static void
       
  1403 setup(void) {
       
  1404 	int i, j;
       
  1405 	unsigned int mask;
       
  1406 	Window w;
       
  1407 	XModifierKeymap *modmap;
       
  1408 	XSetWindowAttributes wa;
       
  1409 
       
  1410 	/* init atoms */
       
  1411 	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
       
  1412 	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
       
  1413 	wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False);
       
  1414 	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
       
  1415 	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
       
  1416 	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
       
  1417 	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
       
  1418 			PropModeReplace, (unsigned char *) netatom, NetLast);
       
  1419 	/* init cursors */
       
  1420 	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
       
  1421 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
       
  1422 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
       
  1423 	/* init modifier map */
       
  1424 	modmap = XGetModifierMapping(dpy);
       
  1425 	for (i = 0; i < 8; i++)
       
  1426 		for (j = 0; j < modmap->max_keypermod; j++) {
       
  1427 			if(modmap->modifiermap[i * modmap->max_keypermod + j]
       
  1428 					== XKeysymToKeycode(dpy, XK_Num_Lock))
       
  1429 				numlockmask = (1 << i);
       
  1430 		}
       
  1431 	XFreeModifiermap(modmap);
       
  1432 	/* select for events */
       
  1433 	wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
       
  1434 		| EnterWindowMask | LeaveWindowMask | StructureNotifyMask;
       
  1435 	wa.cursor = cursor[CurNormal];
       
  1436 	XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
       
  1437 	XSelectInput(dpy, root, wa.event_mask);
       
  1438 	keypress(NULL); /* grabkeys */
       
  1439 	compileregs();
       
  1440 	for(ntags = 0; tags[ntags]; ntags++);
       
  1441 	seltags = emallocz(sizeof(Bool) * ntags);
       
  1442 	seltags[0] = True;
       
  1443 	/* geometry */
       
  1444 	sx = sy = 0;
       
  1445 	sw = DisplayWidth(dpy, screen);
       
  1446 	sh = DisplayHeight(dpy, screen);
       
  1447 	initstyle();
       
  1448 	initlayouts();
       
  1449 	initbar();
       
  1450 	/* multihead support */
       
  1451 	selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
       
  1452 }
       
  1453 
       
  1454 static void
       
  1455 spawn(const char *arg) {
       
  1456 	static char *shell = NULL;
       
  1457 
       
  1458 	if(!shell && !(shell = getenv("SHELL")))
       
  1459 		shell = "/bin/sh";
       
  1460 	if(!arg)
       
  1461 		return;
       
  1462 	/* The double-fork construct avoids zombie processes and keeps the code
       
  1463 	 * clean from stupid signal handlers. */
       
  1464 	if(fork() == 0) {
       
  1465 		if(fork() == 0) {
       
  1466 			if(dpy)
       
  1467 				close(ConnectionNumber(dpy));
       
  1468 			setsid();
       
  1469 			execl(shell, shell, "-c", arg, (char *)NULL);
       
  1470 			fprintf(stderr, "dwm: execl '%s -c %s'", shell, arg);
       
  1471 			perror(" failed");
       
  1472 		}
       
  1473 		exit(0);
       
  1474 	}
       
  1475 	wait(0);
       
  1476 }
       
  1477 
       
  1478 static void
       
  1479 tag(const char *arg) {
       
  1480 	unsigned int i;
       
  1481 
       
  1482 	if(!sel)
       
  1483 		return;
       
  1484 	for(i = 0; i < ntags; i++)
       
  1485 		sel->tags[i] = arg == NULL;
       
  1486 	i = idxoftag(arg);
       
  1487 	if(i >= 0 && i < ntags)
       
  1488 		sel->tags[i] = True;
       
  1489 	arrange();
       
  1490 }
       
  1491 
       
  1492 static unsigned int
       
  1493 textnw(const char *text, unsigned int len) {
       
  1494 	XRectangle r;
       
  1495 
       
  1496 	if(dc.font.set) {
       
  1497 		XmbTextExtents(dc.font.set, text, len, NULL, &r);
       
  1498 		return r.width;
       
  1499 	}
       
  1500 	return XTextWidth(dc.font.xfont, text, len);
       
  1501 }
       
  1502 
       
  1503 static unsigned int
       
  1504 textw(const char *text) {
       
  1505 	return textnw(text, strlen(text)) + dc.font.height;
       
  1506 }
       
  1507 
       
  1508 static void
       
  1509 tile(void) {
       
  1510 	unsigned int i, n, nx, ny, nw, nh, mw, th;
       
  1511 	Client *c;
       
  1512 
       
  1513 	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
       
  1514 		n++;
       
  1515 
       
  1516 	/* window geoms */
       
  1517 	mw = (n == 1) ? waw : mwfact * waw;
       
  1518 	th = (n > 1) ? wah / (n - 1) : 0;
       
  1519 	if(n > 1 && th < bh)
       
  1520 		th = wah;
       
  1521 
       
  1522 	nx = wax;
       
  1523 	ny = way;
       
  1524 	for(i = 0, c = nexttiled(clients); c; c = nexttiled(c->next), i++) {
       
  1525 		c->ismax = False;
       
  1526 		if(i == 0) { /* master */
       
  1527 			nw = mw - 2 * c->border;
       
  1528 			nh = wah - 2 * c->border;
       
  1529 		}
       
  1530 		else {  /* tile window */
       
  1531 			if(i == 1) {
       
  1532 				ny = way;
       
  1533 				nx += mw;
       
  1534 			}
       
  1535 			nw = waw - mw - 2 * c->border;
       
  1536 			if(i + 1 == n) /* remainder */
       
  1537 				nh = (way + wah) - ny - 2 * c->border;
       
  1538 			else
       
  1539 				nh = th - 2 * c->border;
       
  1540 		}
       
  1541 		resize(c, nx, ny, nw, nh, RESIZEHINTS);
       
  1542 		if(n > 1 && th != wah)
       
  1543 			ny += nh + 2 * c->border;
       
  1544 	}
       
  1545 }
       
  1546 
       
  1547 static void
       
  1548 togglebar(const char *arg) {
       
  1549 	if(bpos == BarOff)
       
  1550 		bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
       
  1551 	else
       
  1552 		bpos = BarOff;
       
  1553 	updatebarpos();
       
  1554 	arrange();
       
  1555 }
       
  1556 
       
  1557 static void
       
  1558 togglefloating(const char *arg) {
       
  1559 	if(!sel)
       
  1560 		return;
       
  1561 	sel->isfloating = !sel->isfloating;
       
  1562 	if(sel->isfloating)
       
  1563 		resize(sel, sel->x, sel->y, sel->w, sel->h, True);
       
  1564 	arrange();
       
  1565 }
       
  1566 
       
  1567 static void
       
  1568 togglemax(const char *arg) {
       
  1569 	XEvent ev;
       
  1570 
       
  1571 	if(!sel || (!isfloating() && !sel->isfloating) || sel->isfixed)
       
  1572 		return;
       
  1573 	if((sel->ismax = !sel->ismax)) {
       
  1574 		sel->rx = sel->x;
       
  1575 		sel->ry = sel->y;
       
  1576 		sel->rw = sel->w;
       
  1577 		sel->rh = sel->h;
       
  1578 		resize(sel, wax, way, waw - 2 * sel->border, wah - 2 * sel->border, True);
       
  1579 	}
       
  1580 	else
       
  1581 		resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True);
       
  1582 	drawbar();
       
  1583 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
       
  1584 }
       
  1585 
       
  1586 static void
       
  1587 toggletag(const char *arg) {
       
  1588 	unsigned int i, j;
       
  1589 
       
  1590 	if(!sel)
       
  1591 		return;
       
  1592 	i = idxoftag(arg);
       
  1593 	sel->tags[i] = !sel->tags[i];
       
  1594 	for(j = 0; j < ntags && !sel->tags[j]; j++);
       
  1595 	if(j == ntags)
       
  1596 		sel->tags[i] = True;
       
  1597 	arrange();
       
  1598 }
       
  1599 
       
  1600 static void
       
  1601 toggleview(const char *arg) {
       
  1602 	unsigned int i, j;
       
  1603 
       
  1604 	i = idxoftag(arg);
       
  1605 	seltags[i] = !seltags[i];
       
  1606 	for(j = 0; j < ntags && !seltags[j]; j++);
       
  1607 	if(j == ntags)
       
  1608 		seltags[i] = True; /* cannot toggle last view */
       
  1609 	arrange();
       
  1610 }
       
  1611 
       
  1612 static void
       
  1613 unban(Client *c) {
       
  1614 	if(!c->isbanned)
       
  1615 		return;
       
  1616 	XMoveWindow(dpy, c->win, c->x, c->y);
       
  1617 	c->isbanned = False;
       
  1618 }
       
  1619 
       
  1620 static void
       
  1621 unmanage(Client *c) {
       
  1622 	XWindowChanges wc;
       
  1623 
       
  1624 	wc.border_width = c->oldborder;
       
  1625 	/* The server grab construct avoids race conditions. */
       
  1626 	XGrabServer(dpy);
       
  1627 	XSetErrorHandler(xerrordummy);
       
  1628 	XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
       
  1629 	detach(c);
       
  1630 	detachstack(c);
       
  1631 	if(sel == c)
       
  1632 		focus(NULL);
       
  1633 	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
       
  1634 	setclientstate(c, WithdrawnState);
       
  1635 	free(c->tags);
       
  1636 	free(c);
       
  1637 	XSync(dpy, False);
       
  1638 	XSetErrorHandler(xerror);
       
  1639 	XUngrabServer(dpy);
       
  1640 	arrange();
       
  1641 }
       
  1642 
       
  1643 static void
       
  1644 unmapnotify(XEvent *e) {
       
  1645 	Client *c;
       
  1646 	XUnmapEvent *ev = &e->xunmap;
       
  1647 
       
  1648 	if((c = getclient(ev->window)))
       
  1649 		unmanage(c);
       
  1650 }
       
  1651 
       
  1652 static void
       
  1653 updatebarpos(void) {
       
  1654 	XEvent ev;
       
  1655 
       
  1656 	wax = sx;
       
  1657 	way = sy;
       
  1658 	wah = sh;
       
  1659 	waw = sw;
       
  1660 	switch(bpos) {
       
  1661 	default:
       
  1662 		wah -= bh;
       
  1663 		way += bh;
       
  1664 		XMoveWindow(dpy, barwin, sx, sy);
       
  1665 		break;
       
  1666 	case BarBot:
       
  1667 		wah -= bh;
       
  1668 		XMoveWindow(dpy, barwin, sx, sy + wah);
       
  1669 		break;
       
  1670 	case BarOff:
       
  1671 		XMoveWindow(dpy, barwin, sx, sy - bh);
       
  1672 		break;
       
  1673 	}
       
  1674 	XSync(dpy, False);
       
  1675 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
       
  1676 }
       
  1677 
       
  1678 static void
       
  1679 updatesizehints(Client *c) {
       
  1680 	long msize;
       
  1681 	XSizeHints size;
       
  1682 
       
  1683 	if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
       
  1684 		size.flags = PSize;
       
  1685 	c->flags = size.flags;
       
  1686 	if(c->flags & PBaseSize) {
       
  1687 		c->basew = size.base_width;
       
  1688 		c->baseh = size.base_height;
       
  1689 	}
       
  1690 	else if(c->flags & PMinSize) {
       
  1691 		c->basew = size.min_width;
       
  1692 		c->baseh = size.min_height;
       
  1693 	}
       
  1694 	else
       
  1695 		c->basew = c->baseh = 0;
       
  1696 	if(c->flags & PResizeInc) {
       
  1697 		c->incw = size.width_inc;
       
  1698 		c->inch = size.height_inc;
       
  1699 	}
       
  1700 	else
       
  1701 		c->incw = c->inch = 0;
       
  1702 	if(c->flags & PMaxSize) {
       
  1703 		c->maxw = size.max_width;
       
  1704 		c->maxh = size.max_height;
       
  1705 	}
       
  1706 	else
       
  1707 		c->maxw = c->maxh = 0;
       
  1708 	if(c->flags & PMinSize) {
       
  1709 		c->minw = size.min_width;
       
  1710 		c->minh = size.min_height;
       
  1711 	}
       
  1712 	else if(c->flags & PBaseSize) {
       
  1713 		c->minw = size.base_width;
       
  1714 		c->minh = size.base_height;
       
  1715 	}
       
  1716 	else
       
  1717 		c->minw = c->minh = 0;
       
  1718 	if(c->flags & PAspect) {
       
  1719 		c->minax = size.min_aspect.x;
       
  1720 		c->maxax = size.max_aspect.x;
       
  1721 		c->minay = size.min_aspect.y;
       
  1722 		c->maxay = size.max_aspect.y;
       
  1723 	}
       
  1724 	else
       
  1725 		c->minax = c->maxax = c->minay = c->maxay = 0;
       
  1726 	c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
       
  1727 			&& c->maxw == c->minw && c->maxh == c->minh);
       
  1728 }
       
  1729 
       
  1730 static void
       
  1731 updatetitle(Client *c) {
       
  1732 	if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
       
  1733 		gettextprop(c->win, wmatom[WMName], c->name, sizeof c->name);
       
  1734 }
       
  1735 
       
  1736 /* There's no way to check accesses to destroyed windows, thus those cases are
       
  1737  * ignored (especially on UnmapNotify's).  Other types of errors call Xlibs
       
  1738  * default error handler, which may call exit.  */
       
  1739 static int
       
  1740 xerror(Display *dpy, XErrorEvent *ee) {
       
  1741 	if(ee->error_code == BadWindow
       
  1742 	|| (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
       
  1743 	|| (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
       
  1744 	|| (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
       
  1745 	|| (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
       
  1746 	|| (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
       
  1747 	|| (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
       
  1748 	|| (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
       
  1749 		return 0;
       
  1750 	fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
       
  1751 		ee->request_code, ee->error_code);
       
  1752 	return xerrorxlib(dpy, ee); /* may call exit */
       
  1753 }
       
  1754 
       
  1755 static int
       
  1756 xerrordummy(Display *dsply, XErrorEvent *ee) {
       
  1757 	return 0;
       
  1758 }
       
  1759 
       
  1760 /* Startup Error handler to check if another window manager
       
  1761  * is already running. */
       
  1762 static int
       
  1763 xerrorstart(Display *dsply, XErrorEvent *ee) {
       
  1764 	otherwm = True;
       
  1765 	return -1;
       
  1766 }
       
  1767 
       
  1768 static void
       
  1769 view(const char *arg) {
       
  1770 	unsigned int i;
       
  1771 
       
  1772 	for(i = 0; i < ntags; i++)
       
  1773 		seltags[i] = arg == NULL;
       
  1774 	i = idxoftag(arg);
       
  1775 	if(i >= 0 && i < ntags)
       
  1776 		seltags[i] = True;
       
  1777 	arrange();
       
  1778 }
       
  1779 
       
  1780 static void
       
  1781 zoom(const char *arg) {
       
  1782 	Client *c;
       
  1783 
       
  1784 	if(!sel || !isarrange(tile) || sel->isfloating)
       
  1785 		return;
       
  1786 	if((c = sel) == nexttiled(clients))
       
  1787 		if(!(c = nexttiled(c->next)))
       
  1788 			return;
       
  1789 	detach(c);
       
  1790 	attach(c);
       
  1791 	focus(c);
       
  1792 	arrange();
       
  1793 }
       
  1794 
       
  1795 int
       
  1796 main(int argc, char *argv[]) {
       
  1797 	char *p;
  1288 	char *p;
  1798 	int r, xfd;
  1289 	int r, xfd;
  1799 	fd_set rd;
  1290 	fd_set rd;
  1800 	XEvent ev;
  1291 	XEvent ev;
  1801 
  1292 
  1802 	if(argc == 2 && !strcmp("-v", argv[1]))
       
  1803 		eprint("dwm-"VERSION", © 2006-2007 A. R. Garbe, S. van Dijk, J. Salmi, P. Hruby, S. Nagy\n");
       
  1804 	else if(argc != 1)
       
  1805 		eprint("usage: dwm [-v]\n");
       
  1806 
       
  1807 	/* macros from config.h can be used at function level only */
       
  1808 	mwfact = MWFACT;
       
  1809 	bpos = BARPOS;
       
  1810 
       
  1811 	setlocale(LC_CTYPE, "");
       
  1812 	if(!(dpy = XOpenDisplay(0)))
       
  1813 		eprint("dwm: cannot open display\n");
       
  1814 	xfd = ConnectionNumber(dpy);
       
  1815 	screen = DefaultScreen(dpy);
       
  1816 	root = RootWindow(dpy, screen);
       
  1817 	otherwm = False;
       
  1818 	XSetErrorHandler(xerrorstart);
       
  1819 	/* this causes an error if some other window manager is running */
       
  1820 	XSelectInput(dpy, root, SubstructureRedirectMask);
       
  1821 	XSync(dpy, False);
       
  1822 	if(otherwm)
       
  1823 		eprint("dwm: another window manager is already running\n");
       
  1824 
       
  1825 	XSync(dpy, False);
       
  1826 	XSetErrorHandler(NULL);
       
  1827 	xerrorxlib = XSetErrorHandler(xerror);
       
  1828 	XSync(dpy, False);
       
  1829 	setup();
       
  1830 	drawbar();
       
  1831 	scan();
       
  1832 
       
  1833 	/* main event loop, also reads status text from stdin */
  1293 	/* main event loop, also reads status text from stdin */
  1834 	XSync(dpy, False);
  1294 	XSync(dpy, False);
       
  1295 	xfd = ConnectionNumber(dpy);
  1835 	readin = True;
  1296 	readin = True;
  1836 	while(running) {
  1297 	while(running) {
  1837 		FD_ZERO(&rd);
  1298 		FD_ZERO(&rd);
  1838 		if(readin)
  1299 		if(readin)
  1839 			FD_SET(STDIN_FILENO, &rd);
  1300 			FD_SET(STDIN_FILENO, &rd);
  1866 			XNextEvent(dpy, &ev);
  1327 			XNextEvent(dpy, &ev);
  1867 			if(handler[ev.type])
  1328 			if(handler[ev.type])
  1868 				(handler[ev.type])(&ev); /* call handler */
  1329 				(handler[ev.type])(&ev); /* call handler */
  1869 		}
  1330 		}
  1870 	}
  1331 	}
       
  1332 }
       
  1333 
       
  1334 static void
       
  1335 scan(void) {
       
  1336 	unsigned int i, num;
       
  1337 	Window *wins, d1, d2;
       
  1338 	XWindowAttributes wa;
       
  1339 
       
  1340 	wins = NULL;
       
  1341 	if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
       
  1342 		for(i = 0; i < num; i++) {
       
  1343 			if(!XGetWindowAttributes(dpy, wins[i], &wa)
       
  1344 			|| wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
       
  1345 				continue;
       
  1346 			if(wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
       
  1347 				manage(wins[i], &wa);
       
  1348 		}
       
  1349 		for(i = 0; i < num; i++) { /* now the transients */
       
  1350 			if(!XGetWindowAttributes(dpy, wins[i], &wa))
       
  1351 				continue;
       
  1352 			if(XGetTransientForHint(dpy, wins[i], &d1)
       
  1353 			&& (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
       
  1354 				manage(wins[i], &wa);
       
  1355 		}
       
  1356 	}
       
  1357 	if(wins)
       
  1358 		XFree(wins);
       
  1359 }
       
  1360 
       
  1361 static void
       
  1362 setclientstate(Client *c, long state) {
       
  1363 	long data[] = {state, None};
       
  1364 
       
  1365 	XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
       
  1366 			PropModeReplace, (unsigned char *)data, 2);
       
  1367 }
       
  1368 
       
  1369 static void
       
  1370 setlayout(const char *arg) {
       
  1371 	unsigned int i;
       
  1372 
       
  1373 	if(!arg) {
       
  1374 		if(++ltidx == nlayouts)
       
  1375 			ltidx = 0;;
       
  1376 	}
       
  1377 	else {
       
  1378 		for(i = 0; i < nlayouts; i++)
       
  1379 			if(!strcmp(arg, layouts[i].symbol))
       
  1380 				break;
       
  1381 		if(i == nlayouts)
       
  1382 			return;
       
  1383 		ltidx = i;
       
  1384 	}
       
  1385 	if(sel)
       
  1386 		arrange();
       
  1387 	else
       
  1388 		drawbar();
       
  1389 }
       
  1390 
       
  1391 static void
       
  1392 setmwfact(const char *arg) {
       
  1393 	double delta;
       
  1394 
       
  1395 	if(!isarrange(tile))
       
  1396 		return;
       
  1397 	/* arg handling, manipulate mwfact */
       
  1398 	if(arg == NULL)
       
  1399 		mwfact = MWFACT;
       
  1400 	else if(1 == sscanf(arg, "%lf", &delta)) {
       
  1401 		if(arg[0] != '+' && arg[0] != '-')
       
  1402 			mwfact = delta;
       
  1403 		else
       
  1404 			mwfact += delta;
       
  1405 		if(mwfact < 0.1)
       
  1406 			mwfact = 0.1;
       
  1407 		else if(mwfact > 0.9)
       
  1408 			mwfact = 0.9;
       
  1409 	}
       
  1410 	arrange();
       
  1411 }
       
  1412 
       
  1413 static void
       
  1414 setup(void) {
       
  1415 	unsigned int i, j, mask;
       
  1416 	Window w;
       
  1417 	XModifierKeymap *modmap;
       
  1418 	XSetWindowAttributes wa;
       
  1419 
       
  1420 	/* init atoms */
       
  1421 	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
       
  1422 	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
       
  1423 	wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False);
       
  1424 	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
       
  1425 	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
       
  1426 	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
       
  1427 	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
       
  1428 			PropModeReplace, (unsigned char *) netatom, NetLast);
       
  1429 
       
  1430 	/* init cursors */
       
  1431 	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
       
  1432 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
       
  1433 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
       
  1434 
       
  1435 	/* init geometry */
       
  1436 	sx = sy = 0;
       
  1437 	sw = DisplayWidth(dpy, screen);
       
  1438 	sh = DisplayHeight(dpy, screen);
       
  1439 
       
  1440 	/* init modifier map */
       
  1441 	modmap = XGetModifierMapping(dpy);
       
  1442 	for(i = 0; i < 8; i++)
       
  1443 		for(j = 0; j < modmap->max_keypermod; j++) {
       
  1444 			if(modmap->modifiermap[i * modmap->max_keypermod + j]
       
  1445 			== XKeysymToKeycode(dpy, XK_Num_Lock))
       
  1446 				numlockmask = (1 << i);
       
  1447 		}
       
  1448 	XFreeModifiermap(modmap);
       
  1449 
       
  1450 	/* select for events */
       
  1451 	wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
       
  1452 		| EnterWindowMask | LeaveWindowMask | StructureNotifyMask;
       
  1453 	wa.cursor = cursor[CurNormal];
       
  1454 	XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
       
  1455 	XSelectInput(dpy, root, wa.event_mask);
       
  1456 
       
  1457 	/* grab keys */
       
  1458 	keypress(NULL);
       
  1459 
       
  1460 	/* init tags */
       
  1461 	compileregs();
       
  1462 	for(ntags = 0; tags[ntags]; ntags++);
       
  1463 	seltags = emallocz(sizeof(Bool) * ntags);
       
  1464 	seltags[0] = True;
       
  1465 
       
  1466 	/* init appearance */
       
  1467 	dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR);
       
  1468 	dc.norm[ColBG] = getcolor(NORMBGCOLOR);
       
  1469 	dc.norm[ColFG] = getcolor(NORMFGCOLOR);
       
  1470 	dc.sel[ColBorder] = getcolor(SELBORDERCOLOR);
       
  1471 	dc.sel[ColBG] = getcolor(SELBGCOLOR);
       
  1472 	dc.sel[ColFG] = getcolor(SELFGCOLOR);
       
  1473 	initfont(FONT);
       
  1474 	dc.h = bh = dc.font.height + 2;
       
  1475 
       
  1476 	/* init layouts */
       
  1477 	mwfact = MWFACT;
       
  1478 	nlayouts = sizeof layouts / sizeof layouts[0];
       
  1479 	for(blw = i = 0; i < nlayouts; i++) {
       
  1480 		j = textw(layouts[i].symbol);
       
  1481 		if(j > blw)
       
  1482 			blw = j;
       
  1483 	}
       
  1484 
       
  1485 	/* init bar */
       
  1486 	bpos = BARPOS;
       
  1487 	wa.override_redirect = 1;
       
  1488 	wa.background_pixmap = ParentRelative;
       
  1489 	wa.event_mask = ButtonPressMask | ExposureMask;
       
  1490 	barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0,
       
  1491 			DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
       
  1492 			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
       
  1493 	XDefineCursor(dpy, barwin, cursor[CurNormal]);
       
  1494 	updatebarpos();
       
  1495 	XMapRaised(dpy, barwin);
       
  1496 	strcpy(stext, "dwm-"VERSION);
       
  1497 	dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
       
  1498 	dc.gc = XCreateGC(dpy, root, 0, 0);
       
  1499 	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
       
  1500 	if(!dc.font.set)
       
  1501 		XSetFont(dpy, dc.gc, dc.font.xfont->fid);
       
  1502 
       
  1503 	/* multihead support */
       
  1504 	selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
       
  1505 }
       
  1506 
       
  1507 static void
       
  1508 spawn(const char *arg) {
       
  1509 	static char *shell = NULL;
       
  1510 
       
  1511 	if(!shell && !(shell = getenv("SHELL")))
       
  1512 		shell = "/bin/sh";
       
  1513 	if(!arg)
       
  1514 		return;
       
  1515 	/* The double-fork construct avoids zombie processes and keeps the code
       
  1516 	 * clean from stupid signal handlers. */
       
  1517 	if(fork() == 0) {
       
  1518 		if(fork() == 0) {
       
  1519 			if(dpy)
       
  1520 				close(ConnectionNumber(dpy));
       
  1521 			setsid();
       
  1522 			execl(shell, shell, "-c", arg, (char *)NULL);
       
  1523 			fprintf(stderr, "dwm: execl '%s -c %s'", shell, arg);
       
  1524 			perror(" failed");
       
  1525 		}
       
  1526 		exit(0);
       
  1527 	}
       
  1528 	wait(0);
       
  1529 }
       
  1530 
       
  1531 static void
       
  1532 tag(const char *arg) {
       
  1533 	unsigned int i;
       
  1534 
       
  1535 	if(!sel)
       
  1536 		return;
       
  1537 	for(i = 0; i < ntags; i++)
       
  1538 		sel->tags[i] = arg == NULL;
       
  1539 	i = idxoftag(arg);
       
  1540 	if(i >= 0 && i < ntags)
       
  1541 		sel->tags[i] = True;
       
  1542 	arrange();
       
  1543 }
       
  1544 
       
  1545 static unsigned int
       
  1546 textnw(const char *text, unsigned int len) {
       
  1547 	XRectangle r;
       
  1548 
       
  1549 	if(dc.font.set) {
       
  1550 		XmbTextExtents(dc.font.set, text, len, NULL, &r);
       
  1551 		return r.width;
       
  1552 	}
       
  1553 	return XTextWidth(dc.font.xfont, text, len);
       
  1554 }
       
  1555 
       
  1556 static unsigned int
       
  1557 textw(const char *text) {
       
  1558 	return textnw(text, strlen(text)) + dc.font.height;
       
  1559 }
       
  1560 
       
  1561 static void
       
  1562 tile(void) {
       
  1563 	unsigned int i, n, nx, ny, nw, nh, mw, th;
       
  1564 	Client *c;
       
  1565 
       
  1566 	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
       
  1567 		n++;
       
  1568 
       
  1569 	/* window geoms */
       
  1570 	mw = (n == 1) ? waw : mwfact * waw;
       
  1571 	th = (n > 1) ? wah / (n - 1) : 0;
       
  1572 	if(n > 1 && th < bh)
       
  1573 		th = wah;
       
  1574 
       
  1575 	nx = wax;
       
  1576 	ny = way;
       
  1577 	for(i = 0, c = nexttiled(clients); c; c = nexttiled(c->next), i++) {
       
  1578 		c->ismax = False;
       
  1579 		if(i == 0) { /* master */
       
  1580 			nw = mw - 2 * c->border;
       
  1581 			nh = wah - 2 * c->border;
       
  1582 		}
       
  1583 		else {  /* tile window */
       
  1584 			if(i == 1) {
       
  1585 				ny = way;
       
  1586 				nx += mw;
       
  1587 			}
       
  1588 			nw = waw - mw - 2 * c->border;
       
  1589 			if(i + 1 == n) /* remainder */
       
  1590 				nh = (way + wah) - ny - 2 * c->border;
       
  1591 			else
       
  1592 				nh = th - 2 * c->border;
       
  1593 		}
       
  1594 		resize(c, nx, ny, nw, nh, RESIZEHINTS);
       
  1595 		if(n > 1 && th != wah)
       
  1596 			ny += nh + 2 * c->border;
       
  1597 	}
       
  1598 }
       
  1599 
       
  1600 static void
       
  1601 togglebar(const char *arg) {
       
  1602 	if(bpos == BarOff)
       
  1603 		bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
       
  1604 	else
       
  1605 		bpos = BarOff;
       
  1606 	updatebarpos();
       
  1607 	arrange();
       
  1608 }
       
  1609 
       
  1610 static void
       
  1611 togglefloating(const char *arg) {
       
  1612 	if(!sel)
       
  1613 		return;
       
  1614 	sel->isfloating = !sel->isfloating;
       
  1615 	if(sel->isfloating)
       
  1616 		resize(sel, sel->x, sel->y, sel->w, sel->h, True);
       
  1617 	arrange();
       
  1618 }
       
  1619 
       
  1620 static void
       
  1621 togglemax(const char *arg) {
       
  1622 	XEvent ev;
       
  1623 
       
  1624 	if(!sel || (!isarrange(floating) && !sel->isfloating) || sel->isfixed)
       
  1625 		return;
       
  1626 	if((sel->ismax = !sel->ismax)) {
       
  1627 		sel->rx = sel->x;
       
  1628 		sel->ry = sel->y;
       
  1629 		sel->rw = sel->w;
       
  1630 		sel->rh = sel->h;
       
  1631 		resize(sel, wax, way, waw - 2 * sel->border, wah - 2 * sel->border, True);
       
  1632 	}
       
  1633 	else
       
  1634 		resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True);
       
  1635 	drawbar();
       
  1636 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
       
  1637 }
       
  1638 
       
  1639 static void
       
  1640 toggletag(const char *arg) {
       
  1641 	unsigned int i, j;
       
  1642 
       
  1643 	if(!sel)
       
  1644 		return;
       
  1645 	i = idxoftag(arg);
       
  1646 	sel->tags[i] = !sel->tags[i];
       
  1647 	for(j = 0; j < ntags && !sel->tags[j]; j++);
       
  1648 	if(j == ntags)
       
  1649 		sel->tags[i] = True;
       
  1650 	arrange();
       
  1651 }
       
  1652 
       
  1653 static void
       
  1654 toggleview(const char *arg) {
       
  1655 	unsigned int i, j;
       
  1656 
       
  1657 	i = idxoftag(arg);
       
  1658 	seltags[i] = !seltags[i];
       
  1659 	for(j = 0; j < ntags && !seltags[j]; j++);
       
  1660 	if(j == ntags)
       
  1661 		seltags[i] = True; /* cannot toggle last view */
       
  1662 	arrange();
       
  1663 }
       
  1664 
       
  1665 static void
       
  1666 unban(Client *c) {
       
  1667 	if(!c->isbanned)
       
  1668 		return;
       
  1669 	XMoveWindow(dpy, c->win, c->x, c->y);
       
  1670 	c->isbanned = False;
       
  1671 }
       
  1672 
       
  1673 static void
       
  1674 unmanage(Client *c) {
       
  1675 	XWindowChanges wc;
       
  1676 
       
  1677 	wc.border_width = c->oldborder;
       
  1678 	/* The server grab construct avoids race conditions. */
       
  1679 	XGrabServer(dpy);
       
  1680 	XSetErrorHandler(xerrordummy);
       
  1681 	XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
       
  1682 	detach(c);
       
  1683 	detachstack(c);
       
  1684 	if(sel == c)
       
  1685 		focus(NULL);
       
  1686 	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
       
  1687 	setclientstate(c, WithdrawnState);
       
  1688 	free(c->tags);
       
  1689 	free(c);
       
  1690 	XSync(dpy, False);
       
  1691 	XSetErrorHandler(xerror);
       
  1692 	XUngrabServer(dpy);
       
  1693 	arrange();
       
  1694 }
       
  1695 
       
  1696 static void
       
  1697 unmapnotify(XEvent *e) {
       
  1698 	Client *c;
       
  1699 	XUnmapEvent *ev = &e->xunmap;
       
  1700 
       
  1701 	if((c = getclient(ev->window)))
       
  1702 		unmanage(c);
       
  1703 }
       
  1704 
       
  1705 static void
       
  1706 updatebarpos(void) {
       
  1707 	XEvent ev;
       
  1708 
       
  1709 	wax = sx;
       
  1710 	way = sy;
       
  1711 	wah = sh;
       
  1712 	waw = sw;
       
  1713 	switch(bpos) {
       
  1714 	default:
       
  1715 		wah -= bh;
       
  1716 		way += bh;
       
  1717 		XMoveWindow(dpy, barwin, sx, sy);
       
  1718 		break;
       
  1719 	case BarBot:
       
  1720 		wah -= bh;
       
  1721 		XMoveWindow(dpy, barwin, sx, sy + wah);
       
  1722 		break;
       
  1723 	case BarOff:
       
  1724 		XMoveWindow(dpy, barwin, sx, sy - bh);
       
  1725 		break;
       
  1726 	}
       
  1727 	XSync(dpy, False);
       
  1728 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
       
  1729 }
       
  1730 
       
  1731 static void
       
  1732 updatesizehints(Client *c) {
       
  1733 	long msize;
       
  1734 	XSizeHints size;
       
  1735 
       
  1736 	if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
       
  1737 		size.flags = PSize;
       
  1738 	c->flags = size.flags;
       
  1739 	if(c->flags & PBaseSize) {
       
  1740 		c->basew = size.base_width;
       
  1741 		c->baseh = size.base_height;
       
  1742 	}
       
  1743 	else if(c->flags & PMinSize) {
       
  1744 		c->basew = size.min_width;
       
  1745 		c->baseh = size.min_height;
       
  1746 	}
       
  1747 	else
       
  1748 		c->basew = c->baseh = 0;
       
  1749 	if(c->flags & PResizeInc) {
       
  1750 		c->incw = size.width_inc;
       
  1751 		c->inch = size.height_inc;
       
  1752 	}
       
  1753 	else
       
  1754 		c->incw = c->inch = 0;
       
  1755 	if(c->flags & PMaxSize) {
       
  1756 		c->maxw = size.max_width;
       
  1757 		c->maxh = size.max_height;
       
  1758 	}
       
  1759 	else
       
  1760 		c->maxw = c->maxh = 0;
       
  1761 	if(c->flags & PMinSize) {
       
  1762 		c->minw = size.min_width;
       
  1763 		c->minh = size.min_height;
       
  1764 	}
       
  1765 	else if(c->flags & PBaseSize) {
       
  1766 		c->minw = size.base_width;
       
  1767 		c->minh = size.base_height;
       
  1768 	}
       
  1769 	else
       
  1770 		c->minw = c->minh = 0;
       
  1771 	if(c->flags & PAspect) {
       
  1772 		c->minax = size.min_aspect.x;
       
  1773 		c->maxax = size.max_aspect.x;
       
  1774 		c->minay = size.min_aspect.y;
       
  1775 		c->maxay = size.max_aspect.y;
       
  1776 	}
       
  1777 	else
       
  1778 		c->minax = c->maxax = c->minay = c->maxay = 0;
       
  1779 	c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
       
  1780 			&& c->maxw == c->minw && c->maxh == c->minh);
       
  1781 }
       
  1782 
       
  1783 static void
       
  1784 updatetitle(Client *c) {
       
  1785 	if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
       
  1786 		gettextprop(c->win, wmatom[WMName], c->name, sizeof c->name);
       
  1787 }
       
  1788 
       
  1789 /* There's no way to check accesses to destroyed windows, thus those cases are
       
  1790  * ignored (especially on UnmapNotify's).  Other types of errors call Xlibs
       
  1791  * default error handler, which may call exit.  */
       
  1792 static int
       
  1793 xerror(Display *dpy, XErrorEvent *ee) {
       
  1794 	if(ee->error_code == BadWindow
       
  1795 	|| (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
       
  1796 	|| (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
       
  1797 	|| (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
       
  1798 	|| (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
       
  1799 	|| (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
       
  1800 	|| (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
       
  1801 	|| (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
       
  1802 		return 0;
       
  1803 	fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
       
  1804 		ee->request_code, ee->error_code);
       
  1805 	return xerrorxlib(dpy, ee); /* may call exit */
       
  1806 }
       
  1807 
       
  1808 static int
       
  1809 xerrordummy(Display *dsply, XErrorEvent *ee) {
       
  1810 	return 0;
       
  1811 }
       
  1812 
       
  1813 /* Startup Error handler to check if another window manager
       
  1814  * is already running. */
       
  1815 static int
       
  1816 xerrorstart(Display *dsply, XErrorEvent *ee) {
       
  1817 	otherwm = True;
       
  1818 	return -1;
       
  1819 }
       
  1820 
       
  1821 static void
       
  1822 view(const char *arg) {
       
  1823 	unsigned int i;
       
  1824 
       
  1825 	for(i = 0; i < ntags; i++)
       
  1826 		seltags[i] = arg == NULL;
       
  1827 	i = idxoftag(arg);
       
  1828 	if(i >= 0 && i < ntags)
       
  1829 		seltags[i] = True;
       
  1830 	arrange();
       
  1831 }
       
  1832 
       
  1833 static void
       
  1834 zoom(const char *arg) {
       
  1835 	Client *c;
       
  1836 
       
  1837 	if(!sel || !isarrange(tile) || sel->isfloating)
       
  1838 		return;
       
  1839 	if((c = sel) == nexttiled(clients))
       
  1840 		if(!(c = nexttiled(c->next)))
       
  1841 			return;
       
  1842 	detach(c);
       
  1843 	attach(c);
       
  1844 	focus(c);
       
  1845 	arrange();
       
  1846 }
       
  1847 
       
  1848 int
       
  1849 main(int argc, char *argv[]) {
       
  1850 	if(argc == 2 && !strcmp("-v", argv[1]))
       
  1851 		eprint("dwm-"VERSION", © 2006-2007 A. R. Garbe, S. van Dijk, J. Salmi, P. Hruby, S. Nagy\n");
       
  1852 	else if(argc != 1)
       
  1853 		eprint("usage: dwm [-v]\n");
       
  1854 
       
  1855 	setlocale(LC_CTYPE, "");
       
  1856 	if(!(dpy = XOpenDisplay(0)))
       
  1857 		eprint("dwm: cannot open display\n");
       
  1858 	screen = DefaultScreen(dpy);
       
  1859 	root = RootWindow(dpy, screen);
       
  1860 
       
  1861 	checkotherwm();
       
  1862 	setup();
       
  1863 	drawbar();
       
  1864 	scan();
       
  1865 	run();
  1871 	cleanup();
  1866 	cleanup();
       
  1867 
  1872 	XCloseDisplay(dpy);
  1868 	XCloseDisplay(dpy);
  1873 	return 0;
  1869 	return 0;
  1874 }
  1870 }