all repos — dwm @ 7a496e9777f2656987ba86dbba1e87a46a483fac

fork of suckless dynamic window manager

dwm.c (view raw)

   1/* See LICENSE file for copyright and license details.
   2 *
   3 * 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 * manager selects for SubstructureRedirectMask on the root window, to receive
   6 * events about window (dis-)appearance.  Only one X connection at a time is
   7 * allowed to select for this event mask.
   8 *
   9 * Calls to fetch an X event from the event queue are blocking.  Due reading
  10 * status text from standard input, a select()-driven main loop has been
  11 * implemented which selects for reads on the X connection and STDIN_FILENO to
  12 * handle all data smoothly. The event handlers of dwm are organized in an
  13 * array which is accessed whenever a new event has been fetched. This allows
  14 * event dispatching in O(1) time.
  15 *
  16 * Each child of the root window is called a client, except windows which have
  17 * set the override_redirect flag.  Clients are organized in a global
  18 * doubly-linked client list, the focus history is remembered through a global
  19 * stack list. Each client contains an array of Bools of the same size as the
  20 * global tags array to indicate the tags of a client.  
  21 *
  22 * Keys and tagging rules are organized as arrays and defined in config.h.
  23 *
  24 * To understand everything else, start reading main().
  25 */
  26#include <errno.h>
  27#include <locale.h>
  28#include <stdarg.h>
  29#include <stdio.h>
  30#include <stdlib.h>
  31#include <string.h>
  32#include <unistd.h>
  33#include <sys/select.h>
  34#include <sys/types.h>
  35#include <sys/wait.h>
  36#include <regex.h>
  37#include <X11/cursorfont.h>
  38#include <X11/keysym.h>
  39#include <X11/Xatom.h>
  40#include <X11/Xlib.h>
  41#include <X11/Xproto.h>
  42#include <X11/Xutil.h>
  43//#ifdef XINERAMA
  44#include <X11/extensions/Xinerama.h>
  45//#endif
  46
  47/* macros */
  48#define BUTTONMASK		(ButtonPressMask | ButtonReleaseMask)
  49#define CLEANMASK(mask)		(mask & ~(numlockmask | LockMask))
  50#define LENGTH(x)		(sizeof x / sizeof x[0])
  51#define MAXTAGLEN		16
  52#define MOUSEMASK		(BUTTONMASK | PointerMotionMask)
  53
  54
  55/* enums */
  56enum { BarTop, BarBot, BarOff };			/* bar position */
  57enum { CurNormal, CurResize, CurMove, CurLast };	/* cursor */
  58enum { ColBorder, ColFG, ColBG, ColLast };		/* color */
  59enum { NetSupported, NetWMName, NetLast };		/* EWMH atoms */
  60enum { WMProtocols, WMDelete, WMName, WMState, WMLast };/* default atoms */
  61
  62/* typedefs */
  63typedef struct Client Client;
  64struct Client {
  65	char name[256];
  66	int x, y, w, h;
  67	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
  68	int minax, maxax, minay, maxay;
  69	long flags;
  70	unsigned int border, oldborder;
  71	Bool isbanned, isfixed, isfloating;
  72	Bool *tags;
  73	Client *next;
  74	Client *prev;
  75	Client *snext;
  76	Window win;
  77	int monitor;
  78};
  79
  80typedef struct {
  81	int x, y, w, h;
  82	unsigned long norm[ColLast];
  83	unsigned long sel[ColLast];
  84	Drawable drawable;
  85	GC gc;
  86	struct {
  87		int ascent;
  88		int descent;
  89		int height;
  90		XFontSet set;
  91		XFontStruct *xfont;
  92	} font;
  93} DC; /* draw context */
  94
  95typedef struct {
  96	unsigned long mod;
  97	KeySym keysym;
  98	void (*func)(const char *arg);
  99	const char *arg;
 100} Key;
 101
 102typedef struct {
 103	const char *symbol;
 104	void (*arrange)(void);
 105} Layout;
 106
 107typedef struct {
 108	const char *prop;
 109	const char *tags;
 110	Bool isfloating;
 111	int monitor;
 112} Rule;
 113
 114typedef struct {
 115	regex_t *propregex;
 116	regex_t *tagregex;
 117} Regs;
 118
 119typedef struct {
 120	int id;
 121	Window barwin;
 122//TODO: Window root;
 123//TODO: int screen;
 124	int sx, sy, sw, sh, wax, way, wah, waw;
 125	DC dc;
 126	Bool *seltags;
 127	Bool *prevtags;
 128	Layout *layout;
 129	double mwfact;
 130} Monitor;
 131
 132/* function declarations */
 133void applyrules(Client *c);
 134void arrange(void);
 135void attach(Client *c);
 136void attachstack(Client *c);
 137void ban(Client *c);
 138void buttonpress(XEvent *e);
 139void checkotherwm(void);
 140void cleanup(void);
 141void compileregs(void);
 142void configure(Client *c);
 143void configurenotify(XEvent *e);
 144void configurerequest(XEvent *e);
 145void destroynotify(XEvent *e);
 146void detach(Client *c);
 147void detachstack(Client *c);
 148void drawbar(void);
 149void drawsquare(Monitor *, Bool filled, Bool empty, unsigned long col[ColLast]);
 150void drawtext(Monitor *, const char *text, unsigned long col[ColLast]);
 151void *emallocz(unsigned int size);
 152void enternotify(XEvent *e);
 153void eprint(const char *errstr, ...);
 154void expose(XEvent *e);
 155void floating(void); /* default floating layout */
 156void focus(Client *c);
 157void focusin(XEvent *e);
 158void focusnext(const char *arg);
 159void focusprev(const char *arg);
 160Client *getclient(Window w);
 161unsigned long getcolor(const char *colstr);
 162long getstate(Window w);
 163Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
 164void grabbuttons(Client *c, Bool focused);
 165void grabkeys(void);
 166unsigned int idxoftag(const char *tag);
 167void initfont(Monitor*, const char *fontstr);
 168Bool isoccupied(Monitor *m, unsigned int t);
 169Bool isprotodel(Client *c);
 170Bool isvisible(Client *c, Monitor *m);
 171void keypress(XEvent *e);
 172void killclient(const char *arg);
 173void leavenotify(XEvent *e);
 174void manage(Window w, XWindowAttributes *wa);
 175void mappingnotify(XEvent *e);
 176void maprequest(XEvent *e);
 177void maximize(const char *arg);
 178void movemouse(Client *c);
 179Client *nexttiled(Client *c, Monitor *m);
 180void propertynotify(XEvent *e);
 181void quit(const char *arg);
 182void reapply(const char *arg);
 183void resize(Client *c, int x, int y, int w, int h, Bool sizehints);
 184void resizemouse(Client *c);
 185void restack(void);
 186void run(void);
 187void scan(void);
 188void setclientstate(Client *c, long state);
 189void setlayout(const char *arg);
 190void setmwfact(const char *arg);
 191void setup(void);
 192void spawn(const char *arg);
 193void tag(const char *arg);
 194unsigned int textnw(Monitor*, const char *text, unsigned int len);
 195unsigned int textw(Monitor*, const char *text);
 196void tile(void);
 197void togglebar(const char *arg);
 198void togglefloating(const char *arg);
 199void toggletag(const char *arg);
 200void toggleview(const char *arg);
 201void unban(Client *c);
 202void unmanage(Client *c);
 203void unmapnotify(XEvent *e);
 204void updatebarpos(Monitor *s);
 205void updatesizehints(Client *c);
 206void updatetitle(Client *c);
 207void view(const char *arg);
 208void viewprevtag(const char *arg);	/* views previous selected tags */
 209int xerror(Display *dpy, XErrorEvent *ee);
 210int xerrordummy(Display *dsply, XErrorEvent *ee);
 211int xerrorstart(Display *dsply, XErrorEvent *ee);
 212void zoom(const char *arg);
 213int monitorat(int, int);
 214void movetomonitor(const char *arg);
 215void selectmonitor(const char *arg);
 216
 217/* variables */
 218char stext[256];
 219int mcount, screen;
 220//double mwfact;
 221//int screen, sx, sy, sw, sh, wax, way, waw, wah;
 222int (*xerrorxlib)(Display *, XErrorEvent *);
 223unsigned int bh, bpos;
 224unsigned int blw = 0;
 225unsigned int numlockmask = 0;
 226void (*handler[LASTEvent]) (XEvent *) = {
 227	[ButtonPress] = buttonpress,
 228	[ConfigureRequest] = configurerequest,
 229	[ConfigureNotify] = configurenotify,
 230	[DestroyNotify] = destroynotify,
 231	[EnterNotify] = enternotify,
 232	[Expose] = expose,
 233	[FocusIn] = focusin,
 234	[KeyPress] = keypress,
 235	[LeaveNotify] = leavenotify,
 236	[MappingNotify] = mappingnotify,
 237	[MapRequest] = maprequest,
 238	[PropertyNotify] = propertynotify,
 239	[UnmapNotify] = unmapnotify
 240};
 241Atom wmatom[WMLast], netatom[NetLast];
 242Bool domwfact = True;
 243Bool dozoom = True;
 244Bool otherwm, readin;
 245Bool running = True;
 246//Bool selscreen = True;
 247Client *clients = NULL;
 248Client *sel = NULL;
 249Client *stack = NULL;
 250Cursor cursor[CurLast];
 251Display *dpy;
 252DC dc = {0};
 253Window root;
 254//Layout *layout = NULL;
 255//Window barwin, root;
 256Regs *regs = NULL;
 257Monitor *monitors;
 258int selmonitor = 0;
 259
 260/* configuration, allows nested code to access above variables */
 261#include "config.h"
 262
 263//Bool prevtags[LENGTH(tags)];
 264
 265/* function implementations */
 266void
 267applyrules(Client *c) {
 268	static char buf[512];
 269	unsigned int i, j;
 270	regmatch_t tmp;
 271	Bool matched_tag = False;
 272	Bool matched_monitor = False;
 273	XClassHint ch = { 0 };
 274
 275	/* rule matching */
 276	XGetClassHint(dpy, c->win, &ch);
 277	snprintf(buf, sizeof buf, "%s:%s:%s",
 278			ch.res_class ? ch.res_class : "",
 279			ch.res_name ? ch.res_name : "", c->name);
 280	for(i = 0; i < LENGTH(rules); i++)
 281		if(regs[i].propregex && !regexec(regs[i].propregex, buf, 1, &tmp, 0)) {
 282			if (rules[i].monitor >= 0 && rules[i].monitor < mcount) {
 283				matched_monitor = True;
 284				c->monitor = rules[i].monitor;
 285			}
 286
 287			c->isfloating = rules[i].isfloating;
 288			for(j = 0; regs[i].tagregex && j < LENGTH(tags); j++) {
 289				if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) {
 290					matched_tag = True;
 291					c->tags[j] = True;
 292				}
 293			}
 294		}
 295	if(ch.res_class)
 296		XFree(ch.res_class);
 297	if(ch.res_name)
 298		XFree(ch.res_name);
 299	if(!matched_tag)
 300		memcpy(c->tags, monitors[monitorat(-1, -1)].seltags, sizeof initags);
 301	if (!matched_monitor)
 302		c->monitor = monitorat(-1, -1);
 303}
 304
 305void
 306arrange(void) {
 307	Client *c;
 308
 309	for(c = clients; c; c = c->next)
 310		if(isvisible(c, &monitors[c->monitor]))
 311			unban(c);
 312		else
 313			ban(c);
 314
 315	monitors[selmonitor].layout->arrange();
 316	focus(NULL);
 317	restack();
 318}
 319
 320void
 321attach(Client *c) {
 322	if(clients)
 323		clients->prev = c;
 324	c->next = clients;
 325	clients = c;
 326}
 327
 328void
 329attachstack(Client *c) {
 330	c->snext = stack;
 331	stack = c;
 332}
 333
 334void
 335ban(Client *c) {
 336	if(c->isbanned)
 337		return;
 338	XMoveWindow(dpy, c->win, c->x + 3 * monitors[c->monitor].sw, c->y);
 339	c->isbanned = True;
 340}
 341
 342void
 343buttonpress(XEvent *e) {
 344	unsigned int i, x;
 345	Client *c;
 346	XButtonPressedEvent *ev = &e->xbutton;
 347
 348	Monitor s = monitors[monitorat(-1, -1)];
 349
 350	if(ev->window == s.barwin) {
 351		x = 0;
 352		for(i = 0; i < LENGTH(tags); i++) {
 353			x += textw(&s, tags[i]);
 354			if(ev->x < x) {
 355				if(ev->button == Button1) {
 356					if(ev->state & MODKEY)
 357						tag(tags[i]);
 358					else
 359						view(tags[i]);
 360				}
 361				else if(ev->button == Button3) {
 362					if(ev->state & MODKEY)
 363						toggletag(tags[i]);
 364					else
 365						toggleview(tags[i]);
 366				}
 367				return;
 368			}
 369		}
 370		if((ev->x < x + blw) && ev->button == Button1)
 371			setlayout(NULL);
 372	}
 373	else if((c = getclient(ev->window))) {
 374		focus(c);
 375		if(CLEANMASK(ev->state) != MODKEY)
 376			return;
 377		if(ev->button == Button1) {
 378			if((s.layout->arrange == floating) || c->isfloating)
 379				restack();
 380			else
 381				togglefloating(NULL);
 382			movemouse(c);
 383		}
 384		else if(ev->button == Button2) {
 385			if((floating != s.layout->arrange) && c->isfloating)
 386				togglefloating(NULL);
 387			else
 388				zoom(NULL);
 389		}
 390		else if(ev->button == Button3 && !c->isfixed) {
 391			if((floating == s.layout->arrange) || c->isfloating)
 392				restack();
 393			else
 394				togglefloating(NULL);
 395			resizemouse(c);
 396		}
 397	}
 398}
 399
 400void
 401checkotherwm(void) {
 402	otherwm = False;
 403	XSetErrorHandler(xerrorstart);
 404
 405	/* this causes an error if some other window manager is running */
 406	XSelectInput(dpy, root, SubstructureRedirectMask);
 407	XSync(dpy, False);
 408	if(otherwm)
 409		eprint("dwm: another window manager is already running\n");
 410	XSync(dpy, False);
 411	XSetErrorHandler(NULL);
 412	xerrorxlib = XSetErrorHandler(xerror);
 413	XSync(dpy, False);
 414}
 415
 416void
 417cleanup(void) {
 418	unsigned int i;
 419	close(STDIN_FILENO);
 420	while(stack) {
 421		unban(stack);
 422		unmanage(stack);
 423	}
 424	for(i = 0; i < mcount; i++) {
 425		Monitor *m = &monitors[i];
 426		if(m->dc.font.set)
 427			XFreeFontSet(dpy, m->dc.font.set);
 428		else
 429			XFreeFont(dpy, m->dc.font.xfont);
 430		XUngrabKey(dpy, AnyKey, AnyModifier, root);
 431		XFreePixmap(dpy, m->dc.drawable);
 432		XFreeGC(dpy, m->dc.gc);
 433		XDestroyWindow(dpy, m->barwin);
 434		XFreeCursor(dpy, cursor[CurNormal]);
 435		XFreeCursor(dpy, cursor[CurResize]);
 436		XFreeCursor(dpy, cursor[CurMove]);
 437		XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
 438		XSync(dpy, False);
 439	}
 440}
 441
 442void
 443compileregs(void) {
 444	unsigned int i;
 445	regex_t *reg;
 446
 447	if(regs)
 448		return;
 449	regs = emallocz(LENGTH(rules) * sizeof(Regs));
 450	for(i = 0; i < LENGTH(rules); i++) {
 451		if(rules[i].prop) {
 452			reg = emallocz(sizeof(regex_t));
 453			if(regcomp(reg, rules[i].prop, REG_EXTENDED))
 454				free(reg);
 455			else
 456				regs[i].propregex = reg;
 457		}
 458		if(rules[i].tags) {
 459			reg = emallocz(sizeof(regex_t));
 460			if(regcomp(reg, rules[i].tags, REG_EXTENDED))
 461				free(reg);
 462			else
 463				regs[i].tagregex = reg;
 464		}
 465	}
 466}
 467
 468void
 469configure(Client *c) {
 470	XConfigureEvent ce;
 471
 472	ce.type = ConfigureNotify;
 473	ce.display = dpy;
 474	ce.event = c->win;
 475	ce.window = c->win;
 476	ce.x = c->x;
 477	ce.y = c->y;
 478	ce.width = c->w;
 479	ce.height = c->h;
 480	ce.border_width = c->border;
 481	ce.above = None;
 482	ce.override_redirect = False;
 483	XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
 484}
 485
 486void
 487configurenotify(XEvent *e) {
 488	XConfigureEvent *ev = &e->xconfigure;
 489	Monitor *m = &monitors[selmonitor];
 490
 491	if(ev->window == root && (ev->width != m->sw || ev->height != m->sh)) {
 492		m->sw = ev->width;
 493		m->sh = ev->height;
 494		XFreePixmap(dpy, dc.drawable);
 495		dc.drawable = XCreatePixmap(dpy, root, m->sw, bh, DefaultDepth(dpy, screen));
 496		XResizeWindow(dpy, m->barwin, m->sw, bh);
 497		updatebarpos(m);
 498		arrange();
 499	}
 500}
 501
 502void
 503configurerequest(XEvent *e) {
 504	Client *c;
 505	XConfigureRequestEvent *ev = &e->xconfigurerequest;
 506	XWindowChanges wc;
 507
 508	if((c = getclient(ev->window))) {
 509		Monitor *m = &monitors[c->monitor];
 510		if(ev->value_mask & CWBorderWidth)
 511			c->border = ev->border_width;
 512		if(c->isfixed || c->isfloating || (floating == m->layout->arrange)) {
 513			if(ev->value_mask & CWX)
 514				c->x = m->sx+ev->x;
 515			if(ev->value_mask & CWY)
 516				c->y = m->sy+ev->y;
 517			if(ev->value_mask & CWWidth)
 518				c->w = ev->width;
 519			if(ev->value_mask & CWHeight)
 520				c->h = ev->height;
 521			if((c->x - m->sx + c->w) > m->sw && c->isfloating)
 522				c->x = m->sx + (m->sw / 2 - c->w / 2); /* center in x direction */
 523			if((c->y - m->sy + c->h) > m->sh && c->isfloating)
 524				c->y = m->sy + (m->sh / 2 - c->h / 2); /* center in y direction */
 525			if((ev->value_mask & (CWX | CWY))
 526			&& !(ev->value_mask & (CWWidth | CWHeight)))
 527				configure(c);
 528			if(isvisible(c, &monitors[monitorat(-1,-1)]))
 529				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
 530		}
 531		else
 532			configure(c);
 533	}
 534	else {
 535		wc.x = ev->x;
 536		wc.y = ev->y;
 537		wc.width = ev->width;
 538		wc.height = ev->height;
 539		wc.border_width = ev->border_width;
 540		wc.sibling = ev->above;
 541		wc.stack_mode = ev->detail;
 542		XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
 543	}
 544	XSync(dpy, False);
 545}
 546
 547void
 548destroynotify(XEvent *e) {
 549	Client *c;
 550	XDestroyWindowEvent *ev = &e->xdestroywindow;
 551
 552	if((c = getclient(ev->window)))
 553		unmanage(c);
 554}
 555
 556void
 557detach(Client *c) {
 558	if(c->prev)
 559		c->prev->next = c->next;
 560	if(c->next)
 561		c->next->prev = c->prev;
 562	if(c == clients)
 563		clients = c->next;
 564	c->next = c->prev = NULL;
 565}
 566
 567void
 568detachstack(Client *c) {
 569	Client **tc;
 570
 571	for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
 572	*tc = c->snext;
 573}
 574
 575void
 576drawbar(void) {
 577	int i, x, s;
 578
 579	for(s = 0; s < mcount; ++s) {
 580		Monitor *m = &monitors[s];
 581		m->dc.x = 0;
 582		for(i = 0; i < LENGTH(tags); i++) {
 583			m->dc.w = textw(m, tags[i]);
 584			if(m->seltags[i]) {
 585				drawtext(m, tags[i], m->dc.sel);
 586				drawsquare(m, sel && sel->tags[i] && sel->monitor == m->id, isoccupied(m, i), m->dc.sel);
 587			}
 588			else {
 589				drawtext(m, tags[i], m->dc.norm);
 590				drawsquare(m, sel && sel->tags[i] && sel->monitor == m->id, isoccupied(m, i), m->dc.norm);
 591			}
 592			m->dc.x += m->dc.w;
 593		}
 594		m->dc.w = blw;
 595		drawtext(m, m->layout->symbol, m->dc.norm);
 596		x = m->dc.x + m->dc.w;
 597		m->dc.w = textw(m, stext);
 598		m->dc.x = m->sw - m->dc.w;
 599		if(m->dc.x < x) {
 600			m->dc.x = x;
 601			m->dc.w = m->sw - x;
 602		}
 603		drawtext(m, stext, m->dc.norm);
 604		if((m->dc.w = m->dc.x - x) > bh) {
 605			m->dc.x = x;
 606			if(sel && sel->monitor == m->id) {
 607				drawtext(m, sel->name, m->dc.sel);
 608				drawsquare(m, False, sel->isfloating, m->dc.sel);
 609			}
 610			else
 611				drawtext(m, NULL, m->dc.norm);
 612		}
 613		XCopyArea(dpy, m->dc.drawable, m->barwin, m->dc.gc, 0, 0, m->sw, bh, 0, 0);
 614		XSync(dpy, False);
 615	}
 616}
 617
 618void
 619drawsquare(Monitor *m, Bool filled, Bool empty, unsigned long col[ColLast]) {
 620	int x;
 621	XGCValues gcv;
 622	XRectangle r = { m->dc.x, m->dc.y, m->dc.w, m->dc.h };
 623
 624	gcv.foreground = col[ColFG];
 625	XChangeGC(dpy, m->dc.gc, GCForeground, &gcv);
 626	x = (m->dc.font.ascent + m->dc.font.descent + 2) / 4;
 627	r.x = m->dc.x + 1;
 628	r.y = m->dc.y + 1;
 629	if(filled) {
 630		r.width = r.height = x + 1;
 631		XFillRectangles(dpy, m->dc.drawable, m->dc.gc, &r, 1);
 632	}
 633	else if(empty) {
 634		r.width = r.height = x;
 635		XDrawRectangles(dpy, m->dc.drawable, m->dc.gc, &r, 1);
 636	}
 637}
 638
 639void
 640drawtext(Monitor *m, const char *text, unsigned long col[ColLast]) {
 641	int x, y, w, h;
 642	static char buf[256];
 643	unsigned int len, olen;
 644	XRectangle r = { m->dc.x, m->dc.y, m->dc.w, m->dc.h };
 645
 646	XSetForeground(dpy, m->dc.gc, col[ColBG]);
 647	XFillRectangles(dpy, m->dc.drawable, m->dc.gc, &r, 1);
 648	if(!text)
 649		return;
 650	w = 0;
 651	olen = len = strlen(text);
 652	if(len >= sizeof buf)
 653		len = sizeof buf - 1;
 654	memcpy(buf, text, len);
 655	buf[len] = 0;
 656	h = m->dc.font.ascent + m->dc.font.descent;
 657	y = m->dc.y + (m->dc.h / 2) - (h / 2) + m->dc.font.ascent;
 658	x = m->dc.x + (h / 2);
 659	/* shorten text if necessary */
 660	while(len && (w = textnw(m, buf, len)) > m->dc.w - h)
 661		buf[--len] = 0;
 662	if(len < olen) {
 663		if(len > 1)
 664			buf[len - 1] = '.';
 665		if(len > 2)
 666			buf[len - 2] = '.';
 667		if(len > 3)
 668			buf[len - 3] = '.';
 669	}
 670	if(w > m->dc.w)
 671		return; /* too long */
 672	XSetForeground(dpy, m->dc.gc, col[ColFG]);
 673	if(m->dc.font.set)
 674		XmbDrawString(dpy, m->dc.drawable, m->dc.font.set, m->dc.gc, x, y, buf, len);
 675	else
 676		XDrawString(dpy, m->dc.drawable, m->dc.gc, x, y, buf, len);
 677}
 678
 679void *
 680emallocz(unsigned int size) {
 681	void *res = calloc(1, size);
 682
 683	if(!res)
 684		eprint("fatal: could not malloc() %u bytes\n", size);
 685	return res;
 686}
 687
 688void
 689enternotify(XEvent *e) {
 690	Client *c;
 691	XCrossingEvent *ev = &e->xcrossing;
 692
 693	if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
 694		return;
 695	if((c = getclient(ev->window)))
 696		focus(c);
 697	else if(ev->window == root) {
 698		selmonitor = True;
 699		focus(NULL);
 700	}
 701}
 702
 703void
 704eprint(const char *errstr, ...) {
 705	va_list ap;
 706
 707	va_start(ap, errstr);
 708	vfprintf(stderr, errstr, ap);
 709	va_end(ap);
 710	exit(EXIT_FAILURE);
 711}
 712
 713void
 714expose(XEvent *e) {
 715	XExposeEvent *ev = &e->xexpose;
 716
 717	if(ev->count == 0) {
 718		if(ev->window == monitors[selmonitor].barwin)
 719			drawbar();
 720	}
 721}
 722
 723void
 724floating(void) { /* default floating layout */
 725	Client *c;
 726
 727	domwfact = dozoom = False;
 728	for(c = clients; c; c = c->next)
 729		if(isvisible(c, &monitors[selmonitor]))
 730			resize(c, c->x, c->y, c->w, c->h, True);
 731}
 732
 733void
 734focus(Client *c) {
 735	Monitor *m = &monitors[monitorat(-1, -1)];
 736	if(!c || (c && !isvisible(c, m)))
 737		for(c = stack; c && !isvisible(c, m); c = c->snext);
 738	if(sel && sel != c) {
 739		grabbuttons(sel, False);
 740		XSetWindowBorder(dpy, sel->win, monitors[sel->monitor].dc.norm[ColBorder]);
 741	}
 742	if(c) {
 743		detachstack(c);
 744		attachstack(c);
 745		grabbuttons(c, True);
 746	}
 747	sel = c;
 748	drawbar();
 749	if(c) {
 750		XSetWindowBorder(dpy, c->win, monitors[c->monitor].dc.sel[ColBorder]);
 751		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
 752		selmonitor = monitorat(c->x, c->y);
 753	}
 754	else {
 755		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
 756		selmonitor = monitorat(-1, -1);
 757	}
 758}
 759
 760void
 761focusin(XEvent *e) { /* there are some broken focus acquiring clients */
 762	XFocusChangeEvent *ev = &e->xfocus;
 763
 764	if(sel && ev->window != sel->win)
 765		XSetInputFocus(dpy, sel->win, RevertToPointerRoot, CurrentTime);
 766}
 767
 768void
 769focusnext(const char *arg) {
 770	Client *c;
 771	Monitor *m = &monitors[selmonitor];
 772
 773	if(!sel)
 774		return;
 775	for(c = sel->next; c && !isvisible(c, m); c = c->next);
 776	if(!c)
 777		for(c = clients; c && !isvisible(c, m); c = c->next);
 778	if(c) {
 779		focus(c);
 780		restack();
 781	}
 782}
 783
 784void
 785focusprev(const char *arg) {
 786	Client *c;
 787	Monitor *m = &monitors[selmonitor];
 788
 789	if(!sel)
 790		return;
 791	for(c = sel->prev; c && !isvisible(c, m); c = c->prev);
 792	if(!c) {
 793		for(c = clients; c && c->next; c = c->next);
 794		for(; c && !isvisible(c, m); c = c->prev);
 795	}
 796	if(c) {
 797		focus(c);
 798		restack();
 799	}
 800}
 801
 802Client *
 803getclient(Window w) {
 804	Client *c;
 805
 806	for(c = clients; c && c->win != w; c = c->next);
 807	return c;
 808}
 809
 810unsigned long
 811getcolor(const char *colstr) {
 812	Colormap cmap = DefaultColormap(dpy, screen);
 813	XColor color;
 814
 815	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
 816		eprint("error, cannot allocate color '%s'\n", colstr);
 817	return color.pixel;
 818}
 819
 820long
 821getstate(Window w) {
 822	int format, status;
 823	long result = -1;
 824	unsigned char *p = NULL;
 825	unsigned long n, extra;
 826	Atom real;
 827
 828	status = XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
 829			&real, &format, &n, &extra, (unsigned char **)&p);
 830	if(status != Success)
 831		return -1;
 832	if(n != 0)
 833		result = *p;
 834	XFree(p);
 835	return result;
 836}
 837
 838Bool
 839gettextprop(Window w, Atom atom, char *text, unsigned int size) {
 840	char **list = NULL;
 841	int n;
 842	XTextProperty name;
 843
 844	if(!text || size == 0)
 845		return False;
 846	text[0] = '\0';
 847	XGetTextProperty(dpy, w, &name, atom);
 848	if(!name.nitems)
 849		return False;
 850	if(name.encoding == XA_STRING)
 851		strncpy(text, (char *)name.value, size - 1);
 852	else {
 853		if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
 854		&& n > 0 && *list) {
 855			strncpy(text, *list, size - 1);
 856			XFreeStringList(list);
 857		}
 858	}
 859	text[size - 1] = '\0';
 860	XFree(name.value);
 861	return True;
 862}
 863
 864void
 865grabbuttons(Client *c, Bool focused) {
 866	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
 867
 868	if(focused) {
 869		XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
 870				GrabModeAsync, GrabModeSync, None, None);
 871		XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
 872				GrabModeAsync, GrabModeSync, None, None);
 873		XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK,
 874				GrabModeAsync, GrabModeSync, None, None);
 875		XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
 876				GrabModeAsync, GrabModeSync, None, None);
 877
 878		XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
 879				GrabModeAsync, GrabModeSync, None, None);
 880		XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK,
 881				GrabModeAsync, GrabModeSync, None, None);
 882		XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK,
 883				GrabModeAsync, GrabModeSync, None, None);
 884		XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
 885				GrabModeAsync, GrabModeSync, None, None);
 886
 887		XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
 888				GrabModeAsync, GrabModeSync, None, None);
 889		XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK,
 890				GrabModeAsync, GrabModeSync, None, None);
 891		XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK,
 892				GrabModeAsync, GrabModeSync, None, None);
 893		XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
 894				GrabModeAsync, GrabModeSync, None, None);
 895	}
 896	else
 897		XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
 898				GrabModeAsync, GrabModeSync, None, None);
 899}
 900
 901void
 902grabkeys(void)  {
 903	unsigned int i;
 904	KeyCode code;
 905
 906	XUngrabKey(dpy, AnyKey, AnyModifier, root);
 907	for(i = 0; i < LENGTH(keys); i++) {
 908		code = XKeysymToKeycode(dpy, keys[i].keysym);
 909		XGrabKey(dpy, code, keys[i].mod, root, True,
 910				GrabModeAsync, GrabModeAsync);
 911		XGrabKey(dpy, code, keys[i].mod | LockMask, root, True,
 912				GrabModeAsync, GrabModeAsync);
 913		XGrabKey(dpy, code, keys[i].mod | numlockmask, root, True,
 914				GrabModeAsync, GrabModeAsync);
 915		XGrabKey(dpy, code, keys[i].mod | numlockmask | LockMask, root, True,
 916				GrabModeAsync, GrabModeAsync);
 917	}
 918}
 919
 920unsigned int
 921idxoftag(const char *tag) {
 922	unsigned int i;
 923
 924	for(i = 0; (i < LENGTH(tags)) && (tags[i] != tag); i++);
 925	return (i < LENGTH(tags)) ? i : 0;
 926}
 927
 928void
 929initfont(Monitor *m, const char *fontstr) {
 930	char *def, **missing;
 931	int i, n;
 932
 933	missing = NULL;
 934	if(m->dc.font.set)
 935		XFreeFontSet(dpy, m->dc.font.set);
 936	m->dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
 937	if(missing) {
 938		while(n--)
 939			fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]);
 940		XFreeStringList(missing);
 941	}
 942	if(m->dc.font.set) {
 943		XFontSetExtents *font_extents;
 944		XFontStruct **xfonts;
 945		char **font_names;
 946		m->dc.font.ascent = m->dc.font.descent = 0;
 947		font_extents = XExtentsOfFontSet(m->dc.font.set);
 948		n = XFontsOfFontSet(m->dc.font.set, &xfonts, &font_names);
 949		for(i = 0, m->dc.font.ascent = 0, m->dc.font.descent = 0; i < n; i++) {
 950			if(m->dc.font.ascent < (*xfonts)->ascent)
 951				m->dc.font.ascent = (*xfonts)->ascent;
 952			if(m->dc.font.descent < (*xfonts)->descent)
 953				m->dc.font.descent = (*xfonts)->descent;
 954			xfonts++;
 955		}
 956	}
 957	else {
 958		if(m->dc.font.xfont)
 959			XFreeFont(dpy, m->dc.font.xfont);
 960		m->dc.font.xfont = NULL;
 961		if(!(m->dc.font.xfont = XLoadQueryFont(dpy, fontstr))
 962		&& !(m->dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
 963			eprint("error, cannot load font: '%s'\n", fontstr);
 964		m->dc.font.ascent = m->dc.font.xfont->ascent;
 965		m->dc.font.descent = m->dc.font.xfont->descent;
 966	}
 967	m->dc.font.height = m->dc.font.ascent + m->dc.font.descent;
 968}
 969
 970Bool
 971isoccupied(Monitor *m, unsigned int t) {
 972	Client *c;
 973
 974	for(c = clients; c; c = c->next)
 975		if(c->tags[t] && c->monitor == m->id)
 976			return True;
 977	return False;
 978}
 979
 980Bool
 981isprotodel(Client *c) {
 982	int i, n;
 983	Atom *protocols;
 984	Bool ret = False;
 985
 986	if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
 987		for(i = 0; !ret && i < n; i++)
 988			if(protocols[i] == wmatom[WMDelete])
 989				ret = True;
 990		XFree(protocols);
 991	}
 992	return ret;
 993}
 994
 995Bool
 996isvisible(Client *c, Monitor *m) {
 997	unsigned int i;
 998
 999	for(i = 0; i < LENGTH(tags); i++)
1000		if(c->tags[i] && monitors[c->monitor].seltags[i] && m->id == c->monitor)
1001			return True;
1002	return False;
1003}
1004
1005void
1006keypress(XEvent *e) {
1007	unsigned int i;
1008	KeySym keysym;
1009	XKeyEvent *ev;
1010
1011	ev = &e->xkey;
1012	keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
1013	for(i = 0; i < LENGTH(keys); i++)
1014		if(keysym == keys[i].keysym
1015		&& CLEANMASK(keys[i].mod) == CLEANMASK(ev->state))
1016		{
1017			if(keys[i].func)
1018				keys[i].func(keys[i].arg);
1019		}
1020}
1021
1022void
1023killclient(const char *arg) {
1024	XEvent ev;
1025
1026	if(!sel)
1027		return;
1028	if(isprotodel(sel)) {
1029		ev.type = ClientMessage;
1030		ev.xclient.window = sel->win;
1031		ev.xclient.message_type = wmatom[WMProtocols];
1032		ev.xclient.format = 32;
1033		ev.xclient.data.l[0] = wmatom[WMDelete];
1034		ev.xclient.data.l[1] = CurrentTime;
1035		XSendEvent(dpy, sel->win, False, NoEventMask, &ev);
1036	}
1037	else
1038		XKillClient(dpy, sel->win);
1039}
1040
1041void
1042leavenotify(XEvent *e) {
1043	XCrossingEvent *ev = &e->xcrossing;
1044
1045	if((ev->window == root) && !ev->same_screen) {
1046		selmonitor = False;
1047		focus(NULL);
1048	}
1049}
1050
1051void
1052manage(Window w, XWindowAttributes *wa) {
1053	Client *c, *t = NULL;
1054	Window trans;
1055	Status rettrans;
1056	XWindowChanges wc;
1057
1058	c = emallocz(sizeof(Client));
1059	c->tags = emallocz(sizeof initags);
1060	c->win = w;
1061
1062	applyrules(c);
1063	Monitor *m = &monitors[c->monitor];
1064
1065	c->x = wa->x+m->sx;
1066	c->y = wa->y+m->sy;
1067	c->w = wa->width;
1068	c->h = wa->height;
1069	c->oldborder = wa->border_width;
1070
1071	if (monitorat(c->x, c->y) != c->monitor) {
1072		c->x = m->sx;
1073		c->y = m->sy;
1074	}
1075
1076	if(c->w == m->sw && c->h == m->sh) {
1077		c->x = m->sx;
1078		c->y = m->sy;
1079		c->border = wa->border_width;
1080	}
1081	else {
1082		if(c->x + c->w + 2 * c->border > m->wax + m->waw)
1083			c->x = m->wax + m->waw - c->w - 2 * c->border;
1084		if(c->y + c->h + 2 * c->border > m->way + m->wah)
1085			c->y = m->way + m->wah - c->h - 2 * c->border;
1086		if(c->x < m->wax)
1087			c->x = m->wax;
1088		if(c->y < m->way)
1089			c->y = m->way;
1090		c->border = BORDERPX;
1091	}
1092	wc.border_width = c->border;
1093	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
1094	XSetWindowBorder(dpy, w, m->dc.norm[ColBorder]);
1095	configure(c); /* propagates border_width, if size doesn't change */
1096	updatesizehints(c);
1097	XSelectInput(dpy, w, EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask);
1098	grabbuttons(c, False);
1099	updatetitle(c);
1100	if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success))
1101		for(t = clients; t && t->win != trans; t = t->next);
1102	if(t)
1103		memcpy(c->tags, t->tags, sizeof initags);
1104	if(!c->isfloating)
1105		c->isfloating = (rettrans == Success) || c->isfixed;
1106	attach(c);
1107	attachstack(c);
1108	XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); /* some windows require this */
1109	ban(c);
1110	XMapWindow(dpy, c->win);
1111	setclientstate(c, NormalState);
1112	arrange();
1113}
1114
1115void
1116mappingnotify(XEvent *e) {
1117	XMappingEvent *ev = &e->xmapping;
1118
1119	XRefreshKeyboardMapping(ev);
1120	if(ev->request == MappingKeyboard)
1121		grabkeys();
1122}
1123
1124void
1125maprequest(XEvent *e) {
1126	static XWindowAttributes wa;
1127	XMapRequestEvent *ev = &e->xmaprequest;
1128
1129	if(!XGetWindowAttributes(dpy, ev->window, &wa))
1130		return;
1131	if(wa.override_redirect)
1132		return;
1133	if(!getclient(ev->window))
1134		manage(ev->window, &wa);
1135}
1136
1137void
1138maximize(const char *arg) {
1139/*
1140	if(!sel || (!sel->isfloating && layout->arrange != floating))
1141		return;
1142	resize(sel, wax, way, waw - 2 * sel->border, wah - 2 * sel->border, True);
1143*/
1144}
1145
1146void
1147movemouse(Client *c) {
1148	int x1, y1, ocx, ocy, di, nx, ny;
1149	unsigned int dui;
1150	Window dummy;
1151	XEvent ev;
1152
1153	ocx = nx = c->x;
1154	ocy = ny = c->y;
1155	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
1156			None, cursor[CurMove], CurrentTime) != GrabSuccess)
1157		return;
1158	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
1159	for(;;) {
1160		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
1161		switch (ev.type) {
1162		case ButtonRelease:
1163			XUngrabPointer(dpy, CurrentTime);
1164			return;
1165		case ConfigureRequest:
1166		case Expose:
1167		case MapRequest:
1168			handler[ev.type](&ev);
1169			break;
1170		case MotionNotify:
1171			XSync(dpy, False);
1172			nx = ocx + (ev.xmotion.x - x1);
1173			ny = ocy + (ev.xmotion.y - y1);
1174			Monitor *m = &monitors[monitorat(nx, ny)];
1175			if(abs(m->wax - nx) < SNAP)
1176				nx = m->wax;
1177			else if(abs((m->wax + m->waw) - (nx + c->w + 2 * c->border)) < SNAP)
1178				nx = m->wax + m->waw - c->w - 2 * c->border;
1179			if(abs(m->way - ny) < SNAP)
1180				ny = m->way;
1181			else if(abs((m->way + m->wah) - (ny + c->h + 2 * c->border)) < SNAP)
1182				ny = m->way + m->wah - c->h - 2 * c->border;
1183			resize(c, nx, ny, c->w, c->h, False);
1184			memcpy(c->tags, monitors[monitorat(nx, ny)].seltags, sizeof initags);
1185			break;
1186		}
1187	}
1188}
1189
1190Client *
1191nexttiled(Client *c, Monitor *m) {
1192	for(; c && (c->isfloating || !isvisible(c, m)); c = c->next);
1193	return c;
1194}
1195
1196void
1197propertynotify(XEvent *e) {
1198	Client *c;
1199	Window trans;
1200	XPropertyEvent *ev = &e->xproperty;
1201
1202	if(ev->state == PropertyDelete)
1203		return; /* ignore */
1204	if((c = getclient(ev->window))) {
1205		switch (ev->atom) {
1206			default: break;
1207			case XA_WM_TRANSIENT_FOR:
1208				XGetTransientForHint(dpy, c->win, &trans);
1209				if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL)))
1210					arrange();
1211				break;
1212			case XA_WM_NORMAL_HINTS:
1213				updatesizehints(c);
1214				break;
1215		}
1216		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
1217			updatetitle(c);
1218			if(c == sel)
1219				drawbar();
1220		}
1221	}
1222}
1223
1224void
1225quit(const char *arg) {
1226	readin = running = False;
1227}
1228
1229void
1230reapply(const char *arg) {
1231	static Bool zerotags[LENGTH(tags)] = { 0 };
1232	Client *c;
1233
1234	for(c = clients; c; c = c->next) {
1235		memcpy(c->tags, zerotags, sizeof zerotags);
1236		applyrules(c);
1237	}
1238	arrange();
1239}
1240
1241void
1242resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
1243	XWindowChanges wc;
1244	Monitor scr = monitors[monitorat(x, y)];
1245	c->monitor = scr.id;
1246
1247	if(sizehints) {
1248		/* set minimum possible */
1249		if (w < 1)
1250			w = 1;
1251		if (h < 1)
1252			h = 1;
1253
1254		/* temporarily remove base dimensions */
1255		w -= c->basew;
1256		h -= c->baseh;
1257
1258		/* adjust for aspect limits */
1259		if (c->minay > 0 && c->maxay > 0 && c->minax > 0 && c->maxax > 0) {
1260			if (w * c->maxay > h * c->maxax)
1261				w = h * c->maxax / c->maxay;
1262			else if (w * c->minay < h * c->minax)
1263				h = w * c->minay / c->minax;
1264		}
1265
1266		/* adjust for increment value */
1267		if(c->incw)
1268			w -= w % c->incw;
1269		if(c->inch)
1270			h -= h % c->inch;
1271
1272		/* restore base dimensions */
1273		w += c->basew;
1274		h += c->baseh;
1275
1276		if(c->minw > 0 && w < c->minw)
1277			w = c->minw;
1278		if(c->minh > 0 && h < c->minh)
1279			h = c->minh;
1280		if(c->maxw > 0 && w > c->maxw)
1281			w = c->maxw;
1282		if(c->maxh > 0 && h > c->maxh)
1283			h = c->maxh;
1284	}
1285	if(w <= 0 || h <= 0)
1286		return;
1287	/* TODO: offscreen appearance fixes */
1288	/*
1289	if(x > scr.sw)
1290		x = scr.sw - w - 2 * c->border;
1291	if(y > scr.sh)
1292		y = scr.sh - h - 2 * c->border;
1293	if(x + w + 2 * c->border < scr.sx)
1294		x = scr.sx;
1295	if(y + h + 2 * c->border < scr.sy)
1296		y = scr.sy;
1297	*/
1298	if(c->x != x || c->y != y || c->w != w || c->h != h) {
1299		c->x = wc.x = x;
1300		c->y = wc.y = y;
1301		c->w = wc.width = w;
1302		c->h = wc.height = h;
1303		wc.border_width = c->border;
1304		XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
1305		configure(c);
1306		XSync(dpy, False);
1307	}
1308}
1309
1310void
1311resizemouse(Client *c) {
1312	int ocx, ocy;
1313	int nw, nh;
1314	XEvent ev;
1315
1316	ocx = c->x;
1317	ocy = c->y;
1318	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
1319			None, cursor[CurResize], CurrentTime) != GrabSuccess)
1320		return;
1321	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
1322	for(;;) {
1323		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
1324		switch(ev.type) {
1325		case ButtonRelease:
1326			XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
1327					c->w + c->border - 1, c->h + c->border - 1);
1328			XUngrabPointer(dpy, CurrentTime);
1329			while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
1330			return;
1331		case ConfigureRequest:
1332		case Expose:
1333		case MapRequest:
1334			handler[ev.type](&ev);
1335			break;
1336		case MotionNotify:
1337			XSync(dpy, False);
1338			if((nw = ev.xmotion.x - ocx - 2 * c->border + 1) <= 0)
1339				nw = 1;
1340			if((nh = ev.xmotion.y - ocy - 2 * c->border + 1) <= 0)
1341				nh = 1;
1342			resize(c, c->x, c->y, nw, nh, True);
1343			break;
1344		}
1345	}
1346}
1347
1348void
1349restack(void) {
1350	Client *c;
1351	XEvent ev;
1352	XWindowChanges wc;
1353	int s;
1354
1355	drawbar();
1356	if(!sel)
1357		return;
1358	if(sel->isfloating || (monitors[selmonitor].layout->arrange == floating))
1359		XRaiseWindow(dpy, sel->win);
1360	if(monitors[selmonitor].layout->arrange != floating) {
1361		wc.stack_mode = Below;
1362		wc.sibling = monitors[selmonitor].barwin;
1363		if(!sel->isfloating) {
1364			XConfigureWindow(dpy, sel->win, CWSibling | CWStackMode, &wc);
1365			wc.sibling = sel->win;
1366		}
1367		for(s = 0; s < mcount; s++) {
1368			for(c = nexttiled(clients, &monitors[s]); c; c = nexttiled(c->next, &monitors[s])) {
1369				if(c == sel)
1370					continue;
1371				XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc);
1372				wc.sibling = c->win;
1373			}
1374		}
1375	}
1376	XSync(dpy, False);
1377	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
1378}
1379
1380void
1381run(void) {
1382	char *p;
1383	char buf[sizeof stext];
1384	fd_set rd;
1385	int r, xfd;
1386	unsigned int len, offset;
1387	XEvent ev;
1388
1389	/* main event loop, also reads status text from stdin */
1390	XSync(dpy, False);
1391	xfd = ConnectionNumber(dpy);
1392	readin = True;
1393	offset = 0;
1394	len = sizeof stext - 1;
1395	buf[len] = stext[len] = '\0'; /* 0-terminator is never touched */
1396	while(running) {
1397		FD_ZERO(&rd);
1398		if(readin)
1399			FD_SET(STDIN_FILENO, &rd);
1400		FD_SET(xfd, &rd);
1401		if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) {
1402			if(errno == EINTR)
1403				continue;
1404			eprint("select failed\n");
1405		}
1406		if(FD_ISSET(STDIN_FILENO, &rd)) {
1407			switch((r = read(STDIN_FILENO, buf + offset, len - offset))) {
1408			case -1:
1409				strncpy(stext, strerror(errno), len);
1410				readin = False;
1411				break;
1412			case 0:
1413				strncpy(stext, "EOF", 4);
1414				readin = False;
1415				break;
1416			default:
1417				for(p = buf + offset; r > 0; p++, r--, offset++)
1418					if(*p == '\n' || *p == '\0') {
1419						*p = '\0';
1420						strncpy(stext, buf, len);
1421						p += r - 1; /* p is buf + offset + r - 1 */
1422						for(r = 0; *(p - r) && *(p - r) != '\n'; r++);
1423						offset = r;
1424						if(r)
1425							memmove(buf, p - r + 1, r);
1426						break;
1427					}
1428				break;
1429			}
1430			drawbar();
1431		}
1432		while(XPending(dpy)) {
1433			XNextEvent(dpy, &ev);
1434			if(handler[ev.type])
1435				(handler[ev.type])(&ev); /* call handler */
1436		}
1437	}
1438}
1439
1440void
1441scan(void) {
1442	unsigned int i, num;
1443	Window *wins, d1, d2;
1444	XWindowAttributes wa;
1445
1446	wins = NULL;
1447	if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
1448		for(i = 0; i < num; i++) {
1449			if(!XGetWindowAttributes(dpy, wins[i], &wa)
1450			|| wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
1451				continue;
1452			if(wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
1453				manage(wins[i], &wa);
1454		}
1455		for(i = 0; i < num; i++) { /* now the transients */
1456			if(!XGetWindowAttributes(dpy, wins[i], &wa))
1457				continue;
1458			if(XGetTransientForHint(dpy, wins[i], &d1)
1459			&& (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
1460				manage(wins[i], &wa);
1461		}
1462	}
1463	if(wins)
1464		XFree(wins);
1465}
1466
1467void
1468setclientstate(Client *c, long state) {
1469	long data[] = {state, None};
1470
1471	XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
1472			PropModeReplace, (unsigned char *)data, 2);
1473}
1474
1475void
1476setlayout(const char *arg) {
1477	unsigned int i;
1478	Monitor *m = &monitors[monitorat(-1, -1)];
1479
1480	if(!arg) {
1481		m->layout++;
1482		if(m->layout == &layouts[LENGTH(layouts)])
1483			m->layout = &layouts[0];
1484	}
1485	else {
1486		for(i = 0; i < LENGTH(layouts); i++)
1487			if(!strcmp(arg, layouts[i].symbol))
1488				break;
1489		if(i == LENGTH(layouts))
1490			return;
1491		m->layout = &layouts[i];
1492	}
1493	if(sel)
1494		arrange();
1495	else
1496		drawbar();
1497}
1498
1499void
1500setmwfact(const char *arg) {
1501	double delta;
1502
1503	Monitor *m = &monitors[monitorat(-1, -1)];
1504
1505	if(!domwfact)
1506		return;
1507	/* arg handling, manipulate mwfact */
1508	if(arg == NULL)
1509		m->mwfact = MWFACT;
1510	else if(sscanf(arg, "%lf", &delta) == 1) {
1511		if(arg[0] == '+' || arg[0] == '-')
1512			m->mwfact += delta;
1513		else
1514			m->mwfact = delta;
1515		if(m->mwfact < 0.1)
1516			m->mwfact = 0.1;
1517		else if(m->mwfact > 0.9)
1518			m->mwfact = 0.9;
1519	}
1520	arrange();
1521}
1522
1523void
1524setup(void) {
1525	unsigned int i, j, k;
1526	XModifierKeymap *modmap;
1527	XSetWindowAttributes wa;
1528	int s = 1;
1529	GC g;
1530	XineramaScreenInfo *info = NULL;
1531
1532	/* init atoms */
1533	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
1534	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
1535	wmatom[WMName] = XInternAtom(dpy, "WM_NAME", False);
1536	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
1537	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
1538	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
1539	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
1540			PropModeReplace, (unsigned char *) netatom, NetLast);
1541
1542	/* init cursors */
1543	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
1544	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
1545	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
1546
1547
1548	/* init modifier map */
1549	modmap = XGetModifierMapping(dpy);
1550	for(i = 0; i < 8; i++)
1551		for(j = 0; j < modmap->max_keypermod; j++) {
1552			if(modmap->modifiermap[i * modmap->max_keypermod + j]
1553			== XKeysymToKeycode(dpy, XK_Num_Lock))
1554				numlockmask = (1 << i);
1555		}
1556	XFreeModifiermap(modmap);
1557
1558	/* select for events */
1559	wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
1560		| EnterWindowMask | LeaveWindowMask | StructureNotifyMask;
1561	wa.cursor = cursor[CurNormal];
1562	XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
1563	XSelectInput(dpy, root, wa.event_mask);
1564
1565	/* grab keys */
1566	grabkeys();
1567
1568	/* init tags */
1569	compileregs();
1570
1571	if (XineramaIsActive(dpy)) {
1572		info = XineramaQueryScreens(dpy, &s);
1573	}
1574
1575	monitors = emallocz(s*sizeof(Monitor));
1576	mcount = s;
1577
1578	for(i = 0; i < s; i++) {
1579		/* init geometry */
1580		if (mcount != 1) {
1581			monitors[i].sx = info[i].x_org;
1582			monitors[i].sy = info[i].y_org;
1583			monitors[i].sw = info[i].width;
1584			monitors[i].sh = info[i].height;
1585		}
1586		else {
1587			monitors[i].sx = 0;
1588			monitors[i].sy = 0;
1589			monitors[i].sw = DisplayWidth(dpy, screen);
1590			monitors[i].sh = DisplayHeight(dpy, screen);
1591		}
1592
1593		monitors[i].id = i;
1594		monitors[i].seltags = emallocz(sizeof initags);
1595		monitors[i].prevtags = emallocz(sizeof initags);
1596
1597		memcpy(monitors[i].seltags, initags, sizeof initags);
1598		memcpy(monitors[i].prevtags, initags, sizeof initags);
1599
1600		/* init appearance */
1601		monitors[i].dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR);
1602		monitors[i].dc.norm[ColBG] = getcolor(NORMBGCOLOR);
1603		monitors[i].dc.norm[ColFG] = getcolor(NORMFGCOLOR);
1604		monitors[i].dc.sel[ColBorder] = getcolor(SELBORDERCOLOR);
1605		monitors[i].dc.sel[ColBG] = getcolor(SELBGCOLOR);
1606		monitors[i].dc.sel[ColFG] = getcolor(SELFGCOLOR);
1607		initfont(&(monitors[i]), FONT);
1608		monitors[i].dc.h = bh = monitors[i].dc.font.height + 2;
1609
1610		/* init layouts */
1611		monitors[i].mwfact = MWFACT;
1612		monitors[i].layout = &layouts[0];
1613		for(blw = k = 0; k < LENGTH(layouts); k++) {
1614			j = textw(&monitors[i], layouts[k].symbol);
1615			if(j > blw)
1616				blw = j;
1617		}
1618
1619		bpos = BARPOS;
1620		wa.override_redirect = 1;
1621		wa.background_pixmap = ParentRelative;
1622		wa.event_mask = ButtonPressMask | ExposureMask;
1623
1624		/* init bars */
1625		monitors[i].barwin = XCreateWindow(dpy, root, monitors[i].sx, monitors[i].sy, monitors[i].sw, bh, 0,
1626				DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
1627				CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
1628		XDefineCursor(dpy, monitors[i].barwin, cursor[CurNormal]);
1629		updatebarpos(&monitors[i]);
1630		XMapRaised(dpy, monitors[i].barwin);
1631		strcpy(stext, "dwm-"VERSION);
1632		monitors[i].dc.drawable = XCreatePixmap(dpy, root, monitors[i].sw, bh, DefaultDepth(dpy, screen));
1633		g = XCreateGC(dpy, root, 0, 0);
1634		monitors[i].dc.gc = XCreateGC(dpy, root, 0, 0);
1635		XSetLineAttributes(dpy, monitors[i].dc.gc, 1, LineSolid, CapButt, JoinMiter);
1636		if(!monitors[i].dc.font.set)
1637			XSetFont(dpy, monitors[i].dc.gc, monitors[i].dc.font.xfont->fid);
1638	}
1639}
1640
1641void
1642spawn(const char *arg) {
1643	static char *shell = NULL;
1644
1645	if(!shell && !(shell = getenv("SHELL")))
1646		shell = "/bin/sh";
1647	if(!arg)
1648		return;
1649	/* The double-fork construct avoids zombie processes and keeps the code
1650	 * clean from stupid signal handlers. */
1651	if(fork() == 0) {
1652		if(fork() == 0) {
1653			if(dpy)
1654				close(ConnectionNumber(dpy));
1655			setsid();
1656			execl(shell, shell, "-c", arg, (char *)NULL);
1657			fprintf(stderr, "dwm: execl '%s -c %s'", shell, arg);
1658			perror(" failed");
1659		}
1660		exit(0);
1661	}
1662	wait(0);
1663}
1664
1665void
1666tag(const char *arg) {
1667	unsigned int i;
1668
1669	if(!sel)
1670		return;
1671	for(i = 0; i < LENGTH(tags); i++)
1672		sel->tags[i] = (NULL == arg);
1673	sel->tags[idxoftag(arg)] = True;
1674	arrange();
1675}
1676
1677unsigned int
1678textnw(Monitor *m, const char *text, unsigned int len) {
1679	XRectangle r;
1680
1681	if(m->dc.font.set) {
1682		XmbTextExtents(m->dc.font.set, text, len, NULL, &r);
1683		return r.width;
1684	}
1685	return XTextWidth(m->dc.font.xfont, text, len);
1686}
1687
1688unsigned int
1689textw(Monitor *m, const char *text) {
1690	return textnw(m, text, strlen(text)) + m->dc.font.height;
1691}
1692
1693void
1694tile(void) {
1695	unsigned int i, n, nx, ny, nw, nh, mw, th;
1696	int s;
1697	Client *c, *mc;
1698
1699	domwfact = dozoom = True;
1700
1701	nw = 0; /* gcc stupidity requires this */
1702
1703	for (s = 0; s < mcount; s++) {
1704		Monitor *m = &monitors[s];
1705
1706		for(n = 0, c = nexttiled(clients, m); c; c = nexttiled(c->next, m))
1707			n++;
1708
1709		for(i = 0, c = mc = nexttiled(clients, m); c; c = nexttiled(c->next, m)) {
1710			/* window geoms */
1711			mw = (n == 1) ? m->waw : m->mwfact * m->waw;
1712			th = (n > 1) ? m->wah / (n - 1) : 0;
1713			if(n > 1 && th < bh)
1714				th = m->wah;
1715			if(i == 0) { /* master */
1716				nx = m->wax;
1717				ny = m->way;
1718				nw = mw - 2 * c->border;
1719				nh = m->wah - 2 * c->border;
1720			}
1721			else {  /* tile window */
1722				if(i == 1) {
1723					ny = m->way;
1724					nx += mc->w + 2 * mc->border;
1725					nw = m->waw - mw - 2 * c->border;
1726				}
1727				if(i + 1 == n) /* remainder */
1728					nh = (m->way + m->wah) - ny - 2 * c->border;
1729				else
1730					nh = th - 2 * c->border;
1731			}
1732			resize(c, nx, ny, nw, nh, RESIZEHINTS);
1733			if((RESIZEHINTS) && ((c->h < bh) || (c->h > nh) || (c->w < bh) || (c->w > nw)))
1734				/* client doesn't accept size constraints */
1735				resize(c, nx, ny, nw, nh, False);
1736			if(n > 1 && th != m->wah)
1737				ny = c->y + c->h + 2 * c->border;
1738
1739			i++;
1740		}
1741	}
1742}
1743void
1744togglebar(const char *arg) {
1745	if(bpos == BarOff)
1746		bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
1747	else
1748		bpos = BarOff;
1749	updatebarpos(&monitors[monitorat(-1,-1)]);
1750	arrange();
1751}
1752
1753void
1754togglefloating(const char *arg) {
1755	if(!sel)
1756		return;
1757	sel->isfloating = !sel->isfloating;
1758	if(sel->isfloating)
1759		resize(sel, sel->x, sel->y, sel->w, sel->h, True);
1760	arrange();
1761}
1762
1763void
1764toggletag(const char *arg) {
1765	unsigned int i, j;
1766
1767	if(!sel)
1768		return;
1769	i = idxoftag(arg);
1770	sel->tags[i] = !sel->tags[i];
1771	for(j = 0; j < LENGTH(tags) && !sel->tags[j]; j++);
1772	if(j == LENGTH(tags))
1773		sel->tags[i] = True; /* at least one tag must be enabled */
1774	arrange();
1775}
1776
1777void
1778toggleview(const char *arg) {
1779	unsigned int i, j;
1780
1781	Monitor *m = &monitors[monitorat(-1, -1)];
1782
1783	i = idxoftag(arg);
1784	m->seltags[i] = !m->seltags[i];
1785	for(j = 0; j < LENGTH(tags) && !m->seltags[j]; j++);
1786	if(j == LENGTH(tags))
1787		m->seltags[i] = True; /* at least one tag must be viewed */
1788	arrange();
1789}
1790
1791void
1792unban(Client *c) {
1793	if(!c->isbanned)
1794		return;
1795	XMoveWindow(dpy, c->win, c->x, c->y);
1796	c->isbanned = False;
1797}
1798
1799void
1800unmanage(Client *c) {
1801	XWindowChanges wc;
1802
1803	wc.border_width = c->oldborder;
1804	/* The server grab construct avoids race conditions. */
1805	XGrabServer(dpy);
1806	XSetErrorHandler(xerrordummy);
1807	XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
1808	detach(c);
1809	detachstack(c);
1810	if(sel == c)
1811		focus(NULL);
1812	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
1813	setclientstate(c, WithdrawnState);
1814	free(c->tags);
1815	free(c);
1816	XSync(dpy, False);
1817	XSetErrorHandler(xerror);
1818	XUngrabServer(dpy);
1819	arrange();
1820}
1821
1822void
1823unmapnotify(XEvent *e) {
1824	Client *c;
1825	XUnmapEvent *ev = &e->xunmap;
1826
1827	if((c = getclient(ev->window)))
1828		unmanage(c);
1829}
1830
1831void
1832updatebarpos(Monitor *s) {
1833	XEvent ev;
1834
1835	s->wax = s->sx;
1836	s->way = s->sy;
1837	s->wah = s->sh;
1838	s->waw = s->sw;
1839	switch(bpos) {
1840	default:
1841		s->wah -= bh;
1842		s->way += bh;
1843		XMoveWindow(dpy, s->barwin, s->sx, s->sy);
1844		break;
1845	case BarBot:
1846		s->wah -= bh;
1847		XMoveWindow(dpy, s->barwin, s->sx, s->sy + s->wah);
1848		break;
1849	case BarOff:
1850		XMoveWindow(dpy, s->barwin, s->sx, s->sy - bh);
1851		break;
1852	}
1853	XSync(dpy, False);
1854	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
1855}
1856
1857void
1858updatesizehints(Client *c) {
1859	long msize;
1860	XSizeHints size;
1861
1862	if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
1863		size.flags = PSize;
1864	c->flags = size.flags;
1865	if(c->flags & PBaseSize) {
1866		c->basew = size.base_width;
1867		c->baseh = size.base_height;
1868	}
1869	else if(c->flags & PMinSize) {
1870		c->basew = size.min_width;
1871		c->baseh = size.min_height;
1872	}
1873	else
1874		c->basew = c->baseh = 0;
1875	if(c->flags & PResizeInc) {
1876		c->incw = size.width_inc;
1877		c->inch = size.height_inc;
1878	}
1879	else
1880		c->incw = c->inch = 0;
1881	if(c->flags & PMaxSize) {
1882		c->maxw = size.max_width;
1883		c->maxh = size.max_height;
1884	}
1885	else
1886		c->maxw = c->maxh = 0;
1887	if(c->flags & PMinSize) {
1888		c->minw = size.min_width;
1889		c->minh = size.min_height;
1890	}
1891	else if(c->flags & PBaseSize) {
1892		c->minw = size.base_width;
1893		c->minh = size.base_height;
1894	}
1895	else
1896		c->minw = c->minh = 0;
1897	if(c->flags & PAspect) {
1898		c->minax = size.min_aspect.x;
1899		c->maxax = size.max_aspect.x;
1900		c->minay = size.min_aspect.y;
1901		c->maxay = size.max_aspect.y;
1902	}
1903	else
1904		c->minax = c->maxax = c->minay = c->maxay = 0;
1905	c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
1906			&& c->maxw == c->minw && c->maxh == c->minh);
1907}
1908
1909void
1910updatetitle(Client *c) {
1911	if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
1912		gettextprop(c->win, wmatom[WMName], c->name, sizeof c->name);
1913}
1914
1915/* There's no way to check accesses to destroyed windows, thus those cases are
1916 * ignored (especially on UnmapNotify's).  Other types of errors call Xlibs
1917 * default error handler, which may call exit.  */
1918int
1919xerror(Display *dpy, XErrorEvent *ee) {
1920	if(ee->error_code == BadWindow
1921	|| (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
1922	|| (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
1923	|| (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
1924	|| (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
1925	|| (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
1926	|| (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
1927	|| (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
1928		return 0;
1929	fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
1930		ee->request_code, ee->error_code);
1931	return xerrorxlib(dpy, ee); /* may call exit */
1932}
1933
1934int
1935xerrordummy(Display *dsply, XErrorEvent *ee) {
1936	return 0;
1937}
1938
1939/* Startup Error handler to check if another window manager
1940 * is already running. */
1941int
1942xerrorstart(Display *dsply, XErrorEvent *ee) {
1943	otherwm = True;
1944	return -1;
1945}
1946
1947void
1948view(const char *arg) {
1949	unsigned int i;
1950
1951	Monitor *m = &monitors[monitorat(-1, -1)];
1952
1953	memcpy(m->prevtags, m->seltags, sizeof initags);
1954	for(i = 0; i < LENGTH(tags); i++)
1955		m->seltags[i] = (NULL == arg);
1956	m->seltags[idxoftag(arg)] = True;
1957	arrange();
1958}
1959
1960void
1961viewprevtag(const char *arg) {
1962	static Bool tmp[LENGTH(tags)];
1963
1964	Monitor *m = &monitors[monitorat(-1, -1)];
1965
1966	memcpy(tmp, m->seltags, sizeof initags);
1967	memcpy(m->seltags, m->prevtags, sizeof initags);
1968	memcpy(m->prevtags, tmp, sizeof initags);
1969	arrange();
1970}
1971
1972void
1973zoom(const char *arg) {
1974	Client *c;
1975
1976	if(!sel || !dozoom || sel->isfloating)
1977		return;
1978	if((c = sel) == nexttiled(clients, &monitors[c->monitor]))
1979		if(!(c = nexttiled(c->next, &monitors[c->monitor])))
1980			return;
1981	detach(c);
1982	attach(c);
1983	focus(c);
1984	arrange();
1985}
1986
1987int
1988monitorat(int x, int y) {
1989	int i;
1990
1991	if(!XineramaIsActive(dpy))
1992		return 0;
1993
1994	if (x < 0 || y < 0) {
1995		Window win;
1996		unsigned int mask;
1997		XQueryPointer(dpy, root, &win, &win, &x, &y, &i, &i, &mask);
1998	}
1999
2000	for(i = 0; i < mcount; i++)
2001		if((x < 0 || (x >= monitors[i].sx && x < monitors[i].sx + monitors[i].sw))
2002				&& (y < 0 || (y >= monitors[i].sy && y < monitors[i].sy + monitors[i].sh)))
2003		{
2004			return i;
2005		}
2006	return 0;
2007}
2008
2009void
2010movetomonitor(const char *arg) {
2011	if (sel) {
2012		sel->monitor = arg ? atoi(arg) : (sel->monitor+1) % mcount;
2013
2014		memcpy(sel->tags, monitors[sel->monitor].seltags, sizeof initags);
2015		resize(sel, monitors[sel->monitor].wax, monitors[sel->monitor].way, sel->w, sel->h, True);
2016		arrange();
2017	}
2018}
2019
2020void
2021selectmonitor(const char *arg) {
2022	Monitor *m = &monitors[arg ? atoi(arg) : (monitorat(-1, -1)+1) % mcount];
2023
2024	XWarpPointer(dpy, None, root, 0, 0, 0, 0, m->wax+m->waw/2, m->way+m->wah/2);
2025	focus(NULL);
2026}
2027
2028
2029int
2030main(int argc, char *argv[]) {
2031	if(argc == 2 && !strcmp("-v", argv[1]))
2032		eprint("dwm-"VERSION", © 2006-2007 Anselm R. Garbe, Sander van Dijk, "
2033		       "Jukka Salmi, Premysl Hruby, Szabolcs Nagy\n");
2034	else if(argc != 1)
2035		eprint("usage: dwm [-v]\n");
2036
2037	setlocale(LC_CTYPE, "");
2038	if(!(dpy = XOpenDisplay(0)))
2039		eprint("dwm: cannot open display\n");
2040	screen = DefaultScreen(dpy);
2041	root = RootWindow(dpy, screen);
2042
2043	checkotherwm();
2044	setup();
2045	drawbar();
2046	scan();
2047	run();
2048	cleanup();
2049
2050	XCloseDisplay(dpy);
2051	return 0;
2052}