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