Introduction
Introduction Statistics Contact Development Disclaimer Help
dwm.c - dwm - dynamic window manager
git clone git://git.suckless.org/dwm
Log
Files
Refs
README
LICENSE
---
dwm.c (53238B)
---
1 /* See LICENSE file for copyright and license details.
2 *
3 * dynamic window manager is designed like any other X client as well. I…
4 * driven through handling X events. In contrast to other X clients, a w…
5 * manager selects for SubstructureRedirectMask on the root window, to r…
6 * events about window (dis-)appearance. Only one X connection at a time…
7 * allowed to select for this event mask.
8 *
9 * The event handlers of dwm are organized in an array which is accessed
10 * whenever a new event has been fetched. This allows event dispatching
11 * in O(1) time.
12 *
13 * Each child of the root window is called a client, except windows whic…
14 * set the override_redirect flag. Clients are organized in a linked cli…
15 * list on each monitor, the focus history is remembered through a stack…
16 * on each monitor. Each client contains a bit array to indicate the tag…
17 * client.
18 *
19 * Keys and tagging rules are organized as arrays and defined in config.…
20 *
21 * To understand everything else, start reading main().
22 */
23 #include <errno.h>
24 #include <locale.h>
25 #include <signal.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/wait.h>
33 #include <X11/cursorfont.h>
34 #include <X11/keysym.h>
35 #include <X11/Xatom.h>
36 #include <X11/Xlib.h>
37 #include <X11/Xproto.h>
38 #include <X11/Xutil.h>
39 #ifdef XINERAMA
40 #include <X11/extensions/Xinerama.h>
41 #endif /* XINERAMA */
42 #include <X11/Xft/Xft.h>
43
44 #include "drw.h"
45 #include "util.h"
46
47 /* macros */
48 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
49 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (Shift…
50 #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - M…
51 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - M…
52 #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->selta…
53 #define MOUSEMASK (BUTTONMASK|PointerMotionMask)
54 #define WIDTH(X) ((X)->w + 2 * (X)->bw)
55 #define HEIGHT(X) ((X)->h + 2 * (X)->bw)
56 #define TAGMASK ((1 << LENGTH(tags)) - 1)
57 #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
58
59 /* enums */
60 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
61 enum { SchemeNorm, SchemeSel }; /* color schemes */
62 enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
63 NetWMFullscreen, NetActiveWindow, NetWMWindowType,
64 NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
65 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default…
66 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
67 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
68
69 typedef union {
70 int i;
71 unsigned int ui;
72 float f;
73 const void *v;
74 } Arg;
75
76 typedef struct {
77 unsigned int click;
78 unsigned int mask;
79 unsigned int button;
80 void (*func)(const Arg *arg);
81 const Arg arg;
82 } Button;
83
84 typedef struct Monitor Monitor;
85 typedef struct Client Client;
86 struct Client {
87 char name[256];
88 float mina, maxa;
89 int x, y, w, h;
90 int oldx, oldy, oldw, oldh;
91 int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
92 int bw, oldbw;
93 unsigned int tags;
94 int isfixed, isfloating, isurgent, neverfocus, oldstate, isfulls…
95 Client *next;
96 Client *snext;
97 Monitor *mon;
98 Window win;
99 };
100
101 typedef struct {
102 unsigned int mod;
103 KeySym keysym;
104 void (*func)(const Arg *);
105 const Arg arg;
106 } Key;
107
108 typedef struct {
109 const char *symbol;
110 void (*arrange)(Monitor *);
111 } Layout;
112
113 struct Monitor {
114 char ltsymbol[16];
115 float mfact;
116 int nmaster;
117 int num;
118 int by; /* bar geometry */
119 int mx, my, mw, mh; /* screen size */
120 int wx, wy, ww, wh; /* window area */
121 unsigned int seltags;
122 unsigned int sellt;
123 unsigned int tagset[2];
124 int showbar;
125 int topbar;
126 Client *clients;
127 Client *sel;
128 Client *stack;
129 Monitor *next;
130 Window barwin;
131 const Layout *lt[2];
132 };
133
134 typedef struct {
135 const char *class;
136 const char *instance;
137 const char *title;
138 unsigned int tags;
139 int isfloating;
140 int monitor;
141 } Rule;
142
143 /* function declarations */
144 static void applyrules(Client *c);
145 static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int…
146 static void arrange(Monitor *m);
147 static void arrangemon(Monitor *m);
148 static void attach(Client *c);
149 static void attachstack(Client *c);
150 static void buttonpress(XEvent *e);
151 static void checkotherwm(void);
152 static void cleanup(void);
153 static void cleanupmon(Monitor *mon);
154 static void clientmessage(XEvent *e);
155 static void configure(Client *c);
156 static void configurenotify(XEvent *e);
157 static void configurerequest(XEvent *e);
158 static Monitor *createmon(void);
159 static void destroynotify(XEvent *e);
160 static void detach(Client *c);
161 static void detachstack(Client *c);
162 static Monitor *dirtomon(int dir);
163 static void drawbar(Monitor *m);
164 static void drawbars(void);
165 static void enternotify(XEvent *e);
166 static void expose(XEvent *e);
167 static void focus(Client *c);
168 static void focusin(XEvent *e);
169 static void focusmon(const Arg *arg);
170 static void focusstack(const Arg *arg);
171 static Atom getatomprop(Client *c, Atom prop);
172 static int getrootptr(int *x, int *y);
173 static long getstate(Window w);
174 static int gettextprop(Window w, Atom atom, char *text, unsigned int siz…
175 static void grabbuttons(Client *c, int focused);
176 static void grabkeys(void);
177 static void incnmaster(const Arg *arg);
178 static void keypress(XEvent *e);
179 static void killclient(const Arg *arg);
180 static void manage(Window w, XWindowAttributes *wa);
181 static void mappingnotify(XEvent *e);
182 static void maprequest(XEvent *e);
183 static void monocle(Monitor *m);
184 static void motionnotify(XEvent *e);
185 static void movemouse(const Arg *arg);
186 static Client *nexttiled(Client *c);
187 static void pop(Client *c);
188 static void propertynotify(XEvent *e);
189 static void quit(const Arg *arg);
190 static Monitor *recttomon(int x, int y, int w, int h);
191 static void resize(Client *c, int x, int y, int w, int h, int interact);
192 static void resizeclient(Client *c, int x, int y, int w, int h);
193 static void resizemouse(const Arg *arg);
194 static void restack(Monitor *m);
195 static void run(void);
196 static void scan(void);
197 static int sendevent(Client *c, Atom proto);
198 static void sendmon(Client *c, Monitor *m);
199 static void setclientstate(Client *c, long state);
200 static void setfocus(Client *c);
201 static void setfullscreen(Client *c, int fullscreen);
202 static void setlayout(const Arg *arg);
203 static void setmfact(const Arg *arg);
204 static void setup(void);
205 static void seturgent(Client *c, int urg);
206 static void showhide(Client *c);
207 static void spawn(const Arg *arg);
208 static void tag(const Arg *arg);
209 static void tagmon(const Arg *arg);
210 static void tile(Monitor *m);
211 static void togglebar(const Arg *arg);
212 static void togglefloating(const Arg *arg);
213 static void toggletag(const Arg *arg);
214 static void toggleview(const Arg *arg);
215 static void unfocus(Client *c, int setfocus);
216 static void unmanage(Client *c, int destroyed);
217 static void unmapnotify(XEvent *e);
218 static void updatebarpos(Monitor *m);
219 static void updatebars(void);
220 static void updateclientlist(void);
221 static int updategeom(void);
222 static void updatenumlockmask(void);
223 static void updatesizehints(Client *c);
224 static void updatestatus(void);
225 static void updatetitle(Client *c);
226 static void updatewindowtype(Client *c);
227 static void updatewmhints(Client *c);
228 static void view(const Arg *arg);
229 static Client *wintoclient(Window w);
230 static Monitor *wintomon(Window w);
231 static int xerror(Display *dpy, XErrorEvent *ee);
232 static int xerrordummy(Display *dpy, XErrorEvent *ee);
233 static int xerrorstart(Display *dpy, XErrorEvent *ee);
234 static void zoom(const Arg *arg);
235
236 /* variables */
237 static const char broken[] = "broken";
238 static char stext[256];
239 static int screen;
240 static int sw, sh; /* X display screen geometry width, height …
241 static int bh; /* bar height */
242 static int lrpad; /* sum of left and right padding for text */
243 static int (*xerrorxlib)(Display *, XErrorEvent *);
244 static unsigned int numlockmask = 0;
245 static void (*handler[LASTEvent]) (XEvent *) = {
246 [ButtonPress] = buttonpress,
247 [ClientMessage] = clientmessage,
248 [ConfigureRequest] = configurerequest,
249 [ConfigureNotify] = configurenotify,
250 [DestroyNotify] = destroynotify,
251 [EnterNotify] = enternotify,
252 [Expose] = expose,
253 [FocusIn] = focusin,
254 [KeyPress] = keypress,
255 [MappingNotify] = mappingnotify,
256 [MapRequest] = maprequest,
257 [MotionNotify] = motionnotify,
258 [PropertyNotify] = propertynotify,
259 [UnmapNotify] = unmapnotify
260 };
261 static Atom wmatom[WMLast], netatom[NetLast];
262 static int running = 1;
263 static Cur *cursor[CurLast];
264 static Clr **scheme;
265 static Display *dpy;
266 static Drw *drw;
267 static Monitor *mons, *selmon;
268 static Window root, wmcheckwin;
269
270 /* configuration, allows nested code to access above variables */
271 #include "config.h"
272
273 /* compile-time check if all tags fit into an unsigned int bit array. */
274 struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
275
276 /* function implementations */
277 void
278 applyrules(Client *c)
279 {
280 const char *class, *instance;
281 unsigned int i;
282 const Rule *r;
283 Monitor *m;
284 XClassHint ch = { NULL, NULL };
285
286 /* rule matching */
287 c->isfloating = 0;
288 c->tags = 0;
289 XGetClassHint(dpy, c->win, &ch);
290 class = ch.res_class ? ch.res_class : broken;
291 instance = ch.res_name ? ch.res_name : broken;
292
293 for (i = 0; i < LENGTH(rules); i++) {
294 r = &rules[i];
295 if ((!r->title || strstr(c->name, r->title))
296 && (!r->class || strstr(class, r->class))
297 && (!r->instance || strstr(instance, r->instance)))
298 {
299 c->isfloating = r->isfloating;
300 c->tags |= r->tags;
301 for (m = mons; m && m->num != r->monitor; m = m-…
302 if (m)
303 c->mon = m;
304 }
305 }
306 if (ch.res_class)
307 XFree(ch.res_class);
308 if (ch.res_name)
309 XFree(ch.res_name);
310 c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset…
311 }
312
313 int
314 applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact)
315 {
316 int baseismin;
317 Monitor *m = c->mon;
318
319 /* set minimum possible */
320 *w = MAX(1, *w);
321 *h = MAX(1, *h);
322 if (interact) {
323 if (*x > sw)
324 *x = sw - WIDTH(c);
325 if (*y > sh)
326 *y = sh - HEIGHT(c);
327 if (*x + *w + 2 * c->bw < 0)
328 *x = 0;
329 if (*y + *h + 2 * c->bw < 0)
330 *y = 0;
331 } else {
332 if (*x >= m->wx + m->ww)
333 *x = m->wx + m->ww - WIDTH(c);
334 if (*y >= m->wy + m->wh)
335 *y = m->wy + m->wh - HEIGHT(c);
336 if (*x + *w + 2 * c->bw <= m->wx)
337 *x = m->wx;
338 if (*y + *h + 2 * c->bw <= m->wy)
339 *y = m->wy;
340 }
341 if (*h < bh)
342 *h = bh;
343 if (*w < bh)
344 *w = bh;
345 if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->…
346 if (!c->hintsvalid)
347 updatesizehints(c);
348 /* see last two sentences in ICCCM 4.1.2.3 */
349 baseismin = c->basew == c->minw && c->baseh == c->minh;
350 if (!baseismin) { /* temporarily remove base dimensions …
351 *w -= c->basew;
352 *h -= c->baseh;
353 }
354 /* adjust for aspect limits */
355 if (c->mina > 0 && c->maxa > 0) {
356 if (c->maxa < (float)*w / *h)
357 *w = *h * c->maxa + 0.5;
358 else if (c->mina < (float)*h / *w)
359 *h = *w * c->mina + 0.5;
360 }
361 if (baseismin) { /* increment calculation requires this …
362 *w -= c->basew;
363 *h -= c->baseh;
364 }
365 /* adjust for increment value */
366 if (c->incw)
367 *w -= *w % c->incw;
368 if (c->inch)
369 *h -= *h % c->inch;
370 /* restore base dimensions */
371 *w = MAX(*w + c->basew, c->minw);
372 *h = MAX(*h + c->baseh, c->minh);
373 if (c->maxw)
374 *w = MIN(*w, c->maxw);
375 if (c->maxh)
376 *h = MIN(*h, c->maxh);
377 }
378 return *x != c->x || *y != c->y || *w != c->w || *h != c->h;
379 }
380
381 void
382 arrange(Monitor *m)
383 {
384 if (m)
385 showhide(m->stack);
386 else for (m = mons; m; m = m->next)
387 showhide(m->stack);
388 if (m) {
389 arrangemon(m);
390 restack(m);
391 } else for (m = mons; m; m = m->next)
392 arrangemon(m);
393 }
394
395 void
396 arrangemon(Monitor *m)
397 {
398 strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol…
399 if (m->lt[m->sellt]->arrange)
400 m->lt[m->sellt]->arrange(m);
401 }
402
403 void
404 attach(Client *c)
405 {
406 c->next = c->mon->clients;
407 c->mon->clients = c;
408 }
409
410 void
411 attachstack(Client *c)
412 {
413 c->snext = c->mon->stack;
414 c->mon->stack = c;
415 }
416
417 void
418 buttonpress(XEvent *e)
419 {
420 unsigned int i, x, click;
421 Arg arg = {0};
422 Client *c;
423 Monitor *m;
424 XButtonPressedEvent *ev = &e->xbutton;
425
426 click = ClkRootWin;
427 /* focus monitor if necessary */
428 if ((m = wintomon(ev->window)) && m != selmon) {
429 unfocus(selmon->sel, 1);
430 selmon = m;
431 focus(NULL);
432 }
433 if (ev->window == selmon->barwin) {
434 i = x = 0;
435 do
436 x += TEXTW(tags[i]);
437 while (ev->x >= x && ++i < LENGTH(tags));
438 if (i < LENGTH(tags)) {
439 click = ClkTagBar;
440 arg.ui = 1 << i;
441 } else if (ev->x < x + TEXTW(selmon->ltsymbol))
442 click = ClkLtSymbol;
443 else if (ev->x > selmon->ww - (int)TEXTW(stext))
444 click = ClkStatusText;
445 else
446 click = ClkWinTitle;
447 } else if ((c = wintoclient(ev->window))) {
448 focus(c);
449 restack(selmon);
450 XAllowEvents(dpy, ReplayPointer, CurrentTime);
451 click = ClkClientWin;
452 }
453 for (i = 0; i < LENGTH(buttons); i++)
454 if (click == buttons[i].click && buttons[i].func && butt…
455 && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
456 buttons[i].func(click == ClkTagBar && buttons[i]…
457 }
458
459 void
460 checkotherwm(void)
461 {
462 xerrorxlib = XSetErrorHandler(xerrorstart);
463 /* this causes an error if some other window manager is running …
464 XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMa…
465 XSync(dpy, False);
466 XSetErrorHandler(xerror);
467 XSync(dpy, False);
468 }
469
470 void
471 cleanup(void)
472 {
473 Arg a = {.ui = ~0};
474 Layout foo = { "", NULL };
475 Monitor *m;
476 size_t i;
477
478 view(&a);
479 selmon->lt[selmon->sellt] = &foo;
480 for (m = mons; m; m = m->next)
481 while (m->stack)
482 unmanage(m->stack, 0);
483 XUngrabKey(dpy, AnyKey, AnyModifier, root);
484 while (mons)
485 cleanupmon(mons);
486 for (i = 0; i < CurLast; i++)
487 drw_cur_free(drw, cursor[i]);
488 for (i = 0; i < LENGTH(colors); i++)
489 free(scheme[i]);
490 free(scheme);
491 XDestroyWindow(dpy, wmcheckwin);
492 drw_free(drw);
493 XSync(dpy, False);
494 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTim…
495 XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
496 }
497
498 void
499 cleanupmon(Monitor *mon)
500 {
501 Monitor *m;
502
503 if (mon == mons)
504 mons = mons->next;
505 else {
506 for (m = mons; m && m->next != mon; m = m->next);
507 m->next = mon->next;
508 }
509 XUnmapWindow(dpy, mon->barwin);
510 XDestroyWindow(dpy, mon->barwin);
511 free(mon);
512 }
513
514 void
515 clientmessage(XEvent *e)
516 {
517 XClientMessageEvent *cme = &e->xclient;
518 Client *c = wintoclient(cme->window);
519
520 if (!c)
521 return;
522 if (cme->message_type == netatom[NetWMState]) {
523 if (cme->data.l[1] == netatom[NetWMFullscreen]
524 || cme->data.l[2] == netatom[NetWMFullscreen])
525 setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM…
526 || (cme->data.l[0] == 2 /* _NET_WM_STATE…
527 } else if (cme->message_type == netatom[NetActiveWindow]) {
528 if (c != selmon->sel && !c->isurgent)
529 seturgent(c, 1);
530 }
531 }
532
533 void
534 configure(Client *c)
535 {
536 XConfigureEvent ce;
537
538 ce.type = ConfigureNotify;
539 ce.display = dpy;
540 ce.event = c->win;
541 ce.window = c->win;
542 ce.x = c->x;
543 ce.y = c->y;
544 ce.width = c->w;
545 ce.height = c->h;
546 ce.border_width = c->bw;
547 ce.above = None;
548 ce.override_redirect = False;
549 XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&c…
550 }
551
552 void
553 configurenotify(XEvent *e)
554 {
555 Monitor *m;
556 Client *c;
557 XConfigureEvent *ev = &e->xconfigure;
558 int dirty;
559
560 /* TODO: updategeom handling sucks, needs to be simplified */
561 if (ev->window == root) {
562 dirty = (sw != ev->width || sh != ev->height);
563 sw = ev->width;
564 sh = ev->height;
565 if (updategeom() || dirty) {
566 drw_resize(drw, sw, bh);
567 updatebars();
568 for (m = mons; m; m = m->next) {
569 for (c = m->clients; c; c = c->next)
570 if (c->isfullscreen)
571 resizeclient(c, m->mx, m…
572 XMoveResizeWindow(dpy, m->barwin, m->wx,…
573 }
574 focus(NULL);
575 arrange(NULL);
576 }
577 }
578 }
579
580 void
581 configurerequest(XEvent *e)
582 {
583 Client *c;
584 Monitor *m;
585 XConfigureRequestEvent *ev = &e->xconfigurerequest;
586 XWindowChanges wc;
587
588 if ((c = wintoclient(ev->window))) {
589 if (ev->value_mask & CWBorderWidth)
590 c->bw = ev->border_width;
591 else if (c->isfloating || !selmon->lt[selmon->sellt]->ar…
592 m = c->mon;
593 if (ev->value_mask & CWX) {
594 c->oldx = c->x;
595 c->x = m->mx + ev->x;
596 }
597 if (ev->value_mask & CWY) {
598 c->oldy = c->y;
599 c->y = m->my + ev->y;
600 }
601 if (ev->value_mask & CWWidth) {
602 c->oldw = c->w;
603 c->w = ev->width;
604 }
605 if (ev->value_mask & CWHeight) {
606 c->oldh = c->h;
607 c->h = ev->height;
608 }
609 if ((c->x + c->w) > m->mx + m->mw && c->isfloati…
610 c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2…
611 if ((c->y + c->h) > m->my + m->mh && c->isfloati…
612 c->y = m->my + (m->mh / 2 - HEIGHT(c) / …
613 if ((ev->value_mask & (CWX|CWY)) && !(ev->value_…
614 configure(c);
615 if (ISVISIBLE(c))
616 XMoveResizeWindow(dpy, c->win, c->x, c->…
617 } else
618 configure(c);
619 } else {
620 wc.x = ev->x;
621 wc.y = ev->y;
622 wc.width = ev->width;
623 wc.height = ev->height;
624 wc.border_width = ev->border_width;
625 wc.sibling = ev->above;
626 wc.stack_mode = ev->detail;
627 XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
628 }
629 XSync(dpy, False);
630 }
631
632 Monitor *
633 createmon(void)
634 {
635 Monitor *m;
636
637 m = ecalloc(1, sizeof(Monitor));
638 m->tagset[0] = m->tagset[1] = 1;
639 m->mfact = mfact;
640 m->nmaster = nmaster;
641 m->showbar = showbar;
642 m->topbar = topbar;
643 m->lt[0] = &layouts[0];
644 m->lt[1] = &layouts[1 % LENGTH(layouts)];
645 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
646 return m;
647 }
648
649 void
650 destroynotify(XEvent *e)
651 {
652 Client *c;
653 XDestroyWindowEvent *ev = &e->xdestroywindow;
654
655 if ((c = wintoclient(ev->window)))
656 unmanage(c, 1);
657 }
658
659 void
660 detach(Client *c)
661 {
662 Client **tc;
663
664 for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
665 *tc = c->next;
666 }
667
668 void
669 detachstack(Client *c)
670 {
671 Client **tc, *t;
672
673 for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
674 *tc = c->snext;
675
676 if (c == c->mon->sel) {
677 for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext…
678 c->mon->sel = t;
679 }
680 }
681
682 Monitor *
683 dirtomon(int dir)
684 {
685 Monitor *m = NULL;
686
687 if (dir > 0) {
688 if (!(m = selmon->next))
689 m = mons;
690 } else if (selmon == mons)
691 for (m = mons; m->next; m = m->next);
692 else
693 for (m = mons; m->next != selmon; m = m->next);
694 return m;
695 }
696
697 void
698 drawbar(Monitor *m)
699 {
700 int x, w, tw = 0;
701 int boxs = drw->fonts->h / 9;
702 int boxw = drw->fonts->h / 6 + 2;
703 unsigned int i, occ = 0, urg = 0;
704 Client *c;
705
706 if (!m->showbar)
707 return;
708
709 /* draw status first so it can be overdrawn by tags later */
710 if (m == selmon) { /* status is only drawn on selected monitor */
711 drw_setscheme(drw, scheme[SchemeNorm]);
712 tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
713 drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
714 }
715
716 for (c = m->clients; c; c = c->next) {
717 occ |= c->tags;
718 if (c->isurgent)
719 urg |= c->tags;
720 }
721 x = 0;
722 for (i = 0; i < LENGTH(tags); i++) {
723 w = TEXTW(tags[i]);
724 drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i…
725 drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 <…
726 if (occ & 1 << i)
727 drw_rect(drw, x + boxs, boxs, boxw, boxw,
728 m == selmon && selmon->sel && selmon->se…
729 urg & 1 << i);
730 x += w;
731 }
732 w = TEXTW(m->ltsymbol);
733 drw_setscheme(drw, scheme[SchemeNorm]);
734 x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
735
736 if ((w = m->ww - tw - x) > bh) {
737 if (m->sel) {
738 drw_setscheme(drw, scheme[m == selmon ? SchemeSe…
739 drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->na…
740 if (m->sel->isfloating)
741 drw_rect(drw, x + boxs, boxs, boxw, boxw…
742 } else {
743 drw_setscheme(drw, scheme[SchemeNorm]);
744 drw_rect(drw, x, 0, w, bh, 1, 1);
745 }
746 }
747 drw_map(drw, m->barwin, 0, 0, m->ww, bh);
748 }
749
750 void
751 drawbars(void)
752 {
753 Monitor *m;
754
755 for (m = mons; m; m = m->next)
756 drawbar(m);
757 }
758
759 void
760 enternotify(XEvent *e)
761 {
762 Client *c;
763 Monitor *m;
764 XCrossingEvent *ev = &e->xcrossing;
765
766 if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) &…
767 return;
768 c = wintoclient(ev->window);
769 m = c ? c->mon : wintomon(ev->window);
770 if (m != selmon) {
771 unfocus(selmon->sel, 1);
772 selmon = m;
773 } else if (!c || c == selmon->sel)
774 return;
775 focus(c);
776 }
777
778 void
779 expose(XEvent *e)
780 {
781 Monitor *m;
782 XExposeEvent *ev = &e->xexpose;
783
784 if (ev->count == 0 && (m = wintomon(ev->window)))
785 drawbar(m);
786 }
787
788 void
789 focus(Client *c)
790 {
791 if (!c || !ISVISIBLE(c))
792 for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext…
793 if (selmon->sel && selmon->sel != c)
794 unfocus(selmon->sel, 0);
795 if (c) {
796 if (c->mon != selmon)
797 selmon = c->mon;
798 if (c->isurgent)
799 seturgent(c, 0);
800 detachstack(c);
801 attachstack(c);
802 grabbuttons(c, 1);
803 XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorde…
804 setfocus(c);
805 } else {
806 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTi…
807 XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
808 }
809 selmon->sel = c;
810 drawbars();
811 }
812
813 /* there are some broken focus acquiring clients needing extra handling …
814 void
815 focusin(XEvent *e)
816 {
817 XFocusChangeEvent *ev = &e->xfocus;
818
819 if (selmon->sel && ev->window != selmon->sel->win)
820 setfocus(selmon->sel);
821 }
822
823 void
824 focusmon(const Arg *arg)
825 {
826 Monitor *m;
827
828 if (!mons->next)
829 return;
830 if ((m = dirtomon(arg->i)) == selmon)
831 return;
832 unfocus(selmon->sel, 0);
833 selmon = m;
834 focus(NULL);
835 }
836
837 void
838 focusstack(const Arg *arg)
839 {
840 Client *c = NULL, *i;
841
842 if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen…
843 return;
844 if (arg->i > 0) {
845 for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->n…
846 if (!c)
847 for (c = selmon->clients; c && !ISVISIBLE(c); c …
848 } else {
849 for (i = selmon->clients; i != selmon->sel; i = i->next)
850 if (ISVISIBLE(i))
851 c = i;
852 if (!c)
853 for (; i; i = i->next)
854 if (ISVISIBLE(i))
855 c = i;
856 }
857 if (c) {
858 focus(c);
859 restack(selmon);
860 }
861 }
862
863 Atom
864 getatomprop(Client *c, Atom prop)
865 {
866 int di;
867 unsigned long dl;
868 unsigned char *p = NULL;
869 Atom da, atom = None;
870
871 if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False…
872 &da, &di, &dl, &dl, &p) == Success && p) {
873 atom = *(Atom *)p;
874 XFree(p);
875 }
876 return atom;
877 }
878
879 int
880 getrootptr(int *x, int *y)
881 {
882 int di;
883 unsigned int dui;
884 Window dummy;
885
886 return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, …
887 }
888
889 long
890 getstate(Window w)
891 {
892 int format;
893 long result = -1;
894 unsigned char *p = NULL;
895 unsigned long n, extra;
896 Atom real;
897
898 if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, w…
899 &real, &format, &n, &extra, (unsigned char **)&p) != Suc…
900 return -1;
901 if (n != 0)
902 result = *p;
903 XFree(p);
904 return result;
905 }
906
907 int
908 gettextprop(Window w, Atom atom, char *text, unsigned int size)
909 {
910 char **list = NULL;
911 int n;
912 XTextProperty name;
913
914 if (!text || size == 0)
915 return 0;
916 text[0] = '\0';
917 if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems)
918 return 0;
919 if (name.encoding == XA_STRING) {
920 strncpy(text, (char *)name.value, size - 1);
921 } else if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= S…
922 strncpy(text, *list, size - 1);
923 XFreeStringList(list);
924 }
925 text[size - 1] = '\0';
926 XFree(name.value);
927 return 1;
928 }
929
930 void
931 grabbuttons(Client *c, int focused)
932 {
933 updatenumlockmask();
934 {
935 unsigned int i, j;
936 unsigned int modifiers[] = { 0, LockMask, numlockmask, n…
937 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
938 if (!focused)
939 XGrabButton(dpy, AnyButton, AnyModifier, c->win,…
940 BUTTONMASK, GrabModeSync, GrabModeSync, …
941 for (i = 0; i < LENGTH(buttons); i++)
942 if (buttons[i].click == ClkClientWin)
943 for (j = 0; j < LENGTH(modifiers); j++)
944 XGrabButton(dpy, buttons[i].butt…
945 buttons[i].mask | modifi…
946 c->win, False, BUTTONMAS…
947 GrabModeAsync, GrabModeS…
948 }
949 }
950
951 void
952 grabkeys(void)
953 {
954 updatenumlockmask();
955 {
956 unsigned int i, j, k;
957 unsigned int modifiers[] = { 0, LockMask, numlockmask, n…
958 int start, end, skip;
959 KeySym *syms;
960
961 XUngrabKey(dpy, AnyKey, AnyModifier, root);
962 XDisplayKeycodes(dpy, &start, &end);
963 syms = XGetKeyboardMapping(dpy, start, end - start + 1, …
964 if (!syms)
965 return;
966 for (k = start; k <= end; k++)
967 for (i = 0; i < LENGTH(keys); i++)
968 /* skip modifier codes, we do that ourse…
969 if (keys[i].keysym == syms[(k - start) *…
970 for (j = 0; j < LENGTH(modifiers…
971 XGrabKey(dpy, k,
972 keys[i].mod | m…
973 root, True,
974 GrabModeAsync, …
975 XFree(syms);
976 }
977 }
978
979 void
980 incnmaster(const Arg *arg)
981 {
982 selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
983 arrange(selmon);
984 }
985
986 #ifdef XINERAMA
987 static int
988 isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *i…
989 {
990 while (n--)
991 if (unique[n].x_org == info->x_org && unique[n].y_org ==…
992 && unique[n].width == info->width && unique[n].height ==…
993 return 0;
994 return 1;
995 }
996 #endif /* XINERAMA */
997
998 void
999 keypress(XEvent *e)
1000 {
1001 unsigned int i;
1002 KeySym keysym;
1003 XKeyEvent *ev;
1004
1005 ev = &e->xkey;
1006 keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
1007 for (i = 0; i < LENGTH(keys); i++)
1008 if (keysym == keys[i].keysym
1009 && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
1010 && keys[i].func)
1011 keys[i].func(&(keys[i].arg));
1012 }
1013
1014 void
1015 killclient(const Arg *arg)
1016 {
1017 if (!selmon->sel)
1018 return;
1019 if (!sendevent(selmon->sel, wmatom[WMDelete])) {
1020 XGrabServer(dpy);
1021 XSetErrorHandler(xerrordummy);
1022 XSetCloseDownMode(dpy, DestroyAll);
1023 XKillClient(dpy, selmon->sel->win);
1024 XSync(dpy, False);
1025 XSetErrorHandler(xerror);
1026 XUngrabServer(dpy);
1027 }
1028 }
1029
1030 void
1031 manage(Window w, XWindowAttributes *wa)
1032 {
1033 Client *c, *t = NULL;
1034 Window trans = None;
1035 XWindowChanges wc;
1036
1037 c = ecalloc(1, sizeof(Client));
1038 c->win = w;
1039 /* geometry */
1040 c->x = c->oldx = wa->x;
1041 c->y = c->oldy = wa->y;
1042 c->w = c->oldw = wa->width;
1043 c->h = c->oldh = wa->height;
1044 c->oldbw = wa->border_width;
1045
1046 updatetitle(c);
1047 if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(tra…
1048 c->mon = t->mon;
1049 c->tags = t->tags;
1050 } else {
1051 c->mon = selmon;
1052 applyrules(c);
1053 }
1054
1055 if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww)
1056 c->x = c->mon->wx + c->mon->ww - WIDTH(c);
1057 if (c->y + HEIGHT(c) > c->mon->wy + c->mon->wh)
1058 c->y = c->mon->wy + c->mon->wh - HEIGHT(c);
1059 c->x = MAX(c->x, c->mon->wx);
1060 c->y = MAX(c->y, c->mon->wy);
1061 c->bw = borderpx;
1062
1063 wc.border_width = c->bw;
1064 XConfigureWindow(dpy, w, CWBorderWidth, &wc);
1065 XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
1066 configure(c); /* propagates border_width, if size doesn't change…
1067 updatewindowtype(c);
1068 updatesizehints(c);
1069 updatewmhints(c);
1070 XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyCha…
1071 grabbuttons(c, 0);
1072 if (!c->isfloating)
1073 c->isfloating = c->oldstate = trans != None || c->isfixe…
1074 if (c->isfloating)
1075 XRaiseWindow(dpy, c->win);
1076 attach(c);
1077 attachstack(c);
1078 XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32…
1079 (unsigned char *) &(c->win), 1);
1080 XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h);…
1081 setclientstate(c, NormalState);
1082 if (c->mon == selmon)
1083 unfocus(selmon->sel, 0);
1084 c->mon->sel = c;
1085 arrange(c->mon);
1086 XMapWindow(dpy, c->win);
1087 focus(NULL);
1088 }
1089
1090 void
1091 mappingnotify(XEvent *e)
1092 {
1093 XMappingEvent *ev = &e->xmapping;
1094
1095 XRefreshKeyboardMapping(ev);
1096 if (ev->request == MappingKeyboard)
1097 grabkeys();
1098 }
1099
1100 void
1101 maprequest(XEvent *e)
1102 {
1103 static XWindowAttributes wa;
1104 XMapRequestEvent *ev = &e->xmaprequest;
1105
1106 if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_r…
1107 return;
1108 if (!wintoclient(ev->window))
1109 manage(ev->window, &wa);
1110 }
1111
1112 void
1113 monocle(Monitor *m)
1114 {
1115 unsigned int n = 0;
1116 Client *c;
1117
1118 for (c = m->clients; c; c = c->next)
1119 if (ISVISIBLE(c))
1120 n++;
1121 if (n > 0) /* override layout symbol */
1122 snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
1123 for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
1124 resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c…
1125 }
1126
1127 void
1128 motionnotify(XEvent *e)
1129 {
1130 static Monitor *mon = NULL;
1131 Monitor *m;
1132 XMotionEvent *ev = &e->xmotion;
1133
1134 if (ev->window != root)
1135 return;
1136 if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon)…
1137 unfocus(selmon->sel, 1);
1138 selmon = m;
1139 focus(NULL);
1140 }
1141 mon = m;
1142 }
1143
1144 void
1145 movemouse(const Arg *arg)
1146 {
1147 int x, y, ocx, ocy, nx, ny;
1148 Client *c;
1149 Monitor *m;
1150 XEvent ev;
1151 Time lasttime = 0;
1152
1153 if (!(c = selmon->sel))
1154 return;
1155 if (c->isfullscreen) /* no support moving fullscreen windows by …
1156 return;
1157 restack(selmon);
1158 ocx = c->x;
1159 ocy = c->y;
1160 if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, Gra…
1161 None, cursor[CurMove]->cursor, CurrentTime) != GrabSucce…
1162 return;
1163 if (!getrootptr(&x, &y))
1164 return;
1165 do {
1166 XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedir…
1167 switch(ev.type) {
1168 case ConfigureRequest:
1169 case Expose:
1170 case MapRequest:
1171 handler[ev.type](&ev);
1172 break;
1173 case MotionNotify:
1174 if ((ev.xmotion.time - lasttime) <= (1000 / 60))
1175 continue;
1176 lasttime = ev.xmotion.time;
1177
1178 nx = ocx + (ev.xmotion.x - x);
1179 ny = ocy + (ev.xmotion.y - y);
1180 if (abs(selmon->wx - nx) < snap)
1181 nx = selmon->wx;
1182 else if (abs((selmon->wx + selmon->ww) - (nx + W…
1183 nx = selmon->wx + selmon->ww - WIDTH(c);
1184 if (abs(selmon->wy - ny) < snap)
1185 ny = selmon->wy;
1186 else if (abs((selmon->wy + selmon->wh) - (ny + H…
1187 ny = selmon->wy + selmon->wh - HEIGHT(c);
1188 if (!c->isfloating && selmon->lt[selmon->sellt]-…
1189 && (abs(nx - c->x) > snap || abs(ny - c->y) > sn…
1190 togglefloating(NULL);
1191 if (!selmon->lt[selmon->sellt]->arrange || c->is…
1192 resize(c, nx, ny, c->w, c->h, 1);
1193 break;
1194 }
1195 } while (ev.type != ButtonRelease);
1196 XUngrabPointer(dpy, CurrentTime);
1197 if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
1198 sendmon(c, m);
1199 selmon = m;
1200 focus(NULL);
1201 }
1202 }
1203
1204 Client *
1205 nexttiled(Client *c)
1206 {
1207 for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
1208 return c;
1209 }
1210
1211 void
1212 pop(Client *c)
1213 {
1214 detach(c);
1215 attach(c);
1216 focus(c);
1217 arrange(c->mon);
1218 }
1219
1220 void
1221 propertynotify(XEvent *e)
1222 {
1223 Client *c;
1224 Window trans;
1225 XPropertyEvent *ev = &e->xproperty;
1226
1227 if ((ev->window == root) && (ev->atom == XA_WM_NAME))
1228 updatestatus();
1229 else if (ev->state == PropertyDelete)
1230 return; /* ignore */
1231 else if ((c = wintoclient(ev->window))) {
1232 switch(ev->atom) {
1233 default: break;
1234 case XA_WM_TRANSIENT_FOR:
1235 if (!c->isfloating && (XGetTransientForHint(dpy,…
1236 (c->isfloating = (wintoclient(trans)) !=…
1237 arrange(c->mon);
1238 break;
1239 case XA_WM_NORMAL_HINTS:
1240 c->hintsvalid = 0;
1241 break;
1242 case XA_WM_HINTS:
1243 updatewmhints(c);
1244 drawbars();
1245 break;
1246 }
1247 if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMN…
1248 updatetitle(c);
1249 if (c == c->mon->sel)
1250 drawbar(c->mon);
1251 }
1252 if (ev->atom == netatom[NetWMWindowType])
1253 updatewindowtype(c);
1254 }
1255 }
1256
1257 void
1258 quit(const Arg *arg)
1259 {
1260 running = 0;
1261 }
1262
1263 Monitor *
1264 recttomon(int x, int y, int w, int h)
1265 {
1266 Monitor *m, *r = selmon;
1267 int a, area = 0;
1268
1269 for (m = mons; m; m = m->next)
1270 if ((a = INTERSECT(x, y, w, h, m)) > area) {
1271 area = a;
1272 r = m;
1273 }
1274 return r;
1275 }
1276
1277 void
1278 resize(Client *c, int x, int y, int w, int h, int interact)
1279 {
1280 if (applysizehints(c, &x, &y, &w, &h, interact))
1281 resizeclient(c, x, y, w, h);
1282 }
1283
1284 void
1285 resizeclient(Client *c, int x, int y, int w, int h)
1286 {
1287 XWindowChanges wc;
1288
1289 c->oldx = c->x; c->x = wc.x = x;
1290 c->oldy = c->y; c->y = wc.y = y;
1291 c->oldw = c->w; c->w = wc.width = w;
1292 c->oldh = c->h; c->h = wc.height = h;
1293 wc.border_width = c->bw;
1294 XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderW…
1295 configure(c);
1296 XSync(dpy, False);
1297 }
1298
1299 void
1300 resizemouse(const Arg *arg)
1301 {
1302 int ocx, ocy, nw, nh;
1303 Client *c;
1304 Monitor *m;
1305 XEvent ev;
1306 Time lasttime = 0;
1307
1308 if (!(c = selmon->sel))
1309 return;
1310 if (c->isfullscreen) /* no support resizing fullscreen windows b…
1311 return;
1312 restack(selmon);
1313 ocx = c->x;
1314 ocy = c->y;
1315 if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, Gra…
1316 None, cursor[CurResize]->cursor, CurrentTime) != GrabSuc…
1317 return;
1318 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c-…
1319 do {
1320 XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedir…
1321 switch(ev.type) {
1322 case ConfigureRequest:
1323 case Expose:
1324 case MapRequest:
1325 handler[ev.type](&ev);
1326 break;
1327 case MotionNotify:
1328 if ((ev.xmotion.time - lasttime) <= (1000 / 60))
1329 continue;
1330 lasttime = ev.xmotion.time;
1331
1332 nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
1333 nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
1334 if (c->mon->wx + nw >= selmon->wx && c->mon->wx …
1335 && c->mon->wy + nh >= selmon->wy && c->mon->wy +…
1336 {
1337 if (!c->isfloating && selmon->lt[selmon-…
1338 && (abs(nw - c->w) > snap || abs(nh - c-…
1339 togglefloating(NULL);
1340 }
1341 if (!selmon->lt[selmon->sellt]->arrange || c->is…
1342 resize(c, c->x, c->y, nw, nh, 1);
1343 break;
1344 }
1345 } while (ev.type != ButtonRelease);
1346 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c-…
1347 XUngrabPointer(dpy, CurrentTime);
1348 while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
1349 if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
1350 sendmon(c, m);
1351 selmon = m;
1352 focus(NULL);
1353 }
1354 }
1355
1356 void
1357 restack(Monitor *m)
1358 {
1359 Client *c;
1360 XEvent ev;
1361 XWindowChanges wc;
1362
1363 drawbar(m);
1364 if (!m->sel)
1365 return;
1366 if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
1367 XRaiseWindow(dpy, m->sel->win);
1368 if (m->lt[m->sellt]->arrange) {
1369 wc.stack_mode = Below;
1370 wc.sibling = m->barwin;
1371 for (c = m->stack; c; c = c->snext)
1372 if (!c->isfloating && ISVISIBLE(c)) {
1373 XConfigureWindow(dpy, c->win, CWSibling|…
1374 wc.sibling = c->win;
1375 }
1376 }
1377 XSync(dpy, False);
1378 while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
1379 }
1380
1381 void
1382 run(void)
1383 {
1384 XEvent ev;
1385 /* main event loop */
1386 XSync(dpy, False);
1387 while (running && !XNextEvent(dpy, &ev))
1388 if (handler[ev.type])
1389 handler[ev.type](&ev); /* call handler */
1390 }
1391
1392 void
1393 scan(void)
1394 {
1395 unsigned int i, num;
1396 Window d1, d2, *wins = NULL;
1397 XWindowAttributes wa;
1398
1399 if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
1400 for (i = 0; i < num; i++) {
1401 if (!XGetWindowAttributes(dpy, wins[i], &wa)
1402 || wa.override_redirect || XGetTransientForHint(…
1403 continue;
1404 if (wa.map_state == IsViewable || getstate(wins[…
1405 manage(wins[i], &wa);
1406 }
1407 for (i = 0; i < num; i++) { /* now the transients */
1408 if (!XGetWindowAttributes(dpy, wins[i], &wa))
1409 continue;
1410 if (XGetTransientForHint(dpy, wins[i], &d1)
1411 && (wa.map_state == IsViewable || getstate(wins[…
1412 manage(wins[i], &wa);
1413 }
1414 if (wins)
1415 XFree(wins);
1416 }
1417 }
1418
1419 void
1420 sendmon(Client *c, Monitor *m)
1421 {
1422 if (c->mon == m)
1423 return;
1424 unfocus(c, 1);
1425 detach(c);
1426 detachstack(c);
1427 c->mon = m;
1428 c->tags = m->tagset[m->seltags]; /* assign tags of target monito…
1429 attach(c);
1430 attachstack(c);
1431 focus(NULL);
1432 arrange(NULL);
1433 }
1434
1435 void
1436 setclientstate(Client *c, long state)
1437 {
1438 long data[] = { state, None };
1439
1440 XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 3…
1441 PropModeReplace, (unsigned char *)data, 2);
1442 }
1443
1444 int
1445 sendevent(Client *c, Atom proto)
1446 {
1447 int n;
1448 Atom *protocols;
1449 int exists = 0;
1450 XEvent ev;
1451
1452 if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
1453 while (!exists && n--)
1454 exists = protocols[n] == proto;
1455 XFree(protocols);
1456 }
1457 if (exists) {
1458 ev.type = ClientMessage;
1459 ev.xclient.window = c->win;
1460 ev.xclient.message_type = wmatom[WMProtocols];
1461 ev.xclient.format = 32;
1462 ev.xclient.data.l[0] = proto;
1463 ev.xclient.data.l[1] = CurrentTime;
1464 XSendEvent(dpy, c->win, False, NoEventMask, &ev);
1465 }
1466 return exists;
1467 }
1468
1469 void
1470 setfocus(Client *c)
1471 {
1472 if (!c->neverfocus) {
1473 XSetInputFocus(dpy, c->win, RevertToPointerRoot, Current…
1474 XChangeProperty(dpy, root, netatom[NetActiveWindow],
1475 XA_WINDOW, 32, PropModeReplace,
1476 (unsigned char *) &(c->win), 1);
1477 }
1478 sendevent(c, wmatom[WMTakeFocus]);
1479 }
1480
1481 void
1482 setfullscreen(Client *c, int fullscreen)
1483 {
1484 if (fullscreen && !c->isfullscreen) {
1485 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATO…
1486 PropModeReplace, (unsigned char*)&netatom[NetWMF…
1487 c->isfullscreen = 1;
1488 c->oldstate = c->isfloating;
1489 c->oldbw = c->bw;
1490 c->bw = 0;
1491 c->isfloating = 1;
1492 resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->m…
1493 XRaiseWindow(dpy, c->win);
1494 } else if (!fullscreen && c->isfullscreen){
1495 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATO…
1496 PropModeReplace, (unsigned char*)0, 0);
1497 c->isfullscreen = 0;
1498 c->isfloating = c->oldstate;
1499 c->bw = c->oldbw;
1500 c->x = c->oldx;
1501 c->y = c->oldy;
1502 c->w = c->oldw;
1503 c->h = c->oldh;
1504 resizeclient(c, c->x, c->y, c->w, c->h);
1505 arrange(c->mon);
1506 }
1507 }
1508
1509 void
1510 setlayout(const Arg *arg)
1511 {
1512 if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
1513 selmon->sellt ^= 1;
1514 if (arg && arg->v)
1515 selmon->lt[selmon->sellt] = (Layout *)arg->v;
1516 strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, siz…
1517 if (selmon->sel)
1518 arrange(selmon);
1519 else
1520 drawbar(selmon);
1521 }
1522
1523 /* arg > 1.0 will set mfact absolutely */
1524 void
1525 setmfact(const Arg *arg)
1526 {
1527 float f;
1528
1529 if (!arg || !selmon->lt[selmon->sellt]->arrange)
1530 return;
1531 f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
1532 if (f < 0.05 || f > 0.95)
1533 return;
1534 selmon->mfact = f;
1535 arrange(selmon);
1536 }
1537
1538 void
1539 setup(void)
1540 {
1541 int i;
1542 XSetWindowAttributes wa;
1543 Atom utf8string;
1544 struct sigaction sa;
1545
1546 /* do not transform children into zombies when they terminate */
1547 sigemptyset(&sa.sa_mask);
1548 sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART;
1549 sa.sa_handler = SIG_IGN;
1550 sigaction(SIGCHLD, &sa, NULL);
1551
1552 /* clean up any zombies (inherited from .xinitrc etc) immediatel…
1553 while (waitpid(-1, NULL, WNOHANG) > 0);
1554
1555 /* init screen */
1556 screen = DefaultScreen(dpy);
1557 sw = DisplayWidth(dpy, screen);
1558 sh = DisplayHeight(dpy, screen);
1559 root = RootWindow(dpy, screen);
1560 drw = drw_create(dpy, screen, root, sw, sh);
1561 if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
1562 die("no fonts could be loaded.");
1563 lrpad = drw->fonts->h;
1564 bh = drw->fonts->h + 2;
1565 updategeom();
1566 /* init atoms */
1567 utf8string = XInternAtom(dpy, "UTF8_STRING", False);
1568 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
1569 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
1570 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
1571 wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
1572 netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW"…
1573 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False…
1574 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
1575 netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
1576 netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK…
1577 netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLS…
1578 netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE…
1579 netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDO…
1580 netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", Fa…
1581 /* init cursors */
1582 cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
1583 cursor[CurResize] = drw_cur_create(drw, XC_sizing);
1584 cursor[CurMove] = drw_cur_create(drw, XC_fleur);
1585 /* init appearance */
1586 scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
1587 for (i = 0; i < LENGTH(colors); i++)
1588 scheme[i] = drw_scm_create(drw, colors[i], 3);
1589 /* init bars */
1590 updatebars();
1591 updatestatus();
1592 /* supporting window for NetWMCheck */
1593 wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0);
1594 XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW,…
1595 PropModeReplace, (unsigned char *) &wmcheckwin, 1);
1596 XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string,…
1597 PropModeReplace, (unsigned char *) "dwm", 3);
1598 XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32,
1599 PropModeReplace, (unsigned char *) &wmcheckwin, 1);
1600 /* EWMH support per view */
1601 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
1602 PropModeReplace, (unsigned char *) netatom, NetLast);
1603 XDeleteProperty(dpy, root, netatom[NetClientList]);
1604 /* select events */
1605 wa.cursor = cursor[CurNormal]->cursor;
1606 wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
1607 |ButtonPressMask|PointerMotionMask|EnterWindowMask
1608 |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
1609 XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
1610 XSelectInput(dpy, root, wa.event_mask);
1611 grabkeys();
1612 focus(NULL);
1613 }
1614
1615 void
1616 seturgent(Client *c, int urg)
1617 {
1618 XWMHints *wmh;
1619
1620 c->isurgent = urg;
1621 if (!(wmh = XGetWMHints(dpy, c->win)))
1622 return;
1623 wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~…
1624 XSetWMHints(dpy, c->win, wmh);
1625 XFree(wmh);
1626 }
1627
1628 void
1629 showhide(Client *c)
1630 {
1631 if (!c)
1632 return;
1633 if (ISVISIBLE(c)) {
1634 /* show clients top down */
1635 XMoveWindow(dpy, c->win, c->x, c->y);
1636 if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloatin…
1637 resize(c, c->x, c->y, c->w, c->h, 0);
1638 showhide(c->snext);
1639 } else {
1640 /* hide clients bottom up */
1641 showhide(c->snext);
1642 XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
1643 }
1644 }
1645
1646 void
1647 spawn(const Arg *arg)
1648 {
1649 struct sigaction sa;
1650
1651 if (arg->v == dmenucmd)
1652 dmenumon[0] = '0' + selmon->num;
1653 if (fork() == 0) {
1654 if (dpy)
1655 close(ConnectionNumber(dpy));
1656 setsid();
1657
1658 sigemptyset(&sa.sa_mask);
1659 sa.sa_flags = 0;
1660 sa.sa_handler = SIG_DFL;
1661 sigaction(SIGCHLD, &sa, NULL);
1662
1663 execvp(((char **)arg->v)[0], (char **)arg->v);
1664 die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]);
1665 }
1666 }
1667
1668 void
1669 tag(const Arg *arg)
1670 {
1671 if (selmon->sel && arg->ui & TAGMASK) {
1672 selmon->sel->tags = arg->ui & TAGMASK;
1673 focus(NULL);
1674 arrange(selmon);
1675 }
1676 }
1677
1678 void
1679 tagmon(const Arg *arg)
1680 {
1681 if (!selmon->sel || !mons->next)
1682 return;
1683 sendmon(selmon->sel, dirtomon(arg->i));
1684 }
1685
1686 void
1687 tile(Monitor *m)
1688 {
1689 unsigned int i, n, h, mw, my, ty;
1690 Client *c;
1691
1692 for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)…
1693 if (n == 0)
1694 return;
1695
1696 if (n > m->nmaster)
1697 mw = m->nmaster ? m->ww * m->mfact : 0;
1698 else
1699 mw = m->ww;
1700 for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttile…
1701 if (i < m->nmaster) {
1702 h = (m->wh - my) / (MIN(n, m->nmaster) - i);
1703 resize(c, m->wx, m->wy + my, mw - (2*c->bw), h -…
1704 if (my + HEIGHT(c) < m->wh)
1705 my += HEIGHT(c);
1706 } else {
1707 h = (m->wh - ty) / (n - i);
1708 resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (…
1709 if (ty + HEIGHT(c) < m->wh)
1710 ty += HEIGHT(c);
1711 }
1712 }
1713
1714 void
1715 togglebar(const Arg *arg)
1716 {
1717 selmon->showbar = !selmon->showbar;
1718 updatebarpos(selmon);
1719 XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, s…
1720 arrange(selmon);
1721 }
1722
1723 void
1724 togglefloating(const Arg *arg)
1725 {
1726 if (!selmon->sel)
1727 return;
1728 if (selmon->sel->isfullscreen) /* no support for fullscreen wind…
1729 return;
1730 selmon->sel->isfloating = !selmon->sel->isfloating || selmon->se…
1731 if (selmon->sel->isfloating)
1732 resize(selmon->sel, selmon->sel->x, selmon->sel->y,
1733 selmon->sel->w, selmon->sel->h, 0);
1734 arrange(selmon);
1735 }
1736
1737 void
1738 toggletag(const Arg *arg)
1739 {
1740 unsigned int newtags;
1741
1742 if (!selmon->sel)
1743 return;
1744 newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
1745 if (newtags) {
1746 selmon->sel->tags = newtags;
1747 focus(NULL);
1748 arrange(selmon);
1749 }
1750 }
1751
1752 void
1753 toggleview(const Arg *arg)
1754 {
1755 unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg-…
1756
1757 if (newtagset) {
1758 selmon->tagset[selmon->seltags] = newtagset;
1759 focus(NULL);
1760 arrange(selmon);
1761 }
1762 }
1763
1764 void
1765 unfocus(Client *c, int setfocus)
1766 {
1767 if (!c)
1768 return;
1769 grabbuttons(c, 0);
1770 XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixe…
1771 if (setfocus) {
1772 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTi…
1773 XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
1774 }
1775 }
1776
1777 void
1778 unmanage(Client *c, int destroyed)
1779 {
1780 Monitor *m = c->mon;
1781 XWindowChanges wc;
1782
1783 detach(c);
1784 detachstack(c);
1785 if (!destroyed) {
1786 wc.border_width = c->oldbw;
1787 XGrabServer(dpy); /* avoid race conditions */
1788 XSetErrorHandler(xerrordummy);
1789 XSelectInput(dpy, c->win, NoEventMask);
1790 XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* re…
1791 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
1792 setclientstate(c, WithdrawnState);
1793 XSync(dpy, False);
1794 XSetErrorHandler(xerror);
1795 XUngrabServer(dpy);
1796 }
1797 free(c);
1798 focus(NULL);
1799 updateclientlist();
1800 arrange(m);
1801 }
1802
1803 void
1804 unmapnotify(XEvent *e)
1805 {
1806 Client *c;
1807 XUnmapEvent *ev = &e->xunmap;
1808
1809 if ((c = wintoclient(ev->window))) {
1810 if (ev->send_event)
1811 setclientstate(c, WithdrawnState);
1812 else
1813 unmanage(c, 0);
1814 }
1815 }
1816
1817 void
1818 updatebars(void)
1819 {
1820 Monitor *m;
1821 XSetWindowAttributes wa = {
1822 .override_redirect = True,
1823 .background_pixmap = ParentRelative,
1824 .event_mask = ButtonPressMask|ExposureMask
1825 };
1826 XClassHint ch = {"dwm", "dwm"};
1827 for (m = mons; m; m = m->next) {
1828 if (m->barwin)
1829 continue;
1830 m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww…
1831 CopyFromParent, DefaultVisual(dpy, scree…
1832 CWOverrideRedirect|CWBackPixmap|CWEventM…
1833 XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
1834 XMapRaised(dpy, m->barwin);
1835 XSetClassHint(dpy, m->barwin, &ch);
1836 }
1837 }
1838
1839 void
1840 updatebarpos(Monitor *m)
1841 {
1842 m->wy = m->my;
1843 m->wh = m->mh;
1844 if (m->showbar) {
1845 m->wh -= bh;
1846 m->by = m->topbar ? m->wy : m->wy + m->wh;
1847 m->wy = m->topbar ? m->wy + bh : m->wy;
1848 } else
1849 m->by = -bh;
1850 }
1851
1852 void
1853 updateclientlist(void)
1854 {
1855 Client *c;
1856 Monitor *m;
1857
1858 XDeleteProperty(dpy, root, netatom[NetClientList]);
1859 for (m = mons; m; m = m->next)
1860 for (c = m->clients; c; c = c->next)
1861 XChangeProperty(dpy, root, netatom[NetClientList…
1862 XA_WINDOW, 32, PropModeAppend,
1863 (unsigned char *) &(c->win), 1);
1864 }
1865
1866 int
1867 updategeom(void)
1868 {
1869 int dirty = 0;
1870
1871 #ifdef XINERAMA
1872 if (XineramaIsActive(dpy)) {
1873 int i, j, n, nn;
1874 Client *c;
1875 Monitor *m;
1876 XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn…
1877 XineramaScreenInfo *unique = NULL;
1878
1879 for (n = 0, m = mons; m; m = m->next, n++);
1880 /* only consider unique geometries as separate screens */
1881 unique = ecalloc(nn, sizeof(XineramaScreenInfo));
1882 for (i = 0, j = 0; i < nn; i++)
1883 if (isuniquegeom(unique, j, &info[i]))
1884 memcpy(&unique[j++], &info[i], sizeof(Xi…
1885 XFree(info);
1886 nn = j;
1887
1888 /* new monitors if nn > n */
1889 for (i = n; i < nn; i++) {
1890 for (m = mons; m && m->next; m = m->next);
1891 if (m)
1892 m->next = createmon();
1893 else
1894 mons = createmon();
1895 }
1896 for (i = 0, m = mons; i < nn && m; m = m->next, i++)
1897 if (i >= n
1898 || unique[i].x_org != m->mx || unique[i].y_org !…
1899 || unique[i].width != m->mw || unique[i].height …
1900 {
1901 dirty = 1;
1902 m->num = i;
1903 m->mx = m->wx = unique[i].x_org;
1904 m->my = m->wy = unique[i].y_org;
1905 m->mw = m->ww = unique[i].width;
1906 m->mh = m->wh = unique[i].height;
1907 updatebarpos(m);
1908 }
1909 /* removed monitors if n > nn */
1910 for (i = nn; i < n; i++) {
1911 for (m = mons; m && m->next; m = m->next);
1912 while ((c = m->clients)) {
1913 dirty = 1;
1914 m->clients = c->next;
1915 detachstack(c);
1916 c->mon = mons;
1917 attach(c);
1918 attachstack(c);
1919 }
1920 if (m == selmon)
1921 selmon = mons;
1922 cleanupmon(m);
1923 }
1924 free(unique);
1925 } else
1926 #endif /* XINERAMA */
1927 { /* default monitor setup */
1928 if (!mons)
1929 mons = createmon();
1930 if (mons->mw != sw || mons->mh != sh) {
1931 dirty = 1;
1932 mons->mw = mons->ww = sw;
1933 mons->mh = mons->wh = sh;
1934 updatebarpos(mons);
1935 }
1936 }
1937 if (dirty) {
1938 selmon = mons;
1939 selmon = wintomon(root);
1940 }
1941 return dirty;
1942 }
1943
1944 void
1945 updatenumlockmask(void)
1946 {
1947 unsigned int i, j;
1948 XModifierKeymap *modmap;
1949
1950 numlockmask = 0;
1951 modmap = XGetModifierMapping(dpy);
1952 for (i = 0; i < 8; i++)
1953 for (j = 0; j < modmap->max_keypermod; j++)
1954 if (modmap->modifiermap[i * modmap->max_keypermo…
1955 == XKeysymToKeycode(dpy, XK_Num_Lock))
1956 numlockmask = (1 << i);
1957 XFreeModifiermap(modmap);
1958 }
1959
1960 void
1961 updatesizehints(Client *c)
1962 {
1963 long msize;
1964 XSizeHints size;
1965
1966 if (!XGetWMNormalHints(dpy, c->win, &size, &msize))
1967 /* size is uninitialized, ensure that size.flags aren't …
1968 size.flags = PSize;
1969 if (size.flags & PBaseSize) {
1970 c->basew = size.base_width;
1971 c->baseh = size.base_height;
1972 } else if (size.flags & PMinSize) {
1973 c->basew = size.min_width;
1974 c->baseh = size.min_height;
1975 } else
1976 c->basew = c->baseh = 0;
1977 if (size.flags & PResizeInc) {
1978 c->incw = size.width_inc;
1979 c->inch = size.height_inc;
1980 } else
1981 c->incw = c->inch = 0;
1982 if (size.flags & PMaxSize) {
1983 c->maxw = size.max_width;
1984 c->maxh = size.max_height;
1985 } else
1986 c->maxw = c->maxh = 0;
1987 if (size.flags & PMinSize) {
1988 c->minw = size.min_width;
1989 c->minh = size.min_height;
1990 } else if (size.flags & PBaseSize) {
1991 c->minw = size.base_width;
1992 c->minh = size.base_height;
1993 } else
1994 c->minw = c->minh = 0;
1995 if (size.flags & PAspect) {
1996 c->mina = (float)size.min_aspect.y / size.min_aspect.x;
1997 c->maxa = (float)size.max_aspect.x / size.max_aspect.y;
1998 } else
1999 c->maxa = c->mina = 0.0;
2000 c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->max…
2001 c->hintsvalid = 1;
2002 }
2003
2004 void
2005 updatestatus(void)
2006 {
2007 if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
2008 strcpy(stext, "dwm-"VERSION);
2009 drawbar(selmon);
2010 }
2011
2012 void
2013 updatetitle(Client *c)
2014 {
2015 if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->…
2016 gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
2017 if (c->name[0] == '\0') /* hack to mark broken clients */
2018 strcpy(c->name, broken);
2019 }
2020
2021 void
2022 updatewindowtype(Client *c)
2023 {
2024 Atom state = getatomprop(c, netatom[NetWMState]);
2025 Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
2026
2027 if (state == netatom[NetWMFullscreen])
2028 setfullscreen(c, 1);
2029 if (wtype == netatom[NetWMWindowTypeDialog])
2030 c->isfloating = 1;
2031 }
2032
2033 void
2034 updatewmhints(Client *c)
2035 {
2036 XWMHints *wmh;
2037
2038 if ((wmh = XGetWMHints(dpy, c->win))) {
2039 if (c == selmon->sel && wmh->flags & XUrgencyHint) {
2040 wmh->flags &= ~XUrgencyHint;
2041 XSetWMHints(dpy, c->win, wmh);
2042 } else
2043 c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : …
2044 if (wmh->flags & InputHint)
2045 c->neverfocus = !wmh->input;
2046 else
2047 c->neverfocus = 0;
2048 XFree(wmh);
2049 }
2050 }
2051
2052 void
2053 view(const Arg *arg)
2054 {
2055 if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
2056 return;
2057 selmon->seltags ^= 1; /* toggle sel tagset */
2058 if (arg->ui & TAGMASK)
2059 selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
2060 focus(NULL);
2061 arrange(selmon);
2062 }
2063
2064 Client *
2065 wintoclient(Window w)
2066 {
2067 Client *c;
2068 Monitor *m;
2069
2070 for (m = mons; m; m = m->next)
2071 for (c = m->clients; c; c = c->next)
2072 if (c->win == w)
2073 return c;
2074 return NULL;
2075 }
2076
2077 Monitor *
2078 wintomon(Window w)
2079 {
2080 int x, y;
2081 Client *c;
2082 Monitor *m;
2083
2084 if (w == root && getrootptr(&x, &y))
2085 return recttomon(x, y, 1, 1);
2086 for (m = mons; m; m = m->next)
2087 if (w == m->barwin)
2088 return m;
2089 if ((c = wintoclient(w)))
2090 return c->mon;
2091 return selmon;
2092 }
2093
2094 /* There's no way to check accesses to destroyed windows, thus those cas…
2095 * ignored (especially on UnmapNotify's). Other types of errors call Xli…
2096 * default error handler, which may call exit. */
2097 int
2098 xerror(Display *dpy, XErrorEvent *ee)
2099 {
2100 if (ee->error_code == BadWindow
2101 || (ee->request_code == X_SetInputFocus && ee->error_code == Bad…
2102 || (ee->request_code == X_PolyText8 && ee->error_code == BadDraw…
2103 || (ee->request_code == X_PolyFillRectangle && ee->error_code ==…
2104 || (ee->request_code == X_PolySegment && ee->error_code == BadDr…
2105 || (ee->request_code == X_ConfigureWindow && ee->error_code == B…
2106 || (ee->request_code == X_GrabButton && ee->error_code == BadAcc…
2107 || (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
2108 || (ee->request_code == X_CopyArea && ee->error_code == BadDrawa…
2109 return 0;
2110 fprintf(stderr, "dwm: fatal error: request code=%d, error code=%…
2111 ee->request_code, ee->error_code);
2112 return xerrorxlib(dpy, ee); /* may call exit */
2113 }
2114
2115 int
2116 xerrordummy(Display *dpy, XErrorEvent *ee)
2117 {
2118 return 0;
2119 }
2120
2121 /* Startup Error handler to check if another window manager
2122 * is already running. */
2123 int
2124 xerrorstart(Display *dpy, XErrorEvent *ee)
2125 {
2126 die("dwm: another window manager is already running");
2127 return -1;
2128 }
2129
2130 void
2131 zoom(const Arg *arg)
2132 {
2133 Client *c = selmon->sel;
2134
2135 if (!selmon->lt[selmon->sellt]->arrange || !c || c->isfloating)
2136 return;
2137 if (c == nexttiled(selmon->clients) && !(c = nexttiled(c->next)))
2138 return;
2139 pop(c);
2140 }
2141
2142 int
2143 main(int argc, char *argv[])
2144 {
2145 if (argc == 2 && !strcmp("-v", argv[1]))
2146 die("dwm-"VERSION);
2147 else if (argc != 1)
2148 die("usage: dwm [-v]");
2149 if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
2150 fputs("warning: no locale support\n", stderr);
2151 if (!(dpy = XOpenDisplay(NULL)))
2152 die("dwm: cannot open display");
2153 checkotherwm();
2154 setup();
2155 #ifdef __OpenBSD__
2156 if (pledge("stdio rpath proc exec", NULL) == -1)
2157 die("pledge");
2158 #endif /* __OpenBSD__ */
2159 scan();
2160 run();
2161 cleanup();
2162 XCloseDisplay(dpy);
2163 return EXIT_SUCCESS;
2164 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.