dwm.c
changeset 1539 e2a9bd720b6e
parent 1530 072c62ed10f2
child 1540 e8a43c5bbc46
equal deleted inserted replaced
1530:072c62ed10f2 1539:e2a9bd720b6e
    40 #include <X11/extensions/Xinerama.h>
    40 #include <X11/extensions/Xinerama.h>
    41 #endif /* XINERAMA */
    41 #endif /* XINERAMA */
    42 
    42 
    43 /* macros */
    43 /* macros */
    44 #define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask)
    44 #define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask)
    45 #define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask))
    45 #define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
    46 #define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
    46 #define INTERSECT(x,y,w,h,m)    (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
       
    47                                * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
    47 #define ISVISIBLE(C)            ((C->tags & C->mon->tagset[C->mon->seltags]))
    48 #define ISVISIBLE(C)            ((C->tags & C->mon->tagset[C->mon->seltags]))
    48 #define LENGTH(X)               (sizeof X / sizeof X[0])
    49 #define LENGTH(X)               (sizeof X / sizeof X[0])
    49 #define MAX(A, B)               ((A) > (B) ? (A) : (B))
    50 #define MAX(A, B)               ((A) > (B) ? (A) : (B))
    50 #define MIN(A, B)               ((A) < (B) ? (A) : (B))
    51 #define MIN(A, B)               ((A) < (B) ? (A) : (B))
    51 #define MOUSEMASK               (BUTTONMASK|PointerMotionMask)
    52 #define MOUSEMASK               (BUTTONMASK|PointerMotionMask)
    56 
    57 
    57 /* enums */
    58 /* enums */
    58 enum { CurNormal, CurResize, CurMove, CurLast };        /* cursor */
    59 enum { CurNormal, CurResize, CurMove, CurLast };        /* cursor */
    59 enum { ColBorder, ColFG, ColBG, ColLast };              /* color */
    60 enum { ColBorder, ColFG, ColBG, ColLast };              /* color */
    60 enum { NetSupported, NetWMName, NetWMState,
    61 enum { NetSupported, NetWMName, NetWMState,
    61        NetWMFullscreen, NetLast };                      /* EWMH atoms */
    62        NetWMFullscreen, NetActiveWindow, NetWMWindowType,
    62 enum { WMProtocols, WMDelete, WMState, WMLast };        /* default atoms */
    63        NetWMWindowTypeDialog, NetLast };     /* EWMH atoms */
       
    64 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
    63 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
    65 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
    64        ClkClientWin, ClkRootWin, ClkLast };             /* clicks */
    66        ClkClientWin, ClkRootWin, ClkLast };             /* clicks */
    65 
    67 
    66 typedef union {
    68 typedef union {
    67 	int i;
    69 	int i;
    86 	int x, y, w, h;
    88 	int x, y, w, h;
    87 	int oldx, oldy, oldw, oldh;
    89 	int oldx, oldy, oldw, oldh;
    88 	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    90 	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    89 	int bw, oldbw;
    91 	int bw, oldbw;
    90 	unsigned int tags;
    92 	unsigned int tags;
    91 	Bool isfixed, isfloating, isurgent, oldstate;
    93 	Bool isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
    92 	Client *next;
    94 	Client *next;
    93 	Client *snext;
    95 	Client *snext;
    94 	Monitor *mon;
    96 	Monitor *mon;
    95 	Window win;
    97 	Window win;
    96 };
    98 };
   123 } Layout;
   125 } Layout;
   124 
   126 
   125 struct Monitor {
   127 struct Monitor {
   126 	char ltsymbol[16];
   128 	char ltsymbol[16];
   127 	float mfact;
   129 	float mfact;
       
   130 	int nmaster;
   128 	int num;
   131 	int num;
   129 	int by;               /* bar geometry */
   132 	int by;               /* bar geometry */
   130 	int mx, my, mw, mh;   /* screen size */
   133 	int mx, my, mw, mh;   /* screen size */
   131 	int wx, wy, ww, wh;   /* window area  */
   134 	int wx, wy, ww, wh;   /* window area  */
   132 	unsigned int seltags;
   135 	unsigned int seltags;
   187 static Bool getrootptr(int *x, int *y);
   190 static Bool getrootptr(int *x, int *y);
   188 static long getstate(Window w);
   191 static long getstate(Window w);
   189 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   192 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
   190 static void grabbuttons(Client *c, Bool focused);
   193 static void grabbuttons(Client *c, Bool focused);
   191 static void grabkeys(void);
   194 static void grabkeys(void);
       
   195 static void incnmaster(const Arg *arg);
   192 static void initfont(const char *fontstr);
   196 static void initfont(const char *fontstr);
   193 static Bool isprotodel(Client *c);
       
   194 static void keypress(XEvent *e);
   197 static void keypress(XEvent *e);
   195 static void killclient(const Arg *arg);
   198 static void killclient(const Arg *arg);
   196 static void manage(Window w, XWindowAttributes *wa);
   199 static void manage(Window w, XWindowAttributes *wa);
   197 static void mappingnotify(XEvent *e);
   200 static void mappingnotify(XEvent *e);
   198 static void maprequest(XEvent *e);
   201 static void maprequest(XEvent *e);
   199 static void monocle(Monitor *m);
   202 static void monocle(Monitor *m);
       
   203 static void motionnotify(XEvent *e);
   200 static void movemouse(const Arg *arg);
   204 static void movemouse(const Arg *arg);
   201 static Client *nexttiled(Client *c);
   205 static Client *nexttiled(Client *c);
   202 static Monitor *ptrtomon(int x, int y);
   206 static void pop(Client *);
   203 static void propertynotify(XEvent *e);
   207 static void propertynotify(XEvent *e);
   204 static void quit(const Arg *arg);
   208 static void quit(const Arg *arg);
       
   209 static Monitor *recttomon(int x, int y, int w, int h);
   205 static void resize(Client *c, int x, int y, int w, int h, Bool interact);
   210 static void resize(Client *c, int x, int y, int w, int h, Bool interact);
   206 static void resizeclient(Client *c, int x, int y, int w, int h);
   211 static void resizeclient(Client *c, int x, int y, int w, int h);
   207 static void resizemouse(const Arg *arg);
   212 static void resizemouse(const Arg *arg);
   208 static void restack(Monitor *m);
   213 static void restack(Monitor *m);
   209 static void run(void);
   214 static void run(void);
   210 static void scan(void);
   215 static void scan(void);
       
   216 static Bool sendevent(Client *c, Atom proto);
   211 static void sendmon(Client *c, Monitor *m);
   217 static void sendmon(Client *c, Monitor *m);
   212 static void setclientstate(Client *c, long state);
   218 static void setclientstate(Client *c, long state);
       
   219 static void setfocus(Client *c);
       
   220 static void setfullscreen(Client *c, Bool fullscreen);
   213 static void setlayout(const Arg *arg);
   221 static void setlayout(const Arg *arg);
   214 static void setmfact(const Arg *arg);
   222 static void setmfact(const Arg *arg);
   215 static void setup(void);
   223 static void setup(void);
   216 static void showhide(Client *c);
   224 static void showhide(Client *c);
   217 static void sigchld(int unused);
   225 static void sigchld(int unused);
   231 static void updatebarpos(Monitor *m);
   239 static void updatebarpos(Monitor *m);
   232 static void updatebars(void);
   240 static void updatebars(void);
   233 static void updatenumlockmask(void);
   241 static void updatenumlockmask(void);
   234 static void updatesizehints(Client *c);
   242 static void updatesizehints(Client *c);
   235 static void updatestatus(void);
   243 static void updatestatus(void);
       
   244 static void updatewindowtype(Client *c);
   236 static void updatetitle(Client *c);
   245 static void updatetitle(Client *c);
   237 static void updatewmhints(Client *c);
   246 static void updatewmhints(Client *c);
   238 static void view(const Arg *arg);
   247 static void view(const Arg *arg);
   239 static Client *wintoclient(Window w);
   248 static Client *wintoclient(Window w);
   240 static Monitor *wintomon(Window w);
   249 static Monitor *wintomon(Window w);
   261 	[Expose] = expose,
   270 	[Expose] = expose,
   262 	[FocusIn] = focusin,
   271 	[FocusIn] = focusin,
   263 	[KeyPress] = keypress,
   272 	[KeyPress] = keypress,
   264 	[MappingNotify] = mappingnotify,
   273 	[MappingNotify] = mappingnotify,
   265 	[MapRequest] = maprequest,
   274 	[MapRequest] = maprequest,
       
   275 	[MotionNotify] = motionnotify,
   266 	[PropertyNotify] = propertynotify,
   276 	[PropertyNotify] = propertynotify,
   267 	[UnmapNotify] = unmapnotify
   277 	[UnmapNotify] = unmapnotify
   268 };
   278 };
   269 static Atom wmatom[WMLast], netatom[NetLast];
   279 static Atom wmatom[WMLast], netatom[NetLast];
   270 static Bool running = True;
   280 static Bool running = True;
   285 applyrules(Client *c) {
   295 applyrules(Client *c) {
   286 	const char *class, *instance;
   296 	const char *class, *instance;
   287 	unsigned int i;
   297 	unsigned int i;
   288 	const Rule *r;
   298 	const Rule *r;
   289 	Monitor *m;
   299 	Monitor *m;
   290 	XClassHint ch = { 0 };
   300 	XClassHint ch = { NULL, NULL };
   291 
   301 
   292 	/* rule matching */
   302 	/* rule matching */
   293 	c->isfloating = c->tags = 0;
   303 	c->isfloating = c->tags = 0;
   294 	if(XGetClassHint(dpy, c->win, &ch)) {
   304 	XGetClassHint(dpy, c->win, &ch);
   295 		class = ch.res_class ? ch.res_class : broken;
   305 	class    = ch.res_class ? ch.res_class : broken;
   296 		instance = ch.res_name ? ch.res_name : broken;
   306 	instance = ch.res_name  ? ch.res_name  : broken;
   297 		for(i = 0; i < LENGTH(rules); i++) {
   307 
   298 			r = &rules[i];
   308 	for(i = 0; i < LENGTH(rules); i++) {
   299 			if((!r->title || strstr(c->name, r->title))
   309 		r = &rules[i];
   300 			&& (!r->class || strstr(class, r->class))
   310 		if((!r->title || strstr(c->name, r->title))
   301 			&& (!r->instance || strstr(instance, r->instance)))
   311 		&& (!r->class || strstr(class, r->class))
   302 			{
   312 		&& (!r->instance || strstr(instance, r->instance)))
   303 				c->isfloating = r->isfloating;
   313 		{
   304 				c->tags |= r->tags;
   314 			c->isfloating = r->isfloating;
   305 				for(m = mons; m && m->num != r->monitor; m = m->next);
   315 			c->tags |= r->tags;
   306 				if(m)
   316 			for(m = mons; m && m->num != r->monitor; m = m->next);
   307 					c->mon = m;
   317 			if(m)
   308 			}
   318 				c->mon = m;
   309 		}
   319 		}
   310 		if(ch.res_class)
   320 	}
   311 			XFree(ch.res_class);
   321 	if(ch.res_class)
   312 		if(ch.res_name)
   322 		XFree(ch.res_class);
   313 			XFree(ch.res_name);
   323 	if(ch.res_name)
   314 	}
   324 		XFree(ch.res_name);
   315 	c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
   325 	c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
   316 }
   326 }
   317 
   327 
   318 Bool
   328 Bool
   319 applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) {
   329 applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) {
   332 			*x = 0;
   342 			*x = 0;
   333 		if(*y + *h + 2 * c->bw < 0)
   343 		if(*y + *h + 2 * c->bw < 0)
   334 			*y = 0;
   344 			*y = 0;
   335 	}
   345 	}
   336 	else {
   346 	else {
   337 		if(*x > m->mx + m->mw)
   347 		if(*x >= m->wx + m->ww)
   338 			*x = m->mx + m->mw - WIDTH(c);
   348 			*x = m->wx + m->ww - WIDTH(c);
   339 		if(*y > m->my + m->mh)
   349 		if(*y >= m->wy + m->wh)
   340 			*y = m->my + m->mh - HEIGHT(c);
   350 			*y = m->wy + m->wh - HEIGHT(c);
   341 		if(*x + *w + 2 * c->bw < m->mx)
   351 		if(*x + *w + 2 * c->bw <= m->wx)
   342 			*x = m->mx;
   352 			*x = m->wx;
   343 		if(*y + *h + 2 * c->bw < m->my)
   353 		if(*y + *h + 2 * c->bw <= m->wy)
   344 			*y = m->my;
   354 			*y = m->wy;
   345 	}
   355 	}
   346 	if(*h < bh)
   356 	if(*h < bh)
   347 		*h = bh;
   357 		*h = bh;
   348 	if(*w < bh)
   358 	if(*w < bh)
   349 		*w = bh;
   359 		*w = bh;
   350 	if(resizehints || c->isfloating) {
   360 	if(resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
   351 		/* see last two sentences in ICCCM 4.1.2.3 */
   361 		/* see last two sentences in ICCCM 4.1.2.3 */
   352 		baseismin = c->basew == c->minw && c->baseh == c->minh;
   362 		baseismin = c->basew == c->minw && c->baseh == c->minh;
   353 		if(!baseismin) { /* temporarily remove base dimensions */
   363 		if(!baseismin) { /* temporarily remove base dimensions */
   354 			*w -= c->basew;
   364 			*w -= c->basew;
   355 			*h -= c->baseh;
   365 			*h -= c->baseh;
   385 arrange(Monitor *m) {
   395 arrange(Monitor *m) {
   386 	if(m)
   396 	if(m)
   387 		showhide(m->stack);
   397 		showhide(m->stack);
   388 	else for(m = mons; m; m = m->next)
   398 	else for(m = mons; m; m = m->next)
   389 		showhide(m->stack);
   399 		showhide(m->stack);
   390 	focus(NULL);
       
   391 	if(m)
   400 	if(m)
   392 		arrangemon(m);
   401 		arrangemon(m);
   393 	else for(m = mons; m; m = m->next)
   402 	else for(m = mons; m; m = m->next)
   394 		arrangemon(m);
   403 		arrangemon(m);
   395 }
   404 }
   429 		selmon = m;
   438 		selmon = m;
   430 		focus(NULL);
   439 		focus(NULL);
   431 	}
   440 	}
   432 	if(ev->window == selmon->barwin) {
   441 	if(ev->window == selmon->barwin) {
   433 		i = x = 0;
   442 		i = x = 0;
   434 		do {
   443 		do
   435 			x += TEXTW(tags[i]);
   444 			x += TEXTW(tags[i]);
   436 		} while(ev->x >= x && ++i < LENGTH(tags));
   445 		while(ev->x >= x && ++i < LENGTH(tags));
   437 		if(i < LENGTH(tags)) {
   446 		if(i < LENGTH(tags)) {
   438 			click = ClkTagBar;
   447 			click = ClkTagBar;
   439 			arg.ui = 1 << i;
   448 			arg.ui = 1 << i;
   440 		}
   449 		}
   441 		else if(ev->x < x + blw)
   450 		else if(ev->x < x + blw)
   442 			click = ClkLtSymbol;
   451 			click = ClkLtSymbol;
   443 		else if(ev->x > selmon->wx + selmon->ww - TEXTW(stext))
   452 		else if(ev->x > selmon->ww - TEXTW(stext))
   444 			click = ClkStatusText;
   453 			click = ClkStatusText;
   445 		else
   454 		else
   446 			click = ClkWinTitle;
   455 			click = ClkWinTitle;
   447 	}
   456 	}
   448 	else if((c = wintoclient(ev->window))) {
   457 	else if((c = wintoclient(ev->window))) {
   518 	XSetWMHints(dpy, c->win, wmh);
   527 	XSetWMHints(dpy, c->win, wmh);
   519 	XFree(wmh);
   528 	XFree(wmh);
   520 }
   529 }
   521 
   530 
   522 void
   531 void
       
   532 clientmessage(XEvent *e) {
       
   533 	XClientMessageEvent *cme = &e->xclient;
       
   534 	Client *c = wintoclient(cme->window);
       
   535 
       
   536 	if(!c)
       
   537 		return;
       
   538 	if(cme->message_type == netatom[NetWMState]) {
       
   539 		if(cme->data.l[1] == netatom[NetWMFullscreen] || cme->data.l[2] == netatom[NetWMFullscreen])
       
   540 			setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD    */
       
   541 			              || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
       
   542 	}
       
   543 	else if(cme->message_type == netatom[NetActiveWindow]) {
       
   544 		if(!ISVISIBLE(c)) {
       
   545 			c->mon->seltags ^= 1;
       
   546 			c->mon->tagset[c->mon->seltags] = c->tags;
       
   547 		}
       
   548 		pop(c);
       
   549 	}
       
   550 }
       
   551 
       
   552 void
   523 configure(Client *c) {
   553 configure(Client *c) {
   524 	XConfigureEvent ce;
   554 	XConfigureEvent ce;
   525 
   555 
   526 	ce.type = ConfigureNotify;
   556 	ce.type = ConfigureNotify;
   527 	ce.display = dpy;
   557 	ce.display = dpy;
   539 
   569 
   540 void
   570 void
   541 configurenotify(XEvent *e) {
   571 configurenotify(XEvent *e) {
   542 	Monitor *m;
   572 	Monitor *m;
   543 	XConfigureEvent *ev = &e->xconfigure;
   573 	XConfigureEvent *ev = &e->xconfigure;
       
   574 	Bool dirty;
   544 
   575 
   545 	if(ev->window == root) {
   576 	if(ev->window == root) {
       
   577 		dirty = (sw != ev->width);
   546 		sw = ev->width;
   578 		sw = ev->width;
   547 		sh = ev->height;
   579 		sh = ev->height;
   548 		if(updategeom()) {
   580 		if(updategeom() || dirty) {
   549 			if(dc.drawable != 0)
   581 			if(dc.drawable != 0)
   550 				XFreePixmap(dpy, dc.drawable);
   582 				XFreePixmap(dpy, dc.drawable);
   551 			dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
   583 			dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
   552 			updatebars();
   584 			updatebars();
   553 			for(m = mons; m; m = m->next)
   585 			for(m = mons; m; m = m->next)
   554 				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
   586 				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
       
   587 			focus(NULL);
   555 			arrange(NULL);
   588 			arrange(NULL);
   556 		}
   589 		}
   557 	}
   590 	}
   558 }
   591 }
   559 
   592 
   567 	if((c = wintoclient(ev->window))) {
   600 	if((c = wintoclient(ev->window))) {
   568 		if(ev->value_mask & CWBorderWidth)
   601 		if(ev->value_mask & CWBorderWidth)
   569 			c->bw = ev->border_width;
   602 			c->bw = ev->border_width;
   570 		else if(c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
   603 		else if(c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
   571 			m = c->mon;
   604 			m = c->mon;
   572 			if(ev->value_mask & CWX)
   605 			if(ev->value_mask & CWX) {
       
   606 				c->oldx = c->x;
   573 				c->x = m->mx + ev->x;
   607 				c->x = m->mx + ev->x;
   574 			if(ev->value_mask & CWY)
   608 			}
       
   609 			if(ev->value_mask & CWY) {
       
   610 				c->oldy = c->y;
   575 				c->y = m->my + ev->y;
   611 				c->y = m->my + ev->y;
   576 			if(ev->value_mask & CWWidth)
   612 			}
       
   613 			if(ev->value_mask & CWWidth) {
       
   614 				c->oldw = c->w;
   577 				c->w = ev->width;
   615 				c->w = ev->width;
   578 			if(ev->value_mask & CWHeight)
   616 			}
       
   617 			if(ev->value_mask & CWHeight) {
       
   618 				c->oldh = c->h;
   579 				c->h = ev->height;
   619 				c->h = ev->height;
       
   620 			}
   580 			if((c->x + c->w) > m->mx + m->mw && c->isfloating)
   621 			if((c->x + c->w) > m->mx + m->mw && c->isfloating)
   581 				c->x = m->mx + (m->mw / 2 - c->w / 2); /* center in x direction */
   622 				c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */
   582 			if((c->y + c->h) > m->my + m->mh && c->isfloating)
   623 			if((c->y + c->h) > m->my + m->mh && c->isfloating)
   583 				c->y = m->my + (m->mh / 2 - c->h / 2); /* center in y direction */
   624 				c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */
   584 			if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
   625 			if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
   585 				configure(c);
   626 				configure(c);
   586 			if(ISVISIBLE(c))
   627 			if(ISVISIBLE(c))
   587 				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
   628 				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
   588 		}
   629 		}
   608 
   649 
   609 	if(!(m = (Monitor *)calloc(1, sizeof(Monitor))))
   650 	if(!(m = (Monitor *)calloc(1, sizeof(Monitor))))
   610 		die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
   651 		die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
   611 	m->tagset[0] = m->tagset[1] = 1;
   652 	m->tagset[0] = m->tagset[1] = 1;
   612 	m->mfact = mfact;
   653 	m->mfact = mfact;
       
   654 	m->nmaster = nmaster;
   613 	m->showbar = showbar;
   655 	m->showbar = showbar;
   614 	m->topbar = topbar;
   656 	m->topbar = topbar;
   615 	m->lt[0] = &layouts[0];
   657 	m->lt[0] = &layouts[0];
   616 	m->lt[1] = &layouts[1 % LENGTH(layouts)];
   658 	m->lt[1] = &layouts[1 % LENGTH(layouts)];
   617 	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
   659 	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
   664 
   706 
   665 	if(dir > 0) {
   707 	if(dir > 0) {
   666 		if(!(m = selmon->next))
   708 		if(!(m = selmon->next))
   667 			m = mons;
   709 			m = mons;
   668 	}
   710 	}
   669 	else {
   711 	else if(selmon == mons)
   670 		if(selmon == mons)
   712 		for(m = mons; m->next; m = m->next);
   671 			for(m = mons; m->next; m = m->next);
   713 	else
   672 		else
   714 		for(m = mons; m->next != selmon; m = m->next);
   673 			for(m = mons; m->next != selmon; m = m->next);
       
   674 	}
       
   675 	return m;
   715 	return m;
   676 }
   716 }
   677 
   717 
   678 void
   718 void
   679 drawbar(Monitor *m) {
   719 drawbar(Monitor *m) {
   734 }
   774 }
   735 
   775 
   736 void
   776 void
   737 drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
   777 drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
   738 	int x;
   778 	int x;
   739 	XGCValues gcv;
   779 
   740 	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
   780 	XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]);
   741 
       
   742 	gcv.foreground = col[invert ? ColBG : ColFG];
       
   743 	XChangeGC(dpy, dc.gc, GCForeground, &gcv);
       
   744 	x = (dc.font.ascent + dc.font.descent + 2) / 4;
   781 	x = (dc.font.ascent + dc.font.descent + 2) / 4;
   745 	r.x = dc.x + 1;
   782 	if(filled)
   746 	r.y = dc.y + 1;
   783 		XFillRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x+1, x+1);
   747 	if(filled) {
   784 	else if(empty)
   748 		r.width = r.height = x + 1;
   785 		XDrawRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x, x);
   749 		XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
       
   750 	}
       
   751 	else if(empty) {
       
   752 		r.width = r.height = x;
       
   753 		XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
       
   754 	}
       
   755 }
   786 }
   756 
   787 
   757 void
   788 void
   758 drawtext(const char *text, unsigned long col[ColLast], Bool invert) {
   789 drawtext(const char *text, unsigned long col[ColLast], Bool invert) {
   759 	char buf[256];
   790 	char buf[256];
   760 	int i, x, y, h, len, olen;
   791 	int i, x, y, h, len, olen;
   761 	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
       
   762 
   792 
   763 	XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]);
   793 	XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]);
   764 	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
   794 	XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.w, dc.h);
   765 	if(!text)
   795 	if(!text)
   766 		return;
   796 		return;
   767 	olen = strlen(text);
   797 	olen = strlen(text);
   768 	h = dc.font.ascent + dc.font.descent;
   798 	h = dc.font.ascent + dc.font.descent;
   769 	y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
   799 	y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
   782 		XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
   812 		XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
   783 }
   813 }
   784 
   814 
   785 void
   815 void
   786 enternotify(XEvent *e) {
   816 enternotify(XEvent *e) {
       
   817 	Client *c;
   787 	Monitor *m;
   818 	Monitor *m;
   788 	XCrossingEvent *ev = &e->xcrossing;
   819 	XCrossingEvent *ev = &e->xcrossing;
   789 
   820 
   790 	if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
   821 	if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
   791 		return;
   822 		return;
   792 	if((m = wintomon(ev->window)) && m != selmon) {
   823 	c = wintoclient(ev->window);
       
   824 	m = c ? c->mon : wintomon(ev->window);
       
   825 	if(m != selmon) {
   793 		unfocus(selmon->sel, True);
   826 		unfocus(selmon->sel, True);
   794 		selmon = m;
   827 		selmon = m;
   795 	}
   828 	}
   796 	focus((wintoclient(ev->window)));
   829 	else if(!c || c == selmon->sel)
       
   830 		return;
       
   831 	focus(c);
   797 }
   832 }
   798 
   833 
   799 void
   834 void
   800 expose(XEvent *e) {
   835 expose(XEvent *e) {
   801 	Monitor *m;
   836 	Monitor *m;
   819 			clearurgent(c);
   854 			clearurgent(c);
   820 		detachstack(c);
   855 		detachstack(c);
   821 		attachstack(c);
   856 		attachstack(c);
   822 		grabbuttons(c, True);
   857 		grabbuttons(c, True);
   823 		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
   858 		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
   824 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
   859 		setfocus(c);
   825 	}
   860 	}
   826 	else
   861 	else
   827 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
   862 		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
   828 	selmon->sel = c;
   863 	selmon->sel = c;
   829 	drawbars();
   864 	drawbars();
   832 void
   867 void
   833 focusin(XEvent *e) { /* there are some broken focus acquiring clients */
   868 focusin(XEvent *e) { /* there are some broken focus acquiring clients */
   834 	XFocusChangeEvent *ev = &e->xfocus;
   869 	XFocusChangeEvent *ev = &e->xfocus;
   835 
   870 
   836 	if(selmon->sel && ev->window != selmon->sel->win)
   871 	if(selmon->sel && ev->window != selmon->sel->win)
   837 		XSetInputFocus(dpy, selmon->sel->win, RevertToPointerRoot, CurrentTime);
   872 		setfocus(selmon->sel);
   838 }
   873 }
   839 
   874 
   840 void
   875 void
   841 focusmon(const Arg *arg) {
   876 focusmon(const Arg *arg) {
   842 	Monitor *m;
   877 	Monitor *m;
   872 	}
   907 	}
   873 	if(c) {
   908 	if(c) {
   874 		focus(c);
   909 		focus(c);
   875 		restack(selmon);
   910 		restack(selmon);
   876 	}
   911 	}
       
   912 }
       
   913 
       
   914 Atom
       
   915 getatomprop(Client *c, Atom prop) {
       
   916 	int di;
       
   917 	unsigned long dl;
       
   918 	unsigned char *p = NULL;
       
   919 	Atom da, atom = None;
       
   920 
       
   921 	if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
       
   922 	                      &da, &di, &dl, &dl, &p) == Success && p) {
       
   923 		atom = *(Atom *)p;
       
   924 		XFree(p);
       
   925 	}
       
   926 	return atom;
   877 }
   927 }
   878 
   928 
   879 unsigned long
   929 unsigned long
   880 getcolor(const char *colstr) {
   930 getcolor(const char *colstr) {
   881 	Colormap cmap = DefaultColormap(dpy, screen);
   931 	Colormap cmap = DefaultColormap(dpy, screen);
   966 		unsigned int i, j;
  1016 		unsigned int i, j;
   967 		unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
  1017 		unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
   968 		KeyCode code;
  1018 		KeyCode code;
   969 
  1019 
   970 		XUngrabKey(dpy, AnyKey, AnyModifier, root);
  1020 		XUngrabKey(dpy, AnyKey, AnyModifier, root);
   971 		for(i = 0; i < LENGTH(keys); i++) {
  1021 		for(i = 0; i < LENGTH(keys); i++)
   972 			if((code = XKeysymToKeycode(dpy, keys[i].keysym)))
  1022 			if((code = XKeysymToKeycode(dpy, keys[i].keysym)))
   973 				for(j = 0; j < LENGTH(modifiers); j++)
  1023 				for(j = 0; j < LENGTH(modifiers); j++)
   974 					XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
  1024 					XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
   975 						 True, GrabModeAsync, GrabModeAsync);
  1025 						 True, GrabModeAsync, GrabModeAsync);
   976 		}
  1026 	}
   977 	}
  1027 }
       
  1028 
       
  1029 void
       
  1030 incnmaster(const Arg *arg) {
       
  1031 	selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
       
  1032 	arrange(selmon);
   978 }
  1033 }
   979 
  1034 
   980 void
  1035 void
   981 initfont(const char *fontstr) {
  1036 initfont(const char *fontstr) {
   982 	char *def, **missing;
  1037 	char *def, **missing;
   983 	int n;
  1038 	int n;
   984 
  1039 
   985 	missing = NULL;
       
   986 	dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
  1040 	dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
   987 	if(missing) {
  1041 	if(missing) {
   988 		while(n--)
  1042 		while(n--)
   989 			fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]);
  1043 			fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]);
   990 		XFreeStringList(missing);
  1044 		XFreeStringList(missing);
  1008 			die("error, cannot load font: '%s'\n", fontstr);
  1062 			die("error, cannot load font: '%s'\n", fontstr);
  1009 		dc.font.ascent = dc.font.xfont->ascent;
  1063 		dc.font.ascent = dc.font.xfont->ascent;
  1010 		dc.font.descent = dc.font.xfont->descent;
  1064 		dc.font.descent = dc.font.xfont->descent;
  1011 	}
  1065 	}
  1012 	dc.font.height = dc.font.ascent + dc.font.descent;
  1066 	dc.font.height = dc.font.ascent + dc.font.descent;
  1013 }
       
  1014 
       
  1015 Bool
       
  1016 isprotodel(Client *c) {
       
  1017 	int n;
       
  1018 	Atom *protocols;
       
  1019 	Bool ret = False;
       
  1020 
       
  1021 	if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
       
  1022 		while(!ret && n--)
       
  1023 			ret = protocols[n] == wmatom[WMDelete];
       
  1024 		XFree(protocols);
       
  1025 	}
       
  1026 	return ret;
       
  1027 }
  1067 }
  1028 
  1068 
  1029 #ifdef XINERAMA
  1069 #ifdef XINERAMA
  1030 static Bool
  1070 static Bool
  1031 isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) {
  1071 isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) {
  1052 			keys[i].func(&(keys[i].arg));
  1092 			keys[i].func(&(keys[i].arg));
  1053 }
  1093 }
  1054 
  1094 
  1055 void
  1095 void
  1056 killclient(const Arg *arg) {
  1096 killclient(const Arg *arg) {
  1057 	XEvent ev;
       
  1058 
       
  1059 	if(!selmon->sel)
  1097 	if(!selmon->sel)
  1060 		return;
  1098 		return;
  1061 	if(isprotodel(selmon->sel)) {
  1099 	if(!sendevent(selmon->sel, wmatom[WMDelete])) {
  1062 		ev.type = ClientMessage;
       
  1063 		ev.xclient.window = selmon->sel->win;
       
  1064 		ev.xclient.message_type = wmatom[WMProtocols];
       
  1065 		ev.xclient.format = 32;
       
  1066 		ev.xclient.data.l[0] = wmatom[WMDelete];
       
  1067 		ev.xclient.data.l[1] = CurrentTime;
       
  1068 		XSendEvent(dpy, selmon->sel->win, False, NoEventMask, &ev);
       
  1069 	}
       
  1070 	else {
       
  1071 		XGrabServer(dpy);
  1100 		XGrabServer(dpy);
  1072 		XSetErrorHandler(xerrordummy);
  1101 		XSetErrorHandler(xerrordummy);
  1073 		XSetCloseDownMode(dpy, DestroyAll);
  1102 		XSetCloseDownMode(dpy, DestroyAll);
  1074 		XKillClient(dpy, selmon->sel->win);
  1103 		XKillClient(dpy, selmon->sel->win);
  1075 		XSync(dpy, False);
  1104 		XSync(dpy, False);
  1095 	else {
  1124 	else {
  1096 		c->mon = selmon;
  1125 		c->mon = selmon;
  1097 		applyrules(c);
  1126 		applyrules(c);
  1098 	}
  1127 	}
  1099 	/* geometry */
  1128 	/* geometry */
  1100 	c->x = c->oldx = wa->x + c->mon->wx;
  1129 	c->x = c->oldx = wa->x;
  1101 	c->y = c->oldy = wa->y + c->mon->wy;
  1130 	c->y = c->oldy = wa->y;
  1102 	c->w = c->oldw = wa->width;
  1131 	c->w = c->oldw = wa->width;
  1103 	c->h = c->oldh = wa->height;
  1132 	c->h = c->oldh = wa->height;
  1104 	c->oldbw = wa->border_width;
  1133 	c->oldbw = wa->border_width;
  1105 	if(c->w == c->mon->mw && c->h == c->mon->mh) {
  1134 
  1106 		c->isfloating = True;
  1135 	if(c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
  1107 		c->x = c->mon->mx;
  1136 		c->x = c->mon->mx + c->mon->mw - WIDTH(c);
  1108 		c->y = c->mon->my;
  1137 	if(c->y + HEIGHT(c) > c->mon->my + c->mon->mh)
  1109 		c->bw = 0;
  1138 		c->y = c->mon->my + c->mon->mh - HEIGHT(c);
  1110 	}
  1139 	c->x = MAX(c->x, c->mon->mx);
  1111 	else {
  1140 	/* only fix client y-offset, if the client center might cover the bar */
  1112 		if(c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
  1141 	c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
  1113 			c->x = c->mon->mx + c->mon->mw - WIDTH(c);
  1142 	           && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
  1114 		if(c->y + HEIGHT(c) > c->mon->my + c->mon->mh)
  1143 	c->bw = borderpx;
  1115 			c->y = c->mon->my + c->mon->mh - HEIGHT(c);
  1144 
  1116 		c->x = MAX(c->x, c->mon->mx);
       
  1117 		/* only fix client y-offset, if the client center might cover the bar */
       
  1118 		c->y = MAX(c->y, ((c->mon->by == 0) && (c->x + (c->w / 2) >= c->mon->wx)
       
  1119 		           && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
       
  1120 		c->bw = borderpx;
       
  1121 	}
       
  1122 	wc.border_width = c->bw;
  1145 	wc.border_width = c->bw;
  1123 	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
  1146 	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
  1124 	XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
  1147 	XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
  1125 	configure(c); /* propagates border_width, if size doesn't change */
  1148 	configure(c); /* propagates border_width, if size doesn't change */
       
  1149 	updatewindowtype(c);
  1126 	updatesizehints(c);
  1150 	updatesizehints(c);
       
  1151 	updatewmhints(c);
  1127 	XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
  1152 	XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
  1128 	grabbuttons(c, False);
  1153 	grabbuttons(c, False);
  1129 	if(!c->isfloating)
  1154 	if(!c->isfloating)
  1130 		c->isfloating = c->oldstate = trans != None || c->isfixed;
  1155 		c->isfloating = c->oldstate = trans != None || c->isfixed;
  1131 	if(c->isfloating)
  1156 	if(c->isfloating)
  1132 		XRaiseWindow(dpy, c->win);
  1157 		XRaiseWindow(dpy, c->win);
  1133 	attach(c);
  1158 	attach(c);
  1134 	attachstack(c);
  1159 	attachstack(c);
  1135 	XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
  1160 	XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
       
  1161 	setclientstate(c, NormalState);
       
  1162 	if (c->mon == selmon)
       
  1163 		unfocus(selmon->sel, False);
       
  1164 	c->mon->sel = c;
       
  1165 	arrange(c->mon);
  1136 	XMapWindow(dpy, c->win);
  1166 	XMapWindow(dpy, c->win);
  1137 	setclientstate(c, NormalState);
  1167 	focus(NULL);
  1138 	arrange(c->mon);
       
  1139 }
  1168 }
  1140 
  1169 
  1141 void
  1170 void
  1142 mappingnotify(XEvent *e) {
  1171 mappingnotify(XEvent *e) {
  1143 	XMappingEvent *ev = &e->xmapping;
  1172 	XMappingEvent *ev = &e->xmapping;
  1173 	for(c = nexttiled(m->clients); c; c = nexttiled(c->next))
  1202 	for(c = nexttiled(m->clients); c; c = nexttiled(c->next))
  1174 		resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False);
  1203 		resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False);
  1175 }
  1204 }
  1176 
  1205 
  1177 void
  1206 void
       
  1207 motionnotify(XEvent *e) {
       
  1208 	static Monitor *mon = NULL;
       
  1209 	Monitor *m;
       
  1210 	XMotionEvent *ev = &e->xmotion;
       
  1211 
       
  1212 	if(ev->window != root)
       
  1213 		return;
       
  1214 	if((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
       
  1215 		selmon = m;
       
  1216 		focus(NULL);
       
  1217 	}
       
  1218 	mon = m;
       
  1219 }
       
  1220 
       
  1221 void
  1178 movemouse(const Arg *arg) {
  1222 movemouse(const Arg *arg) {
  1179 	int x, y, ocx, ocy, nx, ny;
  1223 	int x, y, ocx, ocy, nx, ny;
  1180 	Client *c;
  1224 	Client *c;
  1181 	Monitor *m;
  1225 	Monitor *m;
  1182 	XEvent ev;
  1226 	XEvent ev;
  1191 		return;
  1235 		return;
  1192 	if(!getrootptr(&x, &y))
  1236 	if(!getrootptr(&x, &y))
  1193 		return;
  1237 		return;
  1194 	do {
  1238 	do {
  1195 		XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
  1239 		XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
  1196 		switch (ev.type) {
  1240 		switch(ev.type) {
  1197 		case ConfigureRequest:
  1241 		case ConfigureRequest:
  1198 		case Expose:
  1242 		case Expose:
  1199 		case MapRequest:
  1243 		case MapRequest:
  1200 			handler[ev.type](&ev);
  1244 			handler[ev.type](&ev);
  1201 			break;
  1245 			break;
  1202 		case MotionNotify:
  1246 		case MotionNotify:
  1203 			nx = ocx + (ev.xmotion.x - x);
  1247 			nx = ocx + (ev.xmotion.x - x);
  1204 			ny = ocy + (ev.xmotion.y - y);
  1248 			ny = ocy + (ev.xmotion.y - y);
  1205 			if(snap && nx >= selmon->wx && nx <= selmon->wx + selmon->ww
  1249 			if(nx >= selmon->wx && nx <= selmon->wx + selmon->ww
  1206 			&& ny >= selmon->wy && ny <= selmon->wy + selmon->wh) {
  1250 			&& ny >= selmon->wy && ny <= selmon->wy + selmon->wh) {
  1207 				if(abs(selmon->wx - nx) < snap)
  1251 				if(abs(selmon->wx - nx) < snap)
  1208 					nx = selmon->wx;
  1252 					nx = selmon->wx;
  1209 				else if(abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
  1253 				else if(abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
  1210 					nx = selmon->wx + selmon->ww - WIDTH(c);
  1254 					nx = selmon->wx + selmon->ww - WIDTH(c);
  1220 				resize(c, nx, ny, c->w, c->h, True);
  1264 				resize(c, nx, ny, c->w, c->h, True);
  1221 			break;
  1265 			break;
  1222 		}
  1266 		}
  1223 	} while(ev.type != ButtonRelease);
  1267 	} while(ev.type != ButtonRelease);
  1224 	XUngrabPointer(dpy, CurrentTime);
  1268 	XUngrabPointer(dpy, CurrentTime);
  1225 	if((m = ptrtomon(c->x + c->w / 2, c->y + c->h / 2)) != selmon) {
  1269 	if((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
  1226 		sendmon(c, m);
  1270 		sendmon(c, m);
  1227 		selmon = m;
  1271 		selmon = m;
  1228 		focus(NULL);
  1272 		focus(NULL);
  1229 	}
  1273 	}
  1230 }
  1274 }
  1233 nexttiled(Client *c) {
  1277 nexttiled(Client *c) {
  1234 	for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
  1278 	for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
  1235 	return c;
  1279 	return c;
  1236 }
  1280 }
  1237 
  1281 
  1238 Monitor *
  1282 void
  1239 ptrtomon(int x, int y) {
  1283 pop(Client *c) {
  1240 	Monitor *m;
  1284 	detach(c);
  1241 
  1285 	attach(c);
  1242 	for(m = mons; m; m = m->next)
  1286 	focus(c);
  1243 		if(INRECT(x, y, m->wx, m->wy, m->ww, m->wh))
  1287 	arrange(c->mon);
  1244 			return m;
       
  1245 	return selmon;
       
  1246 }
  1288 }
  1247 
  1289 
  1248 void
  1290 void
  1249 propertynotify(XEvent *e) {
  1291 propertynotify(XEvent *e) {
  1250 	Client *c;
  1292 	Client *c;
  1254 	if((ev->window == root) && (ev->atom == XA_WM_NAME))
  1296 	if((ev->window == root) && (ev->atom == XA_WM_NAME))
  1255 		updatestatus();
  1297 		updatestatus();
  1256 	else if(ev->state == PropertyDelete)
  1298 	else if(ev->state == PropertyDelete)
  1257 		return; /* ignore */
  1299 		return; /* ignore */
  1258 	else if((c = wintoclient(ev->window))) {
  1300 	else if((c = wintoclient(ev->window))) {
  1259 		switch (ev->atom) {
  1301 		switch(ev->atom) {
  1260 		default: break;
  1302 		default: break;
  1261 		case XA_WM_TRANSIENT_FOR:
  1303 		case XA_WM_TRANSIENT_FOR:
  1262 			if(!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
  1304 			if(!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
  1263 			   (c->isfloating = (wintoclient(trans)) != NULL))
  1305 			   (c->isfloating = (wintoclient(trans)) != NULL))
  1264 				arrange(c->mon);
  1306 				arrange(c->mon);
  1274 		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
  1316 		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
  1275 			updatetitle(c);
  1317 			updatetitle(c);
  1276 			if(c == c->mon->sel)
  1318 			if(c == c->mon->sel)
  1277 				drawbar(c->mon);
  1319 				drawbar(c->mon);
  1278 		}
  1320 		}
  1279 	}
  1321 		if(ev->atom == netatom[NetWMWindowType])
  1280 }
  1322 			updatewindowtype(c);
  1281 
       
  1282 void
       
  1283 clientmessage(XEvent *e) {
       
  1284 	XClientMessageEvent *cme = &e->xclient;
       
  1285 	Client *c;
       
  1286 
       
  1287 	if((c = wintoclient(cme->window))
       
  1288 	&& (cme->message_type == netatom[NetWMState] && cme->data.l[1] == netatom[NetWMFullscreen]))
       
  1289 	{
       
  1290 		if(cme->data.l[0]) {
       
  1291 			XChangeProperty(dpy, cme->window, netatom[NetWMState], XA_ATOM, 32,
       
  1292 			                PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
       
  1293 			c->oldstate = c->isfloating;
       
  1294 			c->oldbw = c->bw;
       
  1295 			c->bw = 0;
       
  1296 			c->isfloating = True;
       
  1297 			resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
       
  1298 			XRaiseWindow(dpy, c->win);
       
  1299 		}
       
  1300 		else {
       
  1301 			XChangeProperty(dpy, cme->window, netatom[NetWMState], XA_ATOM, 32,
       
  1302 			                PropModeReplace, (unsigned char*)0, 0);
       
  1303 			c->isfloating = c->oldstate;
       
  1304 			c->bw = c->oldbw;
       
  1305 			c->x = c->oldx;
       
  1306 			c->y = c->oldy;
       
  1307 			c->w = c->oldw;
       
  1308 			c->h = c->oldh;
       
  1309 			resizeclient(c, c->x, c->y, c->w, c->h);
       
  1310 			arrange(c->mon);
       
  1311 		}
       
  1312 	}
  1323 	}
  1313 }
  1324 }
  1314 
  1325 
  1315 void
  1326 void
  1316 quit(const Arg *arg) {
  1327 quit(const Arg *arg) {
  1317 	running = False;
  1328 	running = False;
       
  1329 }
       
  1330 
       
  1331 Monitor *
       
  1332 recttomon(int x, int y, int w, int h) {
       
  1333 	Monitor *m, *r = selmon;
       
  1334 	int a, area = 0;
       
  1335 
       
  1336 	for(m = mons; m; m = m->next)
       
  1337 		if((a = INTERSECT(x, y, w, h, m)) > area) {
       
  1338 			area = a;
       
  1339 			r = m;
       
  1340 		}
       
  1341 	return r;
  1318 }
  1342 }
  1319 
  1343 
  1320 void
  1344 void
  1321 resize(Client *c, int x, int y, int w, int h, Bool interact) {
  1345 resize(Client *c, int x, int y, int w, int h, Bool interact) {
  1322 	if(applysizehints(c, &x, &y, &w, &h, interact))
  1346 	if(applysizehints(c, &x, &y, &w, &h, interact))
  1363 			handler[ev.type](&ev);
  1387 			handler[ev.type](&ev);
  1364 			break;
  1388 			break;
  1365 		case MotionNotify:
  1389 		case MotionNotify:
  1366 			nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
  1390 			nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
  1367 			nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
  1391 			nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
  1368 			if(snap && nw >= selmon->wx && nw <= selmon->wx + selmon->ww
  1392 			if(c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
  1369 			&& nh >= selmon->wy && nh <= selmon->wy + selmon->wh)
  1393 			&& c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh)
  1370 			{
  1394 			{
  1371 				if(!c->isfloating && selmon->lt[selmon->sellt]->arrange
  1395 				if(!c->isfloating && selmon->lt[selmon->sellt]->arrange
  1372 				&& (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
  1396 				&& (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
  1373 					togglefloating(NULL);
  1397 					togglefloating(NULL);
  1374 			}
  1398 			}
  1378 		}
  1402 		}
  1379 	} while(ev.type != ButtonRelease);
  1403 	} while(ev.type != ButtonRelease);
  1380 	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
  1404 	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
  1381 	XUngrabPointer(dpy, CurrentTime);
  1405 	XUngrabPointer(dpy, CurrentTime);
  1382 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  1406 	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
  1383 	if((m = ptrtomon(c->x + c->w / 2, c->y + c->h / 2)) != selmon) {
  1407 	if((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
  1384 		sendmon(c, m);
  1408 		sendmon(c, m);
  1385 		selmon = m;
  1409 		selmon = m;
  1386 		focus(NULL);
  1410 		focus(NULL);
  1387 	}
  1411 	}
  1388 }
  1412 }
  1414 void
  1438 void
  1415 run(void) {
  1439 run(void) {
  1416 	XEvent ev;
  1440 	XEvent ev;
  1417 	/* main event loop */
  1441 	/* main event loop */
  1418 	XSync(dpy, False);
  1442 	XSync(dpy, False);
  1419 	while(running && !XNextEvent(dpy, &ev)) {
  1443 	while(running && !XNextEvent(dpy, &ev))
  1420 		if(handler[ev.type])
  1444 		if(handler[ev.type])
  1421 			handler[ev.type](&ev); /* call handler */
  1445 			handler[ev.type](&ev); /* call handler */
  1422 	}
       
  1423 }
  1446 }
  1424 
  1447 
  1425 void
  1448 void
  1426 scan(void) {
  1449 scan(void) {
  1427 	unsigned int i, num;
  1450 	unsigned int i, num;
  1467 setclientstate(Client *c, long state) {
  1490 setclientstate(Client *c, long state) {
  1468 	long data[] = { state, None };
  1491 	long data[] = { state, None };
  1469 
  1492 
  1470 	XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
  1493 	XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
  1471 			PropModeReplace, (unsigned char *)data, 2);
  1494 			PropModeReplace, (unsigned char *)data, 2);
       
  1495 }
       
  1496 
       
  1497 Bool
       
  1498 sendevent(Client *c, Atom proto) {
       
  1499 	int n;
       
  1500 	Atom *protocols;
       
  1501 	Bool exists = False;
       
  1502 	XEvent ev;
       
  1503 
       
  1504 	if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
       
  1505 		while(!exists && n--)
       
  1506 			exists = protocols[n] == proto;
       
  1507 		XFree(protocols);
       
  1508 	}
       
  1509 	if(exists) {
       
  1510 		ev.type = ClientMessage;
       
  1511 		ev.xclient.window = c->win;
       
  1512 		ev.xclient.message_type = wmatom[WMProtocols];
       
  1513 		ev.xclient.format = 32;
       
  1514 		ev.xclient.data.l[0] = proto;
       
  1515 		ev.xclient.data.l[1] = CurrentTime;
       
  1516 		XSendEvent(dpy, c->win, False, NoEventMask, &ev);
       
  1517 	}
       
  1518 	return exists;
       
  1519 }
       
  1520 
       
  1521 void
       
  1522 setfocus(Client *c) {
       
  1523 	if(!c->neverfocus)
       
  1524 		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
       
  1525 	sendevent(c, wmatom[WMTakeFocus]);
       
  1526 }
       
  1527 
       
  1528 void
       
  1529 setfullscreen(Client *c, Bool fullscreen) {
       
  1530 	if(fullscreen) {
       
  1531 		XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
       
  1532 		                PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
       
  1533 		c->isfullscreen = True;
       
  1534 		c->oldstate = c->isfloating;
       
  1535 		c->oldbw = c->bw;
       
  1536 		c->bw = 0;
       
  1537 		c->isfloating = True;
       
  1538 		resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
       
  1539 		XRaiseWindow(dpy, c->win);
       
  1540 	}
       
  1541 	else {
       
  1542 		XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
       
  1543 		                PropModeReplace, (unsigned char*)0, 0);
       
  1544 		c->isfullscreen = False;
       
  1545 		c->isfloating = c->oldstate;
       
  1546 		c->bw = c->oldbw;
       
  1547 		c->x = c->oldx;
       
  1548 		c->y = c->oldy;
       
  1549 		c->w = c->oldw;
       
  1550 		c->h = c->oldh;
       
  1551 		resizeclient(c, c->x, c->y, c->w, c->h);
       
  1552 		arrange(c->mon);
       
  1553 	}
  1472 }
  1554 }
  1473 
  1555 
  1474 void
  1556 void
  1475 setlayout(const Arg *arg) {
  1557 setlayout(const Arg *arg) {
  1476 	if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
  1558 	if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
  1515 	updategeom();
  1597 	updategeom();
  1516 	/* init atoms */
  1598 	/* init atoms */
  1517 	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  1599 	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  1518 	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  1600 	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  1519 	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
  1601 	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
       
  1602 	wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
       
  1603 	netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
  1520 	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
  1604 	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
  1521 	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
  1605 	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
  1522 	netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
  1606 	netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
  1523 	netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
  1607 	netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
       
  1608 	netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
       
  1609 	netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
  1524 	/* init cursors */
  1610 	/* init cursors */
  1525 	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
  1611 	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
  1526 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
  1612 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
  1527 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
  1613 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
  1528 	/* init appearance */
  1614 	/* init appearance */
  1543 	/* EWMH support per view */
  1629 	/* EWMH support per view */
  1544 	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
  1630 	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
  1545 			PropModeReplace, (unsigned char *) netatom, NetLast);
  1631 			PropModeReplace, (unsigned char *) netatom, NetLast);
  1546 	/* select for events */
  1632 	/* select for events */
  1547 	wa.cursor = cursor[CurNormal];
  1633 	wa.cursor = cursor[CurNormal];
  1548 	wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask
  1634 	wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask
  1549 	                |EnterWindowMask|LeaveWindowMask|StructureNotifyMask
  1635 	                |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
  1550 	                |PropertyChangeMask;
       
  1551 	XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
  1636 	XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
  1552 	XSelectInput(dpy, root, wa.event_mask);
  1637 	XSelectInput(dpy, root, wa.event_mask);
  1553 	grabkeys();
  1638 	grabkeys();
  1554 }
  1639 }
  1555 
  1640 
  1557 showhide(Client *c) {
  1642 showhide(Client *c) {
  1558 	if(!c)
  1643 	if(!c)
  1559 		return;
  1644 		return;
  1560 	if(ISVISIBLE(c)) { /* show clients top down */
  1645 	if(ISVISIBLE(c)) { /* show clients top down */
  1561 		XMoveWindow(dpy, c->win, c->x, c->y);
  1646 		XMoveWindow(dpy, c->win, c->x, c->y);
  1562 		if(!c->mon->lt[c->mon->sellt]->arrange || c->isfloating)
  1647 		if((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen)
  1563 			resize(c, c->x, c->y, c->w, c->h, False);
  1648 			resize(c, c->x, c->y, c->w, c->h, False);
  1564 		showhide(c->snext);
  1649 		showhide(c->snext);
  1565 	}
  1650 	}
  1566 	else { /* hide clients bottom up */
  1651 	else { /* hide clients bottom up */
  1567 		showhide(c->snext);
  1652 		showhide(c->snext);
  1568 		XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
  1653 		XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
  1569 	}
  1654 	}
  1570 }
  1655 }
  1571 
  1656 
  1572 void
  1657 void
  1573 sigchld(int unused) {
  1658 sigchld(int unused) {
  1583 			close(ConnectionNumber(dpy));
  1668 			close(ConnectionNumber(dpy));
  1584 		setsid();
  1669 		setsid();
  1585 		execvp(((char **)arg->v)[0], (char **)arg->v);
  1670 		execvp(((char **)arg->v)[0], (char **)arg->v);
  1586 		fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
  1671 		fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
  1587 		perror(" failed");
  1672 		perror(" failed");
  1588 		exit(0);
  1673 		exit(EXIT_SUCCESS);
  1589 	}
  1674 	}
  1590 }
  1675 }
  1591 
  1676 
  1592 void
  1677 void
  1593 tag(const Arg *arg) {
  1678 tag(const Arg *arg) {
  1594 	if(selmon->sel && arg->ui & TAGMASK) {
  1679 	if(selmon->sel && arg->ui & TAGMASK) {
  1595 		selmon->sel->tags = arg->ui & TAGMASK;
  1680 		selmon->sel->tags = arg->ui & TAGMASK;
       
  1681 		focus(NULL);
  1596 		arrange(selmon);
  1682 		arrange(selmon);
  1597 	}
  1683 	}
  1598 }
  1684 }
  1599 
  1685 
  1600 void
  1686 void
  1615 	return XTextWidth(dc.font.xfont, text, len);
  1701 	return XTextWidth(dc.font.xfont, text, len);
  1616 }
  1702 }
  1617 
  1703 
  1618 void
  1704 void
  1619 tile(Monitor *m) {
  1705 tile(Monitor *m) {
  1620 	int x, y, h, w, mw;
  1706 	unsigned int i, n, h, mw, my, ty;
  1621 	unsigned int i, n;
       
  1622 	Client *c;
  1707 	Client *c;
  1623 
  1708 
  1624 	for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
  1709 	for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
  1625 	if(n == 0)
  1710 	if(n == 0)
  1626 		return;
  1711 		return;
  1627 	/* master */
  1712 
  1628 	c = nexttiled(m->clients);
  1713 	if(n > m->nmaster)
  1629 	mw = m->mfact * m->ww;
  1714 		mw = m->nmaster ? m->ww * m->mfact : 0;
  1630 	resize(c, m->wx, m->wy, (n == 1 ? m->ww : mw) - 2 * c->bw, m->wh - 2 * c->bw, False);
  1715 	else
  1631 	if(--n == 0)
  1716 		mw = m->ww;
  1632 		return;
  1717 	for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
  1633 	/* tile stack */
  1718 		if(i < m->nmaster) {
  1634 	x = (m->wx + mw > c->x + c->w) ? c->x + c->w + 2 * c->bw : m->wx + mw;
  1719 			h = (m->wh - my) / (MIN(n, m->nmaster) - i);
  1635 	y = m->wy;
  1720 			resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False);
  1636 	w = (m->wx + mw > c->x + c->w) ? m->wx + m->ww - x : m->ww - mw;
  1721 			my += HEIGHT(c);
  1637 	h = m->wh / n;
  1722 		}
  1638 	if(h < bh)
  1723 		else {
  1639 		h = m->wh;
  1724 			h = (m->wh - ty) / (n - i);
  1640 	for(i = 0, c = nexttiled(c->next); c; c = nexttiled(c->next), i++) {
  1725 			resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), False);
  1641 		resize(c, x, y, w - 2 * c->bw, /* remainder */ ((i + 1 == n)
  1726 			ty += HEIGHT(c);
  1642 		       ? m->wy + m->wh - y - 2 * c->bw : h - 2 * c->bw), False);
  1727 		}
  1643 		if(h != m->wh)
       
  1644 			y = c->y + HEIGHT(c);
       
  1645 	}
       
  1646 }
  1728 }
  1647 
  1729 
  1648 void
  1730 void
  1649 togglebar(const Arg *arg) {
  1731 togglebar(const Arg *arg) {
  1650 	selmon->showbar = !selmon->showbar;
  1732 	selmon->showbar = !selmon->showbar;
  1671 	if(!selmon->sel)
  1753 	if(!selmon->sel)
  1672 		return;
  1754 		return;
  1673 	newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
  1755 	newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
  1674 	if(newtags) {
  1756 	if(newtags) {
  1675 		selmon->sel->tags = newtags;
  1757 		selmon->sel->tags = newtags;
       
  1758 		focus(NULL);
  1676 		arrange(selmon);
  1759 		arrange(selmon);
  1677 	}
  1760 	}
  1678 }
  1761 }
  1679 
  1762 
  1680 void
  1763 void
  1681 toggleview(const Arg *arg) {
  1764 toggleview(const Arg *arg) {
  1682 	unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
  1765 	unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
  1683 
  1766 
  1684 	if(newtagset) {
  1767 	if(newtagset) {
  1685 		selmon->tagset[selmon->seltags] = newtagset;
  1768 		selmon->tagset[selmon->seltags] = newtagset;
       
  1769 		focus(NULL);
  1686 		arrange(selmon);
  1770 		arrange(selmon);
  1687 	}
  1771 	}
  1688 }
  1772 }
  1689 
  1773 
  1690 void
  1774 void
  1724 void
  1808 void
  1725 unmapnotify(XEvent *e) {
  1809 unmapnotify(XEvent *e) {
  1726 	Client *c;
  1810 	Client *c;
  1727 	XUnmapEvent *ev = &e->xunmap;
  1811 	XUnmapEvent *ev = &e->xunmap;
  1728 
  1812 
  1729 	if((c = wintoclient(ev->window)))
  1813 	if((c = wintoclient(ev->window))) {
  1730 		unmanage(c, False);
  1814 		if(ev->send_event)
       
  1815 			setclientstate(c, WithdrawnState);
       
  1816 		else
       
  1817 			unmanage(c, False);
       
  1818 	}
  1731 }
  1819 }
  1732 
  1820 
  1733 void
  1821 void
  1734 updatebars(void) {
  1822 updatebars(void) {
  1735 	Monitor *m;
  1823 	Monitor *m;
  1736 	XSetWindowAttributes wa;
  1824 	XSetWindowAttributes wa = {
  1737 
  1825 		.override_redirect = True,
  1738 	wa.override_redirect = True;
  1826 		.background_pixmap = ParentRelative,
  1739 	wa.background_pixmap = ParentRelative;
  1827 		.event_mask = ButtonPressMask|ExposureMask
  1740 	wa.event_mask = ButtonPressMask|ExposureMask;
  1828 	};
  1741 	for(m = mons; m; m = m->next) {
  1829 	for(m = mons; m; m = m->next) {
  1742 		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
  1830 		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
  1743 		                          CopyFromParent, DefaultVisual(dpy, screen),
  1831 		                          CopyFromParent, DefaultVisual(dpy, screen),
  1744 		                          CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
  1832 		                          CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
  1745 		XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
  1833 		XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
  1921 		strcpy(stext, "dwm-"VERSION);
  2009 		strcpy(stext, "dwm-"VERSION);
  1922 	drawbar(selmon);
  2010 	drawbar(selmon);
  1923 }
  2011 }
  1924 
  2012 
  1925 void
  2013 void
       
  2014 updatewindowtype(Client *c) {
       
  2015 	Atom state = getatomprop(c, netatom[NetWMState]);
       
  2016 	Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
       
  2017 
       
  2018 	if(state == netatom[NetWMFullscreen])
       
  2019 		setfullscreen(c, True);
       
  2020 
       
  2021 	if(wtype == netatom[NetWMWindowTypeDialog])
       
  2022 		c->isfloating = True;
       
  2023 }
       
  2024 
       
  2025 void
  1926 updatewmhints(Client *c) {
  2026 updatewmhints(Client *c) {
  1927 	XWMHints *wmh;
  2027 	XWMHints *wmh;
  1928 
  2028 
  1929 	if((wmh = XGetWMHints(dpy, c->win))) {
  2029 	if((wmh = XGetWMHints(dpy, c->win))) {
  1930 		if(c == selmon->sel && wmh->flags & XUrgencyHint) {
  2030 		if(c == selmon->sel && wmh->flags & XUrgencyHint) {
  1931 			wmh->flags &= ~XUrgencyHint;
  2031 			wmh->flags &= ~XUrgencyHint;
  1932 			XSetWMHints(dpy, c->win, wmh);
  2032 			XSetWMHints(dpy, c->win, wmh);
  1933 		}
  2033 		}
  1934 		else
  2034 		else
  1935 			c->isurgent = (wmh->flags & XUrgencyHint) ? True : False;
  2035 			c->isurgent = (wmh->flags & XUrgencyHint) ? True : False;
       
  2036 		if(wmh->flags & InputHint)
       
  2037 			c->neverfocus = !wmh->input;
       
  2038 		else
       
  2039 			c->neverfocus = False;
  1936 		XFree(wmh);
  2040 		XFree(wmh);
  1937 	}
  2041 	}
  1938 }
  2042 }
  1939 
  2043 
  1940 void
  2044 void
  1942 	if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
  2046 	if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
  1943 		return;
  2047 		return;
  1944 	selmon->seltags ^= 1; /* toggle sel tagset */
  2048 	selmon->seltags ^= 1; /* toggle sel tagset */
  1945 	if(arg->ui & TAGMASK)
  2049 	if(arg->ui & TAGMASK)
  1946 		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
  2050 		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
       
  2051 	focus(NULL);
  1947 	arrange(selmon);
  2052 	arrange(selmon);
  1948 }
  2053 }
  1949 
  2054 
  1950 Client *
  2055 Client *
  1951 wintoclient(Window w) {
  2056 wintoclient(Window w) {
  1964 	int x, y;
  2069 	int x, y;
  1965 	Client *c;
  2070 	Client *c;
  1966 	Monitor *m;
  2071 	Monitor *m;
  1967 
  2072 
  1968 	if(w == root && getrootptr(&x, &y))
  2073 	if(w == root && getrootptr(&x, &y))
  1969 		return ptrtomon(x, y);
  2074 		return recttomon(x, y, 1, 1);
  1970 	for(m = mons; m; m = m->next)
  2075 	for(m = mons; m; m = m->next)
  1971 		if(w == m->barwin)
  2076 		if(w == m->barwin)
  1972 			return m;
  2077 			return m;
  1973 	if((c = wintoclient(w)))
  2078 	if((c = wintoclient(w)))
  1974 		return c->mon;
  2079 		return c->mon;
  2011 void
  2116 void
  2012 zoom(const Arg *arg) {
  2117 zoom(const Arg *arg) {
  2013 	Client *c = selmon->sel;
  2118 	Client *c = selmon->sel;
  2014 
  2119 
  2015 	if(!selmon->lt[selmon->sellt]->arrange
  2120 	if(!selmon->lt[selmon->sellt]->arrange
  2016 	|| selmon->lt[selmon->sellt]->arrange == monocle
       
  2017 	|| (selmon->sel && selmon->sel->isfloating))
  2121 	|| (selmon->sel && selmon->sel->isfloating))
  2018 		return;
  2122 		return;
  2019 	if(c == nexttiled(selmon->clients))
  2123 	if(c == nexttiled(selmon->clients))
  2020 		if(!c || !(c = nexttiled(c->next)))
  2124 		if(!c || !(c = nexttiled(c->next)))
  2021 			return;
  2125 			return;
  2022 	detach(c);
  2126 	pop(c);
  2023 	attach(c);
       
  2024 	focus(c);
       
  2025 	arrange(c->mon);
       
  2026 }
  2127 }
  2027 
  2128 
  2028 int
  2129 int
  2029 main(int argc, char *argv[]) {
  2130 main(int argc, char *argv[]) {
  2030 	if(argc == 2 && !strcmp("-v", argv[1]))
  2131 	if(argc == 2 && !strcmp("-v", argv[1]))
  2031 		die("dwm-"VERSION", © 2006-2010 dwm engineers, see LICENSE for details\n");
  2132 		die("dwm-"VERSION", © 2006-2011 dwm engineers, see LICENSE for details\n");
  2032 	else if(argc != 1)
  2133 	else if(argc != 1)
  2033 		die("usage: dwm [-v]\n");
  2134 		die("usage: dwm [-v]\n");
  2034 	if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
  2135 	if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
  2035 		fputs("warning: no locale support\n", stderr);
  2136 		fputs("warning: no locale support\n", stderr);
  2036 	if(!(dpy = XOpenDisplay(NULL)))
  2137 	if(!(dpy = XOpenDisplay(NULL)))
  2039 	setup();
  2140 	setup();
  2040 	scan();
  2141 	scan();
  2041 	run();
  2142 	run();
  2042 	cleanup();
  2143 	cleanup();
  2043 	XCloseDisplay(dpy);
  2144 	XCloseDisplay(dpy);
  2044 	return 0;
  2145 	return EXIT_SUCCESS;
  2045 }
  2146 }