dwm.c
branchstil
changeset 1540 e8a43c5bbc46
parent 1538 6718f0ba24fd
parent 1539 e2a9bd720b6e
child 1541 16039d3a6270
equal deleted inserted replaced
1538:6718f0ba24fd 1540:e8a43c5bbc46
    45 #include <X11/extensions/Xinerama.h>
    45 #include <X11/extensions/Xinerama.h>
    46 #endif /* XINERAMA */
    46 #endif /* XINERAMA */
    47 
    47 
    48 /* macros */
    48 /* macros */
    49 #define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask)
    49 #define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask)
    50 #define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask))
    50 #define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
    51 #define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
    51 #define INTERSECT(x,y,w,h,m)    (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
       
    52                                * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
    52 #define ISVISIBLE(C)            ((C->tags & C->mon->tagset[C->mon->seltags]))
    53 #define ISVISIBLE(C)            ((C->tags & C->mon->tagset[C->mon->seltags]))
    53 #define LENGTH(X)               (sizeof X / sizeof X[0])
    54 #define LENGTH(X)               (sizeof X / sizeof X[0])
    54 #ifndef MAX
    55 #ifndef MAX
    55 #define MAX(A, B)               ((A) > (B) ? (A) : (B))
    56 #define MAX(A, B)               ((A) > (B) ? (A) : (B))
    56 #endif
    57 #endif
    66 
    67 
    67 /* enums */
    68 /* enums */
    68 enum { CurNormal, CurResize, CurMove, CurLast };        /* cursor */
    69 enum { CurNormal, CurResize, CurMove, CurLast };        /* cursor */
    69 enum { ColBorder, ColFG, ColBG, ColLast };              /* color */
    70 enum { ColBorder, ColFG, ColBG, ColLast };              /* color */
    70 enum { NetSupported, NetWMName, NetWMState,
    71 enum { NetSupported, NetWMName, NetWMState,
    71        NetWMFullscreen, NetLast };                      /* EWMH atoms */
    72        NetWMFullscreen, NetActiveWindow, NetWMWindowType,
    72 enum { WMProtocols, WMDelete, WMState, WMLast };        /* default atoms */
    73        NetWMWindowTypeDialog, NetLast };     /* EWMH atoms */
       
    74 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
    73 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
    75 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
    74        ClkClientWin, ClkRootWin, ClkLast };             /* clicks */
    76        ClkClientWin, ClkRootWin, ClkLast };             /* clicks */
    75 
    77 
    76 typedef union {
    78 typedef union {
    77 	int i;
    79 	int i;
    96 	int x, y, w, h;
    98 	int x, y, w, h;
    97 	int oldx, oldy, oldw, oldh;
    99 	int oldx, oldy, oldw, oldh;
    98 	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
   100 	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    99 	int bw, oldbw;
   101 	int bw, oldbw;
   100 	unsigned int tags;
   102 	unsigned int tags;
   101 	Bool isfixed, isfloating, isurgent, oldstate;
   103 	Bool isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
   102 	Client *next;
   104 	Client *next;
   103 	Client *snext;
   105 	Client *snext;
   104 	Monitor *mon;
   106 	Monitor *mon;
   105 	Window win;
   107 	Window win;
   106 };
   108 };
   135 
   137 
   136 typedef struct {
   138 typedef struct {
   137 	const char *symbol;
   139 	const char *symbol;
   138 	void (*arrange)(Monitor *);
   140 	void (*arrange)(Monitor *);
   139 } Layout;
   141 } Layout;
       
   142 
       
   143 struct Monitor {
       
   144 	char ltsymbol[16];
       
   145 	float mfact;
       
   146 	int nmaster;
       
   147 	int num;
       
   148 	int by;               /* bar geometry */
       
   149 	int mx, my, mw, mh;   /* screen size */
       
   150 	int wx, wy, ww, wh;   /* window area  */
       
   151 	unsigned int seltags;
       
   152 	unsigned int sellt;
       
   153 	unsigned int tagset[2];
       
   154 	Bool showbar;
       
   155 	Bool topbar;
       
   156 	Client *clients;
       
   157 	Client *sel;
       
   158 	Client *stack;
       
   159 	Monitor *next;
       
   160 	Window barwin;
       
   161 	const Layout *lt[2];
       
   162 };
   140 
   163 
   141 typedef struct {
   164 typedef struct {
   142 	const char *class;
   165 	const char *class;
   143 	const char *instance;
   166 	const char *instance;
   144 	const char *title;
   167 	const char *title;
   183 static Bool getrootptr(int *x, int *y);
   206 static Bool getrootptr(int *x, int *y);
   184 static long getstate(Window w);
   207 static long getstate(Window w);
   185 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   208 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   186 static void grabbuttons(Client *c, Bool focused);
   209 static void grabbuttons(Client *c, Bool focused);
   187 static void grabkeys(void);
   210 static void grabkeys(void);
       
   211 static void incnmaster(const Arg *arg);
   188 static void initfont(const char *fontstr);
   212 static void initfont(const char *fontstr);
   189 static Bool isprotodel(Client *c);
       
   190 static void keypress(XEvent *e);
   213 static void keypress(XEvent *e);
   191 static void killclient(const Arg *arg);
   214 static void killclient(const Arg *arg);
   192 static void manage(Window w, XWindowAttributes *wa);
   215 static void manage(Window w, XWindowAttributes *wa);
   193 static void mappingnotify(XEvent *e);
   216 static void mappingnotify(XEvent *e);
   194 static void maprequest(XEvent *e);
   217 static void maprequest(XEvent *e);
   195 static void monocle(Monitor *m);
   218 static void monocle(Monitor *m);
       
   219 static void motionnotify(XEvent *e);
   196 static void movemouse(const Arg *arg);
   220 static void movemouse(const Arg *arg);
   197 static Client *nexttiled(Client *c);
   221 static Client *nexttiled(Client *c);
   198 static Monitor *ptrtomon(int x, int y);
   222 static void pop(Client *);
   199 static void propertynotify(XEvent *e);
   223 static void propertynotify(XEvent *e);
   200 static void quit(const Arg *arg);
   224 static void quit(const Arg *arg);
       
   225 static Monitor *recttomon(int x, int y, int w, int h);
   201 static void resize(Client *c, int x, int y, int w, int h, Bool interact);
   226 static void resize(Client *c, int x, int y, int w, int h, Bool interact);
   202 static void resizeclient(Client *c, int x, int y, int w, int h);
   227 static void resizeclient(Client *c, int x, int y, int w, int h);
   203 static void resizemouse(const Arg *arg);
   228 static void resizemouse(const Arg *arg);
   204 static void restack(Monitor *m);
   229 static void restack(Monitor *m);
   205 static void run(void);
   230 static void run(void);
   206 static void scan(void);
   231 static void scan(void);
       
   232 static Bool sendevent(Client *c, Atom proto);
   207 static void sendmon(Client *c, Monitor *m);
   233 static void sendmon(Client *c, Monitor *m);
   208 static void setclientstate(Client *c, long state);
   234 static void setclientstate(Client *c, long state);
       
   235 static void setfocus(Client *c);
       
   236 static void setfullscreen(Client *c, Bool fullscreen);
   209 static void setlayout(const Arg *arg);
   237 static void setlayout(const Arg *arg);
   210 static void setmfact(const Arg *arg);
   238 static void setmfact(const Arg *arg);
   211 static void setup(void);
   239 static void setup(void);
   212 static void showhide(Client *c);
   240 static void showhide(Client *c);
   213 static void sigchld(int unused);
   241 static void sigchld(int unused);
   227 static void updatebarpos(Monitor *m);
   255 static void updatebarpos(Monitor *m);
   228 static void updatebars(void);
   256 static void updatebars(void);
   229 static void updatenumlockmask(void);
   257 static void updatenumlockmask(void);
   230 static void updatesizehints(Client *c);
   258 static void updatesizehints(Client *c);
   231 static void updatestatus(void);
   259 static void updatestatus(void);
       
   260 static void updatewindowtype(Client *c);
   232 static void updatetitle(Client *c);
   261 static void updatetitle(Client *c);
   233 static void updatewmhints(Client *c);
   262 static void updatewmhints(Client *c);
   234 static void view(const Arg *arg);
   263 static void view(const Arg *arg);
   235 static Client *wintoclient(Window w);
   264 static Client *wintoclient(Window w);
   236 static Monitor *wintomon(Window w);
   265 static Monitor *wintomon(Window w);
   257 	[Expose] = expose,
   286 	[Expose] = expose,
   258 	[FocusIn] = focusin,
   287 	[FocusIn] = focusin,
   259 	[KeyPress] = keypress,
   288 	[KeyPress] = keypress,
   260 	[MappingNotify] = mappingnotify,
   289 	[MappingNotify] = mappingnotify,
   261 	[MapRequest] = maprequest,
   290 	[MapRequest] = maprequest,
       
   291 	[MotionNotify] = motionnotify,
   262 	[PropertyNotify] = propertynotify,
   292 	[PropertyNotify] = propertynotify,
   263 	[UnmapNotify] = unmapnotify
   293 	[UnmapNotify] = unmapnotify
   264 };
   294 };
   265 static Atom wmatom[WMLast], netatom[NetLast];
   295 static Atom wmatom[WMLast], netatom[NetLast];
   266 static Bool running = True;
   296 static Bool running = True;
   311 applyrules(Client *c) {
   341 applyrules(Client *c) {
   312 	const char *class, *instance;
   342 	const char *class, *instance;
   313 	unsigned int i;
   343 	unsigned int i;
   314 	const Rule *r;
   344 	const Rule *r;
   315 	Monitor *m;
   345 	Monitor *m;
   316 	XClassHint ch = { 0 };
   346 	XClassHint ch = { NULL, NULL };
   317 
   347 
   318 	/* rule matching */
   348 	/* rule matching */
   319 	c->isfloating = c->tags = 0;
   349 	c->isfloating = c->tags = 0;
   320 	if(XGetClassHint(dpy, c->win, &ch)) {
   350 	XGetClassHint(dpy, c->win, &ch);
   321 		class = ch.res_class ? ch.res_class : broken;
   351 	class    = ch.res_class ? ch.res_class : broken;
   322 		instance = ch.res_name ? ch.res_name : broken;
   352 	instance = ch.res_name  ? ch.res_name  : broken;
   323 		for(i = 0; i < LENGTH(rules); i++) {
   353 
   324 			r = &rules[i];
   354 	for(i = 0; i < LENGTH(rules); i++) {
   325 			if((!r->title || strstr(c->name, r->title))
   355 		r = &rules[i];
   326 			&& (!r->class || strstr(class, r->class))
   356 		if((!r->title || strstr(c->name, r->title))
   327 			&& (!r->instance || strstr(instance, r->instance)))
   357 		&& (!r->class || strstr(class, r->class))
   328 			{
   358 		&& (!r->instance || strstr(instance, r->instance)))
   329 				c->isfloating = r->isfloating;
   359 		{
   330 				c->tags |= r->tags;
   360 			c->isfloating = r->isfloating;
   331 				for(m = mons; m && m->num != r->monitor; m = m->next);
   361 			c->tags |= r->tags;
   332 				if(m)
   362 			for(m = mons; m && m->num != r->monitor; m = m->next);
   333 					c->mon = m;
   363 			if(m)
   334 			}
   364 				c->mon = m;
   335 		}
   365 		}
   336 		if(ch.res_class)
   366 	}
   337 			XFree(ch.res_class);
   367 	if(ch.res_class)
   338 		if(ch.res_name)
   368 		XFree(ch.res_class);
   339 			XFree(ch.res_name);
   369 	if(ch.res_name)
   340 	}
   370 		XFree(ch.res_name);
   341 	c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
   371 	c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
   342 }
   372 }
   343 
   373 
   344 Bool
   374 Bool
   345 applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) {
   375 applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) {
   358 			*x = 0;
   388 			*x = 0;
   359 		if(*y + *h + 2 * c->bw < 0)
   389 		if(*y + *h + 2 * c->bw < 0)
   360 			*y = 0;
   390 			*y = 0;
   361 	}
   391 	}
   362 	else {
   392 	else {
   363 		if(*x > m->mx + m->mw)
   393 		if(*x >= m->wx + m->ww)
   364 			*x = m->mx + m->mw - WIDTH(c);
   394 			*x = m->wx + m->ww - WIDTH(c);
   365 		if(*y > m->my + m->mh)
   395 		if(*y >= m->wy + m->wh)
   366 			*y = m->my + m->mh - HEIGHT(c);
   396 			*y = m->wy + m->wh - HEIGHT(c);
   367 		if(*x + *w + 2 * c->bw < m->mx)
   397 		if(*x + *w + 2 * c->bw <= m->wx)
   368 			*x = m->mx;
   398 			*x = m->wx;
   369 		if(*y + *h + 2 * c->bw < m->my)
   399 		if(*y + *h + 2 * c->bw <= m->wy)
   370 			*y = m->my;
   400 			*y = m->wy;
   371 	}
   401 	}
   372 	if(*h < bh)
   402 	if(*h < bh)
   373 		*h = bh;
   403 		*h = bh;
   374 	if(*w < bh)
   404 	if(*w < bh)
   375 		*w = bh;
   405 		*w = bh;
   376 	if(resizehints || c->isfloating) {
   406 	if(resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
   377 		/* see last two sentences in ICCCM 4.1.2.3 */
   407 		/* see last two sentences in ICCCM 4.1.2.3 */
   378 		baseismin = c->basew == c->minw && c->baseh == c->minh;
   408 		baseismin = c->basew == c->minw && c->baseh == c->minh;
   379 		if(!baseismin) { /* temporarily remove base dimensions */
   409 		if(!baseismin) { /* temporarily remove base dimensions */
   380 			*w -= c->basew;
   410 			*w -= c->basew;
   381 			*h -= c->baseh;
   411 			*h -= c->baseh;
   411 arrange(Monitor *m) {
   441 arrange(Monitor *m) {
   412 	if(m)
   442 	if(m)
   413 		showhide(m->stack);
   443 		showhide(m->stack);
   414 	else for(m = mons; m; m = m->next)
   444 	else for(m = mons; m; m = m->next)
   415 		showhide(m->stack);
   445 		showhide(m->stack);
   416 	focus(NULL);
       
   417 	if(m)
   446 	if(m)
   418 		arrangemon(m);
   447 		arrangemon(m);
   419 	else for(m = mons; m; m = m->next)
   448 	else for(m = mons; m; m = m->next)
   420 		arrangemon(m);
   449 		arrangemon(m);
   421 }
   450 }
   455 		selmon = m;
   484 		selmon = m;
   456 		focus(NULL);
   485 		focus(NULL);
   457 	}
   486 	}
   458 	if(ev->window == selmon->barwin) {
   487 	if(ev->window == selmon->barwin) {
   459 		i = x = 0;
   488 		i = x = 0;
   460 		do {
   489 		do
   461 			x += TEXTW(tags[i]);
   490 			x += TEXTW(tags[i]);
   462 		} while(ev->x >= x && ++i < LENGTH(tags));
   491 		while(ev->x >= x && ++i < LENGTH(tags));
   463 		if(i < LENGTH(tags)) {
   492 		if(i < LENGTH(tags)) {
   464 			click = ClkTagBar;
   493 			click = ClkTagBar;
   465 			arg.ui = 1 << i;
   494 			arg.ui = 1 << i;
   466 		}
   495 		}
   467 		else if(ev->x < x + blw)
   496 		else if(ev->x < x + blw)
   468 			click = ClkLtSymbol;
   497 			click = ClkLtSymbol;
   469 		else if(ev->x > selmon->wx + selmon->ww - TEXTWM(stext))
   498 		else if(ev->x > selmon->ww - TEXTWM(stext))
   470 			click = ClkStatusText;
   499 			click = ClkStatusText;
   471 		else
   500 		else
   472 			click = ClkWinTitle;
   501 			click = ClkWinTitle;
   473 	}
   502 	}
   474 	else if((c = wintoclient(ev->window))) {
   503 	else if((c = wintoclient(ev->window))) {
   540 	XSetWMHints(dpy, c->win, wmh);
   569 	XSetWMHints(dpy, c->win, wmh);
   541 	XFree(wmh);
   570 	XFree(wmh);
   542 }
   571 }
   543 
   572 
   544 void
   573 void
       
   574 clientmessage(XEvent *e) {
       
   575 	XClientMessageEvent *cme = &e->xclient;
       
   576 	Client *c = wintoclient(cme->window);
       
   577 
       
   578 	if(!c)
       
   579 		return;
       
   580 	if(cme->message_type == netatom[NetWMState]) {
       
   581 		if(cme->data.l[1] == netatom[NetWMFullscreen] || cme->data.l[2] == netatom[NetWMFullscreen])
       
   582 			setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD    */
       
   583 			              || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
       
   584 	}
       
   585 	else if(cme->message_type == netatom[NetActiveWindow]) {
       
   586 		if(!ISVISIBLE(c)) {
       
   587 			c->mon->seltags ^= 1;
       
   588 			c->mon->tagset[c->mon->seltags] = c->tags;
       
   589 		}
       
   590 		pop(c);
       
   591 	}
       
   592 }
       
   593 
       
   594 void
   545 configure(Client *c) {
   595 configure(Client *c) {
   546 	XConfigureEvent ce;
   596 	XConfigureEvent ce;
   547 
   597 
   548 	ce.type = ConfigureNotify;
   598 	ce.type = ConfigureNotify;
   549 	ce.display = dpy;
   599 	ce.display = dpy;
   561 
   611 
   562 void
   612 void
   563 configurenotify(XEvent *e) {
   613 configurenotify(XEvent *e) {
   564 	Monitor *m;
   614 	Monitor *m;
   565 	XConfigureEvent *ev = &e->xconfigure;
   615 	XConfigureEvent *ev = &e->xconfigure;
       
   616 	Bool dirty;
   566 
   617 
   567 	if(ev->window == root) {
   618 	if(ev->window == root) {
       
   619 		dirty = (sw != ev->width);
   568 		sw = ev->width;
   620 		sw = ev->width;
   569 		sh = ev->height;
   621 		sh = ev->height;
   570 		if(updategeom()) {
   622 		if(updategeom() || dirty) {
   571 			if(dc.drawable != 0)
   623 			if(dc.drawable != 0)
   572 				XFreePixmap(dpy, dc.drawable);
   624 				XFreePixmap(dpy, dc.drawable);
   573 			dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
   625 			dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
   574 			XftDrawChange(dc.xftdrawable, dc.drawable);
   626 			XftDrawChange(dc.xftdrawable, dc.drawable);
   575 			updatebars();
   627 			updatebars();
   576 			for(m = mons; m; m = m->next)
   628 			for(m = mons; m; m = m->next)
   577 				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
   629 				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
       
   630 			focus(NULL);
   578 			arrange(NULL);
   631 			arrange(NULL);
   579 		}
   632 		}
   580 	}
   633 	}
   581 }
   634 }
   582 
   635 
   590 	if((c = wintoclient(ev->window))) {
   643 	if((c = wintoclient(ev->window))) {
   591 		if(ev->value_mask & CWBorderWidth)
   644 		if(ev->value_mask & CWBorderWidth)
   592 			c->bw = ev->border_width;
   645 			c->bw = ev->border_width;
   593 		else if(c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
   646 		else if(c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
   594 			m = c->mon;
   647 			m = c->mon;
   595 			if(ev->value_mask & CWX)
   648 			if(ev->value_mask & CWX) {
       
   649 				c->oldx = c->x;
   596 				c->x = m->mx + ev->x;
   650 				c->x = m->mx + ev->x;
   597 			if(ev->value_mask & CWY)
   651 			}
       
   652 			if(ev->value_mask & CWY) {
       
   653 				c->oldy = c->y;
   598 				c->y = m->my + ev->y;
   654 				c->y = m->my + ev->y;
   599 			if(ev->value_mask & CWWidth)
   655 			}
       
   656 			if(ev->value_mask & CWWidth) {
       
   657 				c->oldw = c->w;
   600 				c->w = ev->width;
   658 				c->w = ev->width;
   601 			if(ev->value_mask & CWHeight)
   659 			}
       
   660 			if(ev->value_mask & CWHeight) {
       
   661 				c->oldh = c->h;
   602 				c->h = ev->height;
   662 				c->h = ev->height;
       
   663 			}
   603 			if((c->x + c->w) > m->mx + m->mw && c->isfloating)
   664 			if((c->x + c->w) > m->mx + m->mw && c->isfloating)
   604 				c->x = m->mx + (m->mw / 2 - c->w / 2); /* center in x direction */
   665 				c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */
   605 			if((c->y + c->h) > m->my + m->mh && c->isfloating)
   666 			if((c->y + c->h) > m->my + m->mh && c->isfloating)
   606 				c->y = m->my + (m->mh / 2 - c->h / 2); /* center in y direction */
   667 				c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */
   607 			if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
   668 			if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
   608 				configure(c);
   669 				configure(c);
   609 			if(ISVISIBLE(c))
   670 			if(ISVISIBLE(c))
   610 				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
   671 				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
   611 		}
   672 		}
   632 
   693 
   633 	if(!(m = (Monitor *)calloc(1, sizeof(Monitor))))
   694 	if(!(m = (Monitor *)calloc(1, sizeof(Monitor))))
   634 		die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
   695 		die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
   635 	m->tagset[0] = m->tagset[1] = 1;
   696 	m->tagset[0] = m->tagset[1] = 1;
   636 	m->mfact = mfact;
   697 	m->mfact = mfact;
       
   698 	m->nmaster = nmaster;
   637 	m->showbar = showbar;
   699 	m->showbar = showbar;
   638 	m->topbar = topbar;
   700 	m->topbar = topbar;
   639 	m->lt[0] = &layouts[0];
   701 	m->lt[0] = &layouts[0];
   640 	m->lt[1] = &layouts[1 % LENGTH(layouts)];
   702 	m->lt[1] = &layouts[1 % LENGTH(layouts)];
   641 	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
   703 	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
   697 
   759 
   698 	if(dir > 0) {
   760 	if(dir > 0) {
   699 		if(!(m = selmon->next))
   761 		if(!(m = selmon->next))
   700 			m = mons;
   762 			m = mons;
   701 	}
   763 	}
   702 	else {
   764 	else if(selmon == mons)
   703 		if(selmon == mons)
   765 		for(m = mons; m->next; m = m->next);
   704 			for(m = mons; m->next; m = m->next);
   766 	else
   705 		else
   767 		for(m = mons; m->next != selmon; m = m->next);
   706 			for(m = mons; m->next != selmon; m = m->next);
       
   707 	}
       
   708 	return m;
   768 	return m;
   709 }
   769 }
   710 
   770 
   711 void
   771 void
   712 drawbar(Monitor *m) {
   772 drawbar(Monitor *m) {
   767 }
   827 }
   768 
   828 
   769 void
   829 void
   770 drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
   830 drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
   771 	int x;
   831 	int x;
   772 	XGCValues gcv;
   832 
   773 	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
   833 	XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]);
   774 
       
   775 	gcv.foreground = col[invert ? ColBG : ColFG];
       
   776 	XChangeGC(dpy, dc.gc, GCForeground, &gcv);
       
   777 	x = (dc.font.ascent + dc.font.descent + 2) / 4;
   834 	x = (dc.font.ascent + dc.font.descent + 2) / 4;
   778 	r.x = dc.x + 1;
   835 	if(filled)
   779 	r.y = dc.y + 1;
   836 		XFillRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x+1, x+1);
   780 	if(filled) {
   837 	else if(empty)
   781 		r.width = r.height = x + 1;
   838 		XDrawRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x, x);
   782 		XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
       
   783 	}
       
   784 	else if(empty) {
       
   785 		r.width = r.height = x;
       
   786 		XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
       
   787 	}
       
   788 }
   839 }
   789 
   840 
   790 void
   841 void
   791 drawtext(const char *text, unsigned long col[ColLast], Bool invert, Bool markup) {
   842 drawtext(const char *text, unsigned long col[ColLast], Bool invert, Bool markup) {
   792 	char buf[256];
   843 	char buf[256];
   793 	int i, x, y, h, len, olen;
   844 	int i, x, y, h, len, olen;
   794 	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
       
   795 
   845 
   796 	XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]);
   846 	XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]);
   797 	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
   847 	XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.w, dc.h);
   798 	if(!text)
   848 	if(!text)
   799 		return;
   849 		return;
   800 	olen = strlen(text);
   850 	olen = strlen(text);
   801 	h = dc.font.ascent + dc.font.descent;
   851 	h = dc.font.ascent + dc.font.descent;
   802 	//y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
   852 	//y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
   816 	pango_xft_render_layout(dc.xftdrawable, (col==dc.norm?dc.xftnorm:dc.xftsel)+(invert?ColBG:ColFG), dc.plo, x * PANGO_SCALE, y * PANGO_SCALE);
   866 	pango_xft_render_layout(dc.xftdrawable, (col==dc.norm?dc.xftnorm:dc.xftsel)+(invert?ColBG:ColFG), dc.plo, x * PANGO_SCALE, y * PANGO_SCALE);
   817 }
   867 }
   818 
   868 
   819 void
   869 void
   820 enternotify(XEvent *e) {
   870 enternotify(XEvent *e) {
       
   871 	Client *c;
   821 	Monitor *m;
   872 	Monitor *m;
   822 	XCrossingEvent *ev = &e->xcrossing;
   873 	XCrossingEvent *ev = &e->xcrossing;
   823 
   874 
   824 	if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
   875 	if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
   825 		return;
   876 		return;
   826 	if((m = wintomon(ev->window)) && m != selmon) {
   877 	c = wintoclient(ev->window);
       
   878 	m = c ? c->mon : wintomon(ev->window);
       
   879 	if(m != selmon) {
   827 		unfocus(selmon->sel, True);
   880 		unfocus(selmon->sel, True);
   828 		selmon = m;
   881 		selmon = m;
   829 	}
   882 	}
   830 	focus((wintoclient(ev->window)));
   883 	else if(!c || c == selmon->sel)
       
   884 		return;
       
   885 	focus(c);
   831 }
   886 }
   832 
   887 
   833 void
   888 void
   834 expose(XEvent *e) {
   889 expose(XEvent *e) {
   835 	Monitor *m;
   890 	Monitor *m;
   853 			clearurgent(c);
   908 			clearurgent(c);
   854 		detachstack(c);
   909 		detachstack(c);
   855 		attachstack(c);
   910 		attachstack(c);
   856 		grabbuttons(c, True);
   911 		grabbuttons(c, True);
   857 		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
   912 		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
   858 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
   913 		setfocus(c);
   859 	}
   914 	}
   860 	else
   915 	else
   861 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
   916 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
   862 	selmon->sel = c;
   917 	selmon->sel = c;
   863 	drawbars();
   918 	drawbars();
   866 void
   921 void
   867 focusin(XEvent *e) { /* there are some broken focus acquiring clients */
   922 focusin(XEvent *e) { /* there are some broken focus acquiring clients */
   868 	XFocusChangeEvent *ev = &e->xfocus;
   923 	XFocusChangeEvent *ev = &e->xfocus;
   869 
   924 
   870 	if(selmon->sel && ev->window != selmon->sel->win)
   925 	if(selmon->sel && ev->window != selmon->sel->win)
   871 		XSetInputFocus(dpy, selmon->sel->win, RevertToPointerRoot, CurrentTime);
   926 		setfocus(selmon->sel);
   872 }
   927 }
   873 
   928 
   874 void
   929 void
   875 focusmon(const Arg *arg) {
   930 focusmon(const Arg *arg) {
   876 	Monitor *m;
   931 	Monitor *m;
   906 	}
   961 	}
   907 	if(c) {
   962 	if(c) {
   908 		focus(c);
   963 		focus(c);
   909 		restack(selmon);
   964 		restack(selmon);
   910 	}
   965 	}
       
   966 }
       
   967 
       
   968 Atom
       
   969 getatomprop(Client *c, Atom prop) {
       
   970 	int di;
       
   971 	unsigned long dl;
       
   972 	unsigned char *p = NULL;
       
   973 	Atom da, atom = None;
       
   974 
       
   975 	if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
       
   976 	                      &da, &di, &dl, &dl, &p) == Success && p) {
       
   977 		atom = *(Atom *)p;
       
   978 		XFree(p);
       
   979 	}
       
   980 	return atom;
   911 }
   981 }
   912 
   982 
   913 unsigned long
   983 unsigned long
   914 getcolor(const char *colstr, XftColor *color) {
   984 getcolor(const char *colstr, XftColor *color) {
   915 	Colormap cmap = DefaultColormap(dpy, screen);
   985 	Colormap cmap = DefaultColormap(dpy, screen);
  1000 		unsigned int i, j;
  1070 		unsigned int i, j;
  1001 		unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
  1071 		unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
  1002 		KeyCode code;
  1072 		KeyCode code;
  1003 
  1073 
  1004 		XUngrabKey(dpy, AnyKey, AnyModifier, root);
  1074 		XUngrabKey(dpy, AnyKey, AnyModifier, root);
  1005 		for(i = 0; i < LENGTH(keys); i++) {
  1075 		for(i = 0; i < LENGTH(keys); i++)
  1006 			if((code = XKeysymToKeycode(dpy, keys[i].keysym)))
  1076 			if((code = XKeysymToKeycode(dpy, keys[i].keysym)))
  1007 				for(j = 0; j < LENGTH(modifiers); j++)
  1077 				for(j = 0; j < LENGTH(modifiers); j++)
  1008 					XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
  1078 					XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
  1009 						 True, GrabModeAsync, GrabModeAsync);
  1079 						 True, GrabModeAsync, GrabModeAsync);
  1010 		}
  1080 	}
  1011 	}
  1081 }
       
  1082 
       
  1083 void
       
  1084 incnmaster(const Arg *arg) {
       
  1085 	selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
       
  1086 	arrange(selmon);
  1012 }
  1087 }
  1013 
  1088 
  1014 void
  1089 void
  1015 initfont(const char *fontstr) {
  1090 initfont(const char *fontstr) {
  1016 	PangoFontMetrics *metrics;
  1091 	PangoFontMetrics *metrics;
  1025 	pango_font_metrics_unref(metrics);
  1100 	pango_font_metrics_unref(metrics);
  1026 
  1101 
  1027 	dc.plo = pango_layout_new(dc.pgc);
  1102 	dc.plo = pango_layout_new(dc.pgc);
  1028 	pango_layout_set_font_description(dc.plo, dc.pfd);
  1103 	pango_layout_set_font_description(dc.plo, dc.pfd);
  1029 	dc.font.height = dc.font.ascent + dc.font.descent;
  1104 	dc.font.height = dc.font.ascent + dc.font.descent;
  1030 }
       
  1031 
       
  1032 Bool
       
  1033 isprotodel(Client *c) {
       
  1034 	int n;
       
  1035 	Atom *protocols;
       
  1036 	Bool ret = False;
       
  1037 
       
  1038 	if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
       
  1039 		while(!ret && n--)
       
  1040 			ret = protocols[n] == wmatom[WMDelete];
       
  1041 		XFree(protocols);
       
  1042 	}
       
  1043 	return ret;
       
  1044 }
  1105 }
  1045 
  1106 
  1046 #ifdef XINERAMA
  1107 #ifdef XINERAMA
  1047 static Bool
  1108 static Bool
  1048 isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) {
  1109 isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) {
  1069 			keys[i].func(&(keys[i].arg));
  1130 			keys[i].func(&(keys[i].arg));
  1070 }
  1131 }
  1071 
  1132 
  1072 void
  1133 void
  1073 killclient(const Arg *arg) {
  1134 killclient(const Arg *arg) {
  1074 	XEvent ev;
       
  1075 
       
  1076 	if(!selmon->sel)
  1135 	if(!selmon->sel)
  1077 		return;
  1136 		return;
  1078 	if(isprotodel(selmon->sel)) {
  1137 	if(!sendevent(selmon->sel, wmatom[WMDelete])) {
  1079 		ev.type = ClientMessage;
       
  1080 		ev.xclient.window = selmon->sel->win;
       
  1081 		ev.xclient.message_type = wmatom[WMProtocols];
       
  1082 		ev.xclient.format = 32;
       
  1083 		ev.xclient.data.l[0] = wmatom[WMDelete];
       
  1084 		ev.xclient.data.l[1] = CurrentTime;
       
  1085 		XSendEvent(dpy, selmon->sel->win, False, NoEventMask, &ev);
       
  1086 	}
       
  1087 	else {
       
  1088 		XGrabServer(dpy);
  1138 		XGrabServer(dpy);
  1089 		XSetErrorHandler(xerrordummy);
  1139 		XSetErrorHandler(xerrordummy);
  1090 		XSetCloseDownMode(dpy, DestroyAll);
  1140 		XSetCloseDownMode(dpy, DestroyAll);
  1091 		XKillClient(dpy, selmon->sel->win);
  1141 		XKillClient(dpy, selmon->sel->win);
  1092 		XSync(dpy, False);
  1142 		XSync(dpy, False);
  1112 	else {
  1162 	else {
  1113 		c->mon = selmon;
  1163 		c->mon = selmon;
  1114 		applyrules(c);
  1164 		applyrules(c);
  1115 	}
  1165 	}
  1116 	/* geometry */
  1166 	/* geometry */
  1117 	c->x = c->oldx = wa->x + c->mon->wx;
  1167 	c->x = c->oldx = wa->x;
  1118 	c->y = c->oldy = wa->y + c->mon->wy;
  1168 	c->y = c->oldy = wa->y;
  1119 	c->w = c->oldw = wa->width;
  1169 	c->w = c->oldw = wa->width;
  1120 	c->h = c->oldh = wa->height;
  1170 	c->h = c->oldh = wa->height;
  1121 	c->oldbw = wa->border_width;
  1171 	c->oldbw = wa->border_width;
  1122 	if(c->w == c->mon->mw && c->h == c->mon->mh) {
  1172 
  1123 		c->isfloating = True;
  1173 	if(c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
  1124 		c->x = c->mon->mx;
  1174 		c->x = c->mon->mx + c->mon->mw - WIDTH(c);
  1125 		c->y = c->mon->my;
  1175 	if(c->y + HEIGHT(c) > c->mon->my + c->mon->mh)
  1126 		c->bw = 0;
  1176 		c->y = c->mon->my + c->mon->mh - HEIGHT(c);
  1127 	}
  1177 	c->x = MAX(c->x, c->mon->mx);
  1128 	else {
  1178 	/* only fix client y-offset, if the client center might cover the bar */
  1129 		if(c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
  1179 	c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
  1130 			c->x = c->mon->mx + c->mon->mw - WIDTH(c);
  1180 	           && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
  1131 		if(c->y + HEIGHT(c) > c->mon->my + c->mon->mh)
  1181 	c->bw = borderpx;
  1132 			c->y = c->mon->my + c->mon->mh - HEIGHT(c);
  1182 
  1133 		c->x = MAX(c->x, c->mon->mx);
       
  1134 		/* only fix client y-offset, if the client center might cover the bar */
       
  1135 		c->y = MAX(c->y, ((c->mon->by == 0) && (c->x + (c->w / 2) >= c->mon->wx)
       
  1136 		           && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
       
  1137 		c->bw = borderpx;
       
  1138 	}
       
  1139 	wc.border_width = c->bw;
  1183 	wc.border_width = c->bw;
  1140 	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
  1184 	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
  1141 	XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
  1185 	XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
  1142 	configure(c); /* propagates border_width, if size doesn't change */
  1186 	configure(c); /* propagates border_width, if size doesn't change */
       
  1187 	updatewindowtype(c);
  1143 	updatesizehints(c);
  1188 	updatesizehints(c);
       
  1189 	updatewmhints(c);
  1144 	XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
  1190 	XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
  1145 	grabbuttons(c, False);
  1191 	grabbuttons(c, False);
  1146 	if(!c->isfloating)
  1192 	if(!c->isfloating)
  1147 		c->isfloating = c->oldstate = trans != None || c->isfixed;
  1193 		c->isfloating = c->oldstate = trans != None || c->isfixed;
  1148 	if(c->isfloating)
  1194 	if(c->isfloating)
  1149 		XRaiseWindow(dpy, c->win);
  1195 		XRaiseWindow(dpy, c->win);
  1150 	attach(c);
  1196 	attach(c);
  1151 	attachstack(c);
  1197 	attachstack(c);
  1152 	XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
  1198 	XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
       
  1199 	setclientstate(c, NormalState);
       
  1200 	if (c->mon == selmon)
       
  1201 		unfocus(selmon->sel, False);
       
  1202 	c->mon->sel = c;
       
  1203 	arrange(c->mon);
  1153 	XMapWindow(dpy, c->win);
  1204 	XMapWindow(dpy, c->win);
  1154 	setclientstate(c, NormalState);
  1205 	focus(NULL);
  1155 	arrange(c->mon);
       
  1156 }
  1206 }
  1157 
  1207 
  1158 void
  1208 void
  1159 mappingnotify(XEvent *e) {
  1209 mappingnotify(XEvent *e) {
  1160 	XMappingEvent *ev = &e->xmapping;
  1210 	XMappingEvent *ev = &e->xmapping;
  1190 	for(c = nexttiled(m->clients); c; c = nexttiled(c->next))
  1240 	for(c = nexttiled(m->clients); c; c = nexttiled(c->next))
  1191 		resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False);
  1241 		resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False);
  1192 }
  1242 }
  1193 
  1243 
  1194 void
  1244 void
       
  1245 motionnotify(XEvent *e) {
       
  1246 	static Monitor *mon = NULL;
       
  1247 	Monitor *m;
       
  1248 	XMotionEvent *ev = &e->xmotion;
       
  1249 
       
  1250 	if(ev->window != root)
       
  1251 		return;
       
  1252 	if((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
       
  1253 		selmon = m;
       
  1254 		focus(NULL);
       
  1255 	}
       
  1256 	mon = m;
       
  1257 }
       
  1258 
       
  1259 void
  1195 movemouse(const Arg *arg) {
  1260 movemouse(const Arg *arg) {
  1196 	int x, y, ocx, ocy, nx, ny;
  1261 	int x, y, ocx, ocy, nx, ny;
  1197 	Client *c;
  1262 	Client *c;
  1198 	Monitor *m;
  1263 	Monitor *m;
  1199 	XEvent ev;
  1264 	XEvent ev;
  1208 		return;
  1273 		return;
  1209 	if(!getrootptr(&x, &y))
  1274 	if(!getrootptr(&x, &y))
  1210 		return;
  1275 		return;
  1211 	do {
  1276 	do {
  1212 		XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
  1277 		XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
  1213 		switch (ev.type) {
  1278 		switch(ev.type) {
  1214 		case ConfigureRequest:
  1279 		case ConfigureRequest:
  1215 		case Expose:
  1280 		case Expose:
  1216 		case MapRequest:
  1281 		case MapRequest:
  1217 			handler[ev.type](&ev);
  1282 			handler[ev.type](&ev);
  1218 			break;
  1283 			break;
  1219 		case MotionNotify:
  1284 		case MotionNotify:
  1220 			nx = ocx + (ev.xmotion.x - x);
  1285 			nx = ocx + (ev.xmotion.x - x);
  1221 			ny = ocy + (ev.xmotion.y - y);
  1286 			ny = ocy + (ev.xmotion.y - y);
  1222 			if(snap && nx >= selmon->wx && nx <= selmon->wx + selmon->ww
  1287 			if(nx >= selmon->wx && nx <= selmon->wx + selmon->ww
  1223 			&& ny >= selmon->wy && ny <= selmon->wy + selmon->wh) {
  1288 			&& ny >= selmon->wy && ny <= selmon->wy + selmon->wh) {
  1224 				if(abs(selmon->wx - nx) < snap)
  1289 				if(abs(selmon->wx - nx) < snap)
  1225 					nx = selmon->wx;
  1290 					nx = selmon->wx;
  1226 				else if(abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
  1291 				else if(abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
  1227 					nx = selmon->wx + selmon->ww - WIDTH(c);
  1292 					nx = selmon->wx + selmon->ww - WIDTH(c);
  1237 				resize(c, nx, ny, c->w, c->h, True);
  1302 				resize(c, nx, ny, c->w, c->h, True);
  1238 			break;
  1303 			break;
  1239 		}
  1304 		}
  1240 	} while(ev.type != ButtonRelease);
  1305 	} while(ev.type != ButtonRelease);
  1241 	XUngrabPointer(dpy, CurrentTime);
  1306 	XUngrabPointer(dpy, CurrentTime);
  1242 	if((m = ptrtomon(c->x + c->w / 2, c->y + c->h / 2)) != selmon) {
  1307 	if((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
  1243 		sendmon(c, m);
  1308 		sendmon(c, m);
  1244 		selmon = m;
  1309 		selmon = m;
  1245 		focus(NULL);
  1310 		focus(NULL);
  1246 	}
  1311 	}
  1247 }
  1312 }
  1250 nexttiled(Client *c) {
  1315 nexttiled(Client *c) {
  1251 	for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
  1316 	for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
  1252 	return c;
  1317 	return c;
  1253 }
  1318 }
  1254 
  1319 
  1255 Monitor *
  1320 void
  1256 ptrtomon(int x, int y) {
  1321 pop(Client *c) {
  1257 	Monitor *m;
  1322 	detach(c);
  1258 
  1323 	attach(c);
  1259 	for(m = mons; m; m = m->next)
  1324 	focus(c);
  1260 		if(INRECT(x, y, m->wx, m->wy, m->ww, m->wh))
  1325 	arrange(c->mon);
  1261 			return m;
       
  1262 	return selmon;
       
  1263 }
  1326 }
  1264 
  1327 
  1265 void
  1328 void
  1266 propertynotify(XEvent *e) {
  1329 propertynotify(XEvent *e) {
  1267 	Client *c;
  1330 	Client *c;
  1271 	if((ev->window == root) && (ev->atom == XA_WM_NAME))
  1334 	if((ev->window == root) && (ev->atom == XA_WM_NAME))
  1272 		updatestatus();
  1335 		updatestatus();
  1273 	else if(ev->state == PropertyDelete)
  1336 	else if(ev->state == PropertyDelete)
  1274 		return; /* ignore */
  1337 		return; /* ignore */
  1275 	else if((c = wintoclient(ev->window))) {
  1338 	else if((c = wintoclient(ev->window))) {
  1276 		switch (ev->atom) {
  1339 		switch(ev->atom) {
  1277 		default: break;
  1340 		default: break;
  1278 		case XA_WM_TRANSIENT_FOR:
  1341 		case XA_WM_TRANSIENT_FOR:
  1279 			if(!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
  1342 			if(!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
  1280 			   (c->isfloating = (wintoclient(trans)) != NULL))
  1343 			   (c->isfloating = (wintoclient(trans)) != NULL))
  1281 				arrange(c->mon);
  1344 				arrange(c->mon);
  1291 		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
  1354 		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
  1292 			updatetitle(c);
  1355 			updatetitle(c);
  1293 			if(c == c->mon->sel)
  1356 			if(c == c->mon->sel)
  1294 				drawbar(c->mon);
  1357 				drawbar(c->mon);
  1295 		}
  1358 		}
  1296 	}
  1359 		if(ev->atom == netatom[NetWMWindowType])
  1297 }
  1360 			updatewindowtype(c);
  1298 
       
  1299 void
       
  1300 clientmessage(XEvent *e) {
       
  1301 	XClientMessageEvent *cme = &e->xclient;
       
  1302 	Client *c;
       
  1303 
       
  1304 	if((c = wintoclient(cme->window))
       
  1305 	&& (cme->message_type == netatom[NetWMState] && cme->data.l[1] == netatom[NetWMFullscreen]))
       
  1306 	{
       
  1307 		if(cme->data.l[0]) {
       
  1308 			XChangeProperty(dpy, cme->window, netatom[NetWMState], XA_ATOM, 32,
       
  1309 			                PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
       
  1310 			c->oldstate = c->isfloating;
       
  1311 			c->oldbw = c->bw;
       
  1312 			c->bw = 0;
       
  1313 			c->isfloating = True;
       
  1314 			resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
       
  1315 			XRaiseWindow(dpy, c->win);
       
  1316 		}
       
  1317 		else {
       
  1318 			XChangeProperty(dpy, cme->window, netatom[NetWMState], XA_ATOM, 32,
       
  1319 			                PropModeReplace, (unsigned char*)0, 0);
       
  1320 			c->isfloating = c->oldstate;
       
  1321 			c->bw = c->oldbw;
       
  1322 			c->x = c->oldx;
       
  1323 			c->y = c->oldy;
       
  1324 			c->w = c->oldw;
       
  1325 			c->h = c->oldh;
       
  1326 			resizeclient(c, c->x, c->y, c->w, c->h);
       
  1327 			arrange(c->mon);
       
  1328 		}
       
  1329 	}
  1361 	}
  1330 }
  1362 }
  1331 
  1363 
  1332 void
  1364 void
  1333 quit(const Arg *arg) {
  1365 quit(const Arg *arg) {
  1334 	running = False;
  1366 	running = False;
       
  1367 }
       
  1368 
       
  1369 Monitor *
       
  1370 recttomon(int x, int y, int w, int h) {
       
  1371 	Monitor *m, *r = selmon;
       
  1372 	int a, area = 0;
       
  1373 
       
  1374 	for(m = mons; m; m = m->next)
       
  1375 		if((a = INTERSECT(x, y, w, h, m)) > area) {
       
  1376 			area = a;
       
  1377 			r = m;
       
  1378 		}
       
  1379 	return r;
  1335 }
  1380 }
  1336 
  1381 
  1337 void
  1382 void
  1338 resize(Client *c, int x, int y, int w, int h, Bool interact) {
  1383 resize(Client *c, int x, int y, int w, int h, Bool interact) {
  1339 	if(applysizehints(c, &x, &y, &w, &h, interact))
  1384 	if(applysizehints(c, &x, &y, &w, &h, interact))
  1380 			handler[ev.type](&ev);
  1425 			handler[ev.type](&ev);
  1381 			break;
  1426 			break;
  1382 		case MotionNotify:
  1427 		case MotionNotify:
  1383 			nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
  1428 			nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
  1384 			nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
  1429 			nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
  1385 			if(snap && nw >= selmon->wx && nw <= selmon->wx + selmon->ww
  1430 			if(c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
  1386 			&& nh >= selmon->wy && nh <= selmon->wy + selmon->wh)
  1431 			&& c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh)
  1387 			{
  1432 			{
  1388 				if(!c->isfloating && selmon->lt[selmon->sellt]->arrange
  1433 				if(!c->isfloating && selmon->lt[selmon->sellt]->arrange
  1389 				&& (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
  1434 				&& (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
  1390 					togglefloating(NULL);
  1435 					togglefloating(NULL);
  1391 			}
  1436 			}
  1395 		}
  1440 		}
  1396 	} while(ev.type != ButtonRelease);
  1441 	} while(ev.type != ButtonRelease);
  1397 	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
  1442 	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
  1398 	XUngrabPointer(dpy, CurrentTime);
  1443 	XUngrabPointer(dpy, CurrentTime);
  1399 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  1444 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  1400 	if((m = ptrtomon(c->x + c->w / 2, c->y + c->h / 2)) != selmon) {
  1445 	if((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
  1401 		sendmon(c, m);
  1446 		sendmon(c, m);
  1402 		selmon = m;
  1447 		selmon = m;
  1403 		focus(NULL);
  1448 		focus(NULL);
  1404 	}
  1449 	}
  1405 }
  1450 }
  1431 void
  1476 void
  1432 run(void) {
  1477 run(void) {
  1433 	XEvent ev;
  1478 	XEvent ev;
  1434 	/* main event loop */
  1479 	/* main event loop */
  1435 	XSync(dpy, False);
  1480 	XSync(dpy, False);
  1436 	while(running && !XNextEvent(dpy, &ev)) {
  1481 	while(running && !XNextEvent(dpy, &ev))
  1437 		if(handler[ev.type])
  1482 		if(handler[ev.type])
  1438 			handler[ev.type](&ev); /* call handler */
  1483 			handler[ev.type](&ev); /* call handler */
  1439 	}
       
  1440 }
  1484 }
  1441 
  1485 
  1442 void
  1486 void
  1443 scan(void) {
  1487 scan(void) {
  1444 	unsigned int i, num;
  1488 	unsigned int i, num;
  1484 setclientstate(Client *c, long state) {
  1528 setclientstate(Client *c, long state) {
  1485 	long data[] = { state, None };
  1529 	long data[] = { state, None };
  1486 
  1530 
  1487 	XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
  1531 	XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
  1488 			PropModeReplace, (unsigned char *)data, 2);
  1532 			PropModeReplace, (unsigned char *)data, 2);
       
  1533 }
       
  1534 
       
  1535 Bool
       
  1536 sendevent(Client *c, Atom proto) {
       
  1537 	int n;
       
  1538 	Atom *protocols;
       
  1539 	Bool exists = False;
       
  1540 	XEvent ev;
       
  1541 
       
  1542 	if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
       
  1543 		while(!exists && n--)
       
  1544 			exists = protocols[n] == proto;
       
  1545 		XFree(protocols);
       
  1546 	}
       
  1547 	if(exists) {
       
  1548 		ev.type = ClientMessage;
       
  1549 		ev.xclient.window = c->win;
       
  1550 		ev.xclient.message_type = wmatom[WMProtocols];
       
  1551 		ev.xclient.format = 32;
       
  1552 		ev.xclient.data.l[0] = proto;
       
  1553 		ev.xclient.data.l[1] = CurrentTime;
       
  1554 		XSendEvent(dpy, c->win, False, NoEventMask, &ev);
       
  1555 	}
       
  1556 	return exists;
       
  1557 }
       
  1558 
       
  1559 void
       
  1560 setfocus(Client *c) {
       
  1561 	if(!c->neverfocus)
       
  1562 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
       
  1563 	sendevent(c, wmatom[WMTakeFocus]);
       
  1564 }
       
  1565 
       
  1566 void
       
  1567 setfullscreen(Client *c, Bool fullscreen) {
       
  1568 	if(fullscreen) {
       
  1569 		XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
       
  1570 		                PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
       
  1571 		c->isfullscreen = True;
       
  1572 		c->oldstate = c->isfloating;
       
  1573 		c->oldbw = c->bw;
       
  1574 		c->bw = 0;
       
  1575 		c->isfloating = True;
       
  1576 		resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
       
  1577 		XRaiseWindow(dpy, c->win);
       
  1578 	}
       
  1579 	else {
       
  1580 		XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
       
  1581 		                PropModeReplace, (unsigned char*)0, 0);
       
  1582 		c->isfullscreen = False;
       
  1583 		c->isfloating = c->oldstate;
       
  1584 		c->bw = c->oldbw;
       
  1585 		c->x = c->oldx;
       
  1586 		c->y = c->oldy;
       
  1587 		c->w = c->oldw;
       
  1588 		c->h = c->oldh;
       
  1589 		resizeclient(c, c->x, c->y, c->w, c->h);
       
  1590 		arrange(c->mon);
       
  1591 	}
  1489 }
  1592 }
  1490 
  1593 
  1491 void
  1594 void
  1492 setlayout(const Arg *arg) {
  1595 setlayout(const Arg *arg) {
  1493 	if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
  1596 	if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
  1532 	updategeom();
  1635 	updategeom();
  1533 	/* init atoms */
  1636 	/* init atoms */
  1534 	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  1637 	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  1535 	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  1638 	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  1536 	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
  1639 	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
       
  1640 	wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
       
  1641 	netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
  1537 	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
  1642 	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
  1538 	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
  1643 	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
  1539 	netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
  1644 	netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
  1540 	netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
  1645 	netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
       
  1646 	netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
       
  1647 	netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
  1541 	/* init cursors */
  1648 	/* init cursors */
  1542 	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
  1649 	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
  1543 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
  1650 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
  1544 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
  1651 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
  1545 	/* init appearance */
  1652 	/* init appearance */
  1560 	/* EWMH support per view */
  1667 	/* EWMH support per view */
  1561 	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
  1668 	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
  1562 			PropModeReplace, (unsigned char *) netatom, NetLast);
  1669 			PropModeReplace, (unsigned char *) netatom, NetLast);
  1563 	/* select for events */
  1670 	/* select for events */
  1564 	wa.cursor = cursor[CurNormal];
  1671 	wa.cursor = cursor[CurNormal];
  1565 	wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask
  1672 	wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask
  1566 	                |EnterWindowMask|LeaveWindowMask|StructureNotifyMask
  1673 	                |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
  1567 	                |PropertyChangeMask;
       
  1568 	XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
  1674 	XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
  1569 	XSelectInput(dpy, root, wa.event_mask);
  1675 	XSelectInput(dpy, root, wa.event_mask);
  1570 	grabkeys();
  1676 	grabkeys();
  1571 }
  1677 }
  1572 
  1678 
  1574 showhide(Client *c) {
  1680 showhide(Client *c) {
  1575 	if(!c)
  1681 	if(!c)
  1576 		return;
  1682 		return;
  1577 	if(ISVISIBLE(c)) { /* show clients top down */
  1683 	if(ISVISIBLE(c)) { /* show clients top down */
  1578 		XMoveWindow(dpy, c->win, c->x, c->y);
  1684 		XMoveWindow(dpy, c->win, c->x, c->y);
  1579 		if(!c->mon->lt[c->mon->sellt]->arrange || c->isfloating)
  1685 		if((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen)
  1580 			resize(c, c->x, c->y, c->w, c->h, False);
  1686 			resize(c, c->x, c->y, c->w, c->h, False);
  1581 		showhide(c->snext);
  1687 		showhide(c->snext);
  1582 	}
  1688 	}
  1583 	else { /* hide clients bottom up */
  1689 	else { /* hide clients bottom up */
  1584 		showhide(c->snext);
  1690 		showhide(c->snext);
  1585 		XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
  1691 		XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
  1586 	}
  1692 	}
  1587 }
  1693 }
  1588 
  1694 
  1589 void
  1695 void
  1590 sigchld(int unused) {
  1696 sigchld(int unused) {
  1602 		if (munlockall())
  1708 		if (munlockall())
  1603 		    perror("munlockall()");
  1709 		    perror("munlockall()");
  1604 		execvp(((char **)arg->v)[0], (char **)arg->v);
  1710 		execvp(((char **)arg->v)[0], (char **)arg->v);
  1605 		fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
  1711 		fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
  1606 		perror(" failed");
  1712 		perror(" failed");
  1607 		exit(0);
  1713 		exit(EXIT_SUCCESS);
  1608 	}
  1714 	}
  1609 }
  1715 }
  1610 
  1716 
  1611 void
  1717 void
  1612 tag(const Arg *arg) {
  1718 tag(const Arg *arg) {
  1613 	if(selmon->sel && arg->ui & TAGMASK) {
  1719 	if(selmon->sel && arg->ui & TAGMASK) {
  1614 		selmon->sel->tags = arg->ui & TAGMASK;
  1720 		selmon->sel->tags = arg->ui & TAGMASK;
       
  1721 		focus(NULL);
  1615 		arrange(selmon);
  1722 		arrange(selmon);
  1616 	}
  1723 	}
  1617 }
  1724 }
  1618 
  1725 
  1619 void
  1726 void
  1636 	return r.width / PANGO_SCALE;
  1743 	return r.width / PANGO_SCALE;
  1637 }
  1744 }
  1638 
  1745 
  1639 void
  1746 void
  1640 tile(Monitor *m) {
  1747 tile(Monitor *m) {
  1641 	int x, y, h, w, mw;
  1748 	unsigned int i, n, h, mw, my, ty;
  1642 	unsigned int i, n;
       
  1643 	Client *c;
  1749 	Client *c;
  1644 
  1750 
  1645 	for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
  1751 	for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
  1646 	if(n == 0)
  1752 	if(n == 0)
  1647 		return;
  1753 		return;
  1648 	/* master */
  1754 
  1649 	c = nexttiled(m->clients);
  1755 	if(n > m->nmaster)
  1650 	mw = m->mfact * m->ww;
  1756 		mw = m->nmaster ? m->ww * m->mfact : 0;
  1651 	resize(c, m->wx, m->wy, (n == 1 ? m->ww : mw) - 2 * c->bw, m->wh - 2 * c->bw, False);
  1757 	else
  1652 	if(--n == 0)
  1758 		mw = m->ww;
  1653 		return;
  1759 	for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
  1654 	/* tile stack */
  1760 		if(i < m->nmaster) {
  1655 	x = (m->wx + mw > c->x + c->w) ? c->x + c->w + 2 * c->bw : m->wx + mw;
  1761 			h = (m->wh - my) / (MIN(n, m->nmaster) - i);
  1656 	y = m->wy;
  1762 			resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False);
  1657 	w = (m->wx + mw > c->x + c->w) ? m->wx + m->ww - x : m->ww - mw;
  1763 			my += HEIGHT(c);
  1658 	h = m->wh / n;
  1764 		}
  1659 	if(h < bh)
  1765 		else {
  1660 		h = m->wh;
  1766 			h = (m->wh - ty) / (n - i);
  1661 	for(i = 0, c = nexttiled(c->next); c; c = nexttiled(c->next), i++) {
  1767 			resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), False);
  1662 		resize(c, x, y, w - 2 * c->bw, /* remainder */ ((i + 1 == n)
  1768 			ty += HEIGHT(c);
  1663 		       ? m->wy + m->wh - y - 2 * c->bw : h - 2 * c->bw), False);
  1769 		}
  1664 		if(h != m->wh)
       
  1665 			y = c->y + HEIGHT(c);
       
  1666 	}
       
  1667 }
  1770 }
  1668 
  1771 
  1669 void
  1772 void
  1670 togglebar(const Arg *arg) {
  1773 togglebar(const Arg *arg) {
  1671 	selmon->showbar = selmon->showbars[selmon->curtag] = !selmon->showbar;
  1774 	selmon->showbar = selmon->showbars[selmon->curtag] = !selmon->showbar;
  1707 		selmon->sel->tags = newtags;
  1810 		selmon->sel->tags = newtags;
  1708 		selmon->lt[selmon->sellt] = selmon->lts[selmon->curtag];
  1811 		selmon->lt[selmon->sellt] = selmon->lts[selmon->curtag];
  1709 		selmon->mfact = selmon->mfacts[selmon->curtag];
  1812 		selmon->mfact = selmon->mfacts[selmon->curtag];
  1710 		if (selmon->showbar != selmon->showbars[selmon->curtag])
  1813 		if (selmon->showbar != selmon->showbars[selmon->curtag])
  1711 			togglebar(NULL);
  1814 			togglebar(NULL);
       
  1815 		focus(NULL);
  1712 		arrange(selmon);
  1816 		arrange(selmon);
  1713 	}
  1817 	}
  1714 }
  1818 }
  1715 
  1819 
  1716 void
  1820 void
  1717 toggleview(const Arg *arg) {
  1821 toggleview(const Arg *arg) {
  1718 	unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
  1822 	unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
  1719 
  1823 
  1720 	if(newtagset) {
  1824 	if(newtagset) {
  1721 		selmon->tagset[selmon->seltags] = newtagset;
  1825 		selmon->tagset[selmon->seltags] = newtagset;
       
  1826 		focus(NULL);
  1722 		arrange(selmon);
  1827 		arrange(selmon);
  1723 	}
  1828 	}
  1724 }
  1829 }
  1725 
  1830 
  1726 void
  1831 void
  1760 void
  1865 void
  1761 unmapnotify(XEvent *e) {
  1866 unmapnotify(XEvent *e) {
  1762 	Client *c;
  1867 	Client *c;
  1763 	XUnmapEvent *ev = &e->xunmap;
  1868 	XUnmapEvent *ev = &e->xunmap;
  1764 
  1869 
  1765 	if((c = wintoclient(ev->window)))
  1870 	if((c = wintoclient(ev->window))) {
  1766 		unmanage(c, False);
  1871 		if(ev->send_event)
       
  1872 			setclientstate(c, WithdrawnState);
       
  1873 		else
       
  1874 			unmanage(c, False);
       
  1875 	}
  1767 }
  1876 }
  1768 
  1877 
  1769 void
  1878 void
  1770 updatebars(void) {
  1879 updatebars(void) {
  1771 	Monitor *m;
  1880 	Monitor *m;
  1772 	XSetWindowAttributes wa;
  1881 	XSetWindowAttributes wa = {
  1773 
  1882 		.override_redirect = True,
  1774 	wa.override_redirect = True;
  1883 		.background_pixmap = ParentRelative,
  1775 	wa.background_pixmap = ParentRelative;
  1884 		.event_mask = ButtonPressMask|ExposureMask
  1776 	wa.event_mask = ButtonPressMask|ExposureMask;
  1885 	};
  1777 	for(m = mons; m; m = m->next) {
  1886 	for(m = mons; m; m = m->next) {
  1778 		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
  1887 		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
  1779 		                          CopyFromParent, DefaultVisual(dpy, screen),
  1888 		                          CopyFromParent, DefaultVisual(dpy, screen),
  1780 		                          CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
  1889 		                          CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
  1781 		XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
  1890 		XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
  1957 		strcpy(stext, "dwm-"VERSION);
  2066 		strcpy(stext, "dwm-"VERSION);
  1958 	drawbar(selmon);
  2067 	drawbar(selmon);
  1959 }
  2068 }
  1960 
  2069 
  1961 void
  2070 void
       
  2071 updatewindowtype(Client *c) {
       
  2072 	Atom state = getatomprop(c, netatom[NetWMState]);
       
  2073 	Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
       
  2074 
       
  2075 	if(state == netatom[NetWMFullscreen])
       
  2076 		setfullscreen(c, True);
       
  2077 
       
  2078 	if(wtype == netatom[NetWMWindowTypeDialog])
       
  2079 		c->isfloating = True;
       
  2080 }
       
  2081 
       
  2082 void
  1962 updatewmhints(Client *c) {
  2083 updatewmhints(Client *c) {
  1963 	XWMHints *wmh;
  2084 	XWMHints *wmh;
  1964 
  2085 
  1965 	if((wmh = XGetWMHints(dpy, c->win))) {
  2086 	if((wmh = XGetWMHints(dpy, c->win))) {
  1966 		if(c == selmon->sel && wmh->flags & XUrgencyHint) {
  2087 		if(c == selmon->sel && wmh->flags & XUrgencyHint) {
  1967 			wmh->flags &= ~XUrgencyHint;
  2088 			wmh->flags &= ~XUrgencyHint;
  1968 			XSetWMHints(dpy, c->win, wmh);
  2089 			XSetWMHints(dpy, c->win, wmh);
  1969 		}
  2090 		}
  1970 		else
  2091 		else
  1971 			c->isurgent = (wmh->flags & XUrgencyHint) ? True : False;
  2092 			c->isurgent = (wmh->flags & XUrgencyHint) ? True : False;
       
  2093 		if(wmh->flags & InputHint)
       
  2094 			c->neverfocus = !wmh->input;
       
  2095 		else
       
  2096 			c->neverfocus = False;
  1972 		XFree(wmh);
  2097 		XFree(wmh);
  1973 	}
  2098 	}
  1974 }
  2099 }
  1975 
  2100 
  1976 void
  2101 void
  1996 	}
  2121 	}
  1997 	selmon->lt[selmon->sellt]= selmon->lts[selmon->curtag];
  2122 	selmon->lt[selmon->sellt]= selmon->lts[selmon->curtag];
  1998 	selmon->mfact = selmon->mfacts[selmon->curtag];
  2123 	selmon->mfact = selmon->mfacts[selmon->curtag];
  1999 	if(selmon->showbar != selmon->showbars[selmon->curtag])
  2124 	if(selmon->showbar != selmon->showbars[selmon->curtag])
  2000 		togglebar(NULL);
  2125 		togglebar(NULL);
       
  2126 	focus(NULL);
  2001 	arrange(selmon);
  2127 	arrange(selmon);
  2002 }
  2128 }
  2003 
  2129 
  2004 Client *
  2130 Client *
  2005 wintoclient(Window w) {
  2131 wintoclient(Window w) {
  2018 	int x, y;
  2144 	int x, y;
  2019 	Client *c;
  2145 	Client *c;
  2020 	Monitor *m;
  2146 	Monitor *m;
  2021 
  2147 
  2022 	if(w == root && getrootptr(&x, &y))
  2148 	if(w == root && getrootptr(&x, &y))
  2023 		return ptrtomon(x, y);
  2149 		return recttomon(x, y, 1, 1);
  2024 	for(m = mons; m; m = m->next)
  2150 	for(m = mons; m; m = m->next)
  2025 		if(w == m->barwin)
  2151 		if(w == m->barwin)
  2026 			return m;
  2152 			return m;
  2027 	if((c = wintoclient(w)))
  2153 	if((c = wintoclient(w)))
  2028 		return c->mon;
  2154 		return c->mon;
  2065 void
  2191 void
  2066 zoom(const Arg *arg) {
  2192 zoom(const Arg *arg) {
  2067 	Client *c = selmon->sel;
  2193 	Client *c = selmon->sel;
  2068 
  2194 
  2069 	if(!selmon->lt[selmon->sellt]->arrange
  2195 	if(!selmon->lt[selmon->sellt]->arrange
  2070 	|| selmon->lt[selmon->sellt]->arrange == monocle
       
  2071 	|| (selmon->sel && selmon->sel->isfloating))
  2196 	|| (selmon->sel && selmon->sel->isfloating))
  2072 		return;
  2197 		return;
  2073 	if(c == nexttiled(selmon->clients))
  2198 	if(c == nexttiled(selmon->clients))
  2074 		if(!c || !(c = nexttiled(c->next)))
  2199 		if(!c || !(c = nexttiled(c->next)))
  2075 			return;
  2200 			return;
  2076 	detach(c);
  2201 	pop(c);
  2077 	attach(c);
       
  2078 	focus(c);
       
  2079 	arrange(c->mon);
       
  2080 }
  2202 }
  2081 
  2203 
  2082 int
  2204 int
  2083 main(int argc, char *argv[]) {
  2205 main(int argc, char *argv[]) {
  2084 	if(argc == 2 && !strcmp("-v", argv[1]))
  2206 	if(argc == 2 && !strcmp("-v", argv[1]))
  2085 		die("dwm-"VERSION", © 2006-2010 dwm engineers, see LICENSE for details\n");
  2207 		die("dwm-"VERSION", © 2006-2011 dwm engineers, see LICENSE for details\n");
  2086 	else if(argc != 1)
  2208 	else if(argc != 1)
  2087 		die("usage: dwm [-v]\n");
  2209 		die("usage: dwm [-v]\n");
  2088 	if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
  2210 	if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
  2089 		fputs("warning: no locale support\n", stderr);
  2211 		fputs("warning: no locale support\n", stderr);
  2090 	if(!(dpy = XOpenDisplay(NULL)))
  2212 	if(!(dpy = XOpenDisplay(NULL)))
  2095 	setup();
  2217 	setup();
  2096 	scan();
  2218 	scan();
  2097 	run();
  2219 	run();
  2098 	cleanup();
  2220 	cleanup();
  2099 	XCloseDisplay(dpy);
  2221 	XCloseDisplay(dpy);
  2100 	return 0;
  2222 	return EXIT_SUCCESS;
  2101 }
  2223 }