t* dwm + patches
       
   URI git clone git://git.codevoid.de/dwm-sdk
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tdwm.c (78817B)
       ---
            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 LENGTH(X)               (sizeof X / sizeof X[0])
           54 #define MOUSEMASK               (BUTTONMASK|PointerMotionMask)
           55 #define WIDTH(X)                ((X)->w + 2 * (X)->bw)
           56 #define HEIGHT(X)               ((X)->h + 2 * (X)->bw)
           57 #define TAGMASK                 ((1 << LENGTH(tags)) - 1)
           58 #define TEXTW(X)                (drw_fontset_getwidth(drw, (X)) + lrpad)
           59 
           60 #define SYSTEM_TRAY_REQUEST_DOCK    0
           61 
           62 /* XEMBED messages */
           63 #define XEMBED_EMBEDDED_NOTIFY      0
           64 #define XEMBED_WINDOW_ACTIVATE      1
           65 #define XEMBED_FOCUS_IN             4
           66 #define XEMBED_MODALITY_ON         10
           67 
           68 #define XEMBED_MAPPED              (1 << 0)
           69 #define XEMBED_WINDOW_ACTIVATE      1
           70 #define XEMBED_WINDOW_DEACTIVATE    2
           71 
           72 #define VERSION_MAJOR               0
           73 #define VERSION_MINOR               0
           74 #define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
           75 
           76 /* enums */
           77 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
           78 enum { SchemeNorm, SchemeSel, SchemeWarn, SchemeCrit }; /* color schemes */
           79 enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
           80     NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation,
           81     NetSystemTrayOrientationHorz, NetWMFullscreen, NetActiveWindow,
           82     NetWMWindowType, NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
           83 enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
           84 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
           85 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
           86     ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
           87 
           88 typedef union {
           89     int i;
           90     unsigned int ui;
           91     float f;
           92     const void *v;
           93 } Arg;
           94 
           95 typedef struct {
           96     unsigned int click;
           97     unsigned int mask;
           98     unsigned int button;
           99     void (*func)(const Arg *arg);
          100     const Arg arg;
          101 } Button;
          102 
          103 typedef struct Monitor Monitor;
          104 typedef struct Client Client;
          105 struct Client {
          106     char name[256];
          107     float mina, maxa;
          108     int x, y, w, h;
          109     int oldx, oldy, oldw, oldh;
          110     int basew, baseh, incw, inch, maxw, maxh, minw, minh;
          111     int bw, oldbw;
          112     unsigned int tags;
          113     int ismax, wasfloating, isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
          114     Client *next;
          115     Client *snext;
          116     Monitor *mon;
          117     Window win;
          118 };
          119 
          120 typedef struct {
          121     unsigned int mod;
          122     KeySym keysym;
          123     void (*func)(const Arg *);
          124     const Arg arg;
          125 } Key;
          126 
          127 typedef struct {
          128     const char *symbol;
          129     void (*arrange)(Monitor *);
          130 } Layout;
          131 
          132 typedef struct Pertag Pertag;
          133 struct Monitor {
          134     char ltsymbol[16];
          135     float mfact;
          136     int nmaster;
          137     int num;
          138     int by;               /* bar geometry */
          139     int mx, my, mw, mh;   /* screen size */
          140     int wx, wy, ww, wh;   /* window area  */
          141     unsigned int seltags;
          142     unsigned int sellt;
          143     unsigned int tagset[2];
          144         int rmaster;
          145     int showbar;
          146     int topbar;
          147     Client *clients;
          148     Client *sel;
          149     Client *stack;
          150     Monitor *next;
          151     Window barwin;
          152     const Layout *lt[2];
          153     Pertag *pertag;
          154 };
          155 
          156 typedef struct {
          157     const char *class;
          158     const char *instance;
          159     const char *title;
          160     unsigned int tags;
          161     int isfloating;
          162     int monitor;
          163     int neverfocus;
          164 } Rule;
          165 
          166 typedef struct {
          167     int y;
          168     Bool show;
          169     Window win;
          170     char text[256];
          171 } Bar;
          172 
          173 typedef struct Systray   Systray;
          174 struct Systray {
          175     Window win;
          176     Client *icons;
          177 };
          178 
          179 /* function declarations */
          180 static void applyrules(Client *c);
          181 static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
          182 static void arrange(Monitor *m);
          183 static void arrangemon(Monitor *m);
          184 static void attach(Client *c);
          185 static void attachstack(Client *c);
          186 static void buttonpress(XEvent *e);
          187 static void checkotherwm(void);
          188 static void cleanup(void);
          189 static void cleanupmon(Monitor *mon);
          190 static void clientmessage(XEvent *e);
          191 static void configure(Client *c);
          192 static void configurenotify(XEvent *e);
          193 static void configurerequest(XEvent *e);
          194 static Monitor *createmon(void);
          195 static void deck(Monitor *m);
          196 static void destroynotify(XEvent *e);
          197 static void detach(Client *c);
          198 static void detachstack(Client *c);
          199 static Monitor *dirtomon(int dir);
          200 static void drawbar(Monitor *m);
          201 static void drawbars(void);
          202 static void enternotify(XEvent *e);
          203 static void expose(XEvent *e);
          204 static void focus(Client *c);
          205 static void focusin(XEvent *e);
          206 static void focusmon(const Arg *arg);
          207 static void focusstack(const Arg *arg);
          208 static Atom getatomprop(Client *c, Atom prop);
          209 static int getrootptr(int *x, int *y);
          210 static long getstate(Window w);
          211 static unsigned int getsystraywidth();
          212 static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
          213 static void grabbuttons(Client *c, int focused);
          214 static void grabkeys(void);
          215 static void incnmaster(const Arg *arg);
          216 static void keypress(XEvent *e);
          217 static void killclient(const Arg *arg);
          218 static void manage(Window w, XWindowAttributes *wa);
          219 static void mappingnotify(XEvent *e);
          220 static void maprequest(XEvent *e);
          221 static void motionnotify(XEvent *e);
          222 static void movemouse(const Arg *arg);
          223 static Client *nexttiled(Client *c);
          224 static void pop(Client *);
          225 static void propertynotify(XEvent *e);
          226 static void quit(const Arg *arg);
          227 static Monitor *recttomon(int x, int y, int w, int h);
          228 static void removesystrayicon(Client *i);
          229 static void resize(Client *c, int x, int y, int w, int h, int interact);
          230 static void resizebarwin(Monitor *m);
          231 static void resizeclient(Client *c, int x, int y, int w, int h);
          232 static void resizemouse(const Arg *arg);
          233 static void resizerequest(XEvent *e);
          234 static void restack(Monitor *m);
          235 static void run(void);
          236 static void scan(void);
          237 static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
          238 static void sendmon(Client *c, Monitor *m);
          239 static void setclientstate(Client *c, long state);
          240 static void setfocus(Client *c);
          241 static void setfullscreen(Client *c, int fullscreen);
          242 static void setlayout(const Arg *arg);
          243 static void setmfact(const Arg *arg);
          244 static void setup(void);
          245 static void seturgent(Client *c, int urg);
          246 static void showhide(Client *c);
          247 static void sigchld(int unused);
          248 static void spawn(const Arg *arg);
          249 static void spawn_norestore(const Arg *arg);
          250 static Monitor *systraytomon(Monitor *m);
          251 static void tag(const Arg *arg);
          252 static void tagmon(const Arg *arg);
          253 static void tile(Monitor *);
          254 static void togglebar(const Arg *arg);
          255 static void togglefloating(const Arg *arg);
          256 static void togglermaster(const Arg *arg);
          257 static void togglescratch(const Arg *arg);
          258 static void toggletag(const Arg *arg);
          259 static void toggleview(const Arg *arg);
          260 static void unfocus(Client *c, int setfocus);
          261 static void unmanage(Client *c, int destroyed);
          262 static void unmapnotify(XEvent *e);
          263 static void updatebarpos(Monitor *m);
          264 static void updatebars(void);
          265 static void updateclientlist(void);
          266 static int updategeom(void);
          267 static void updatenumlockmask(void);
          268 static void updatesizehints(Client *c);
          269 static void updatestatus(void);
          270 static void updatesystray(void);
          271 static void updatesystrayicongeom(Client *i, int w, int h);
          272 static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
          273 static void updatetitle(Client *c);
          274 static void updatewindowtype(Client *c);
          275 static void updatewmhints(Client *c);
          276 static void view(const Arg *arg);
          277 static void viewtoleft(const Arg *arg);
          278 static void viewtoright(const Arg *arg);
          279 static Client *wintoclient(Window w);
          280 static Monitor *wintomon(Window w);
          281 static Client *wintosystrayicon(Window w);
          282 static int xerror(Display *dpy, XErrorEvent *ee);
          283 static int xerrordummy(Display *dpy, XErrorEvent *ee);
          284 static int xerrorstart(Display *dpy, XErrorEvent *ee);
          285 static void zoom(const Arg *arg);
          286 
          287 /* variables */
          288 static Systray *systray = NULL;
          289 static const char broken[] = "broken";
          290 static char stext[256];
          291 static int screen;
          292 static int sw, sh;           /* X display screen geometry width, height */
          293 static int bh, blw = 0;      /* bar geometry */
          294 static int lrpad;            /* sum of left and right padding for text */
          295 static int (*xerrorxlib)(Display *, XErrorEvent *);
          296 static unsigned int numlockmask = 0;
          297 static void (*handler[LASTEvent]) (XEvent *) = {
          298     [ButtonPress] = buttonpress,
          299     [ClientMessage] = clientmessage,
          300     [ConfigureRequest] = configurerequest,
          301     [ConfigureNotify] = configurenotify,
          302     [DestroyNotify] = destroynotify,
          303     [EnterNotify] = enternotify,
          304     [Expose] = expose,
          305     [FocusIn] = focusin,
          306     [KeyPress] = keypress,
          307     [MappingNotify] = mappingnotify,
          308     [MapRequest] = maprequest,
          309     [MotionNotify] = motionnotify,
          310     [PropertyNotify] = propertynotify,
          311     [ResizeRequest] = resizerequest,
          312     [UnmapNotify] = unmapnotify
          313 };
          314 static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
          315 static int running = 1;
          316 static Cur *cursor[CurLast];
          317 static Clr **scheme;
          318 static Display *dpy;
          319 static Drw *drw;
          320 static Monitor *mons, *selmon;
          321 static Window root, wmcheckwin;
          322 static Bar eb;
          323 
          324 /* configuration, allows nested code to access above variables */
          325 #include "config.h"
          326 
          327 struct Pertag {
          328     unsigned int curtag, prevtag; /* current and previous tag */
          329     int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
          330     float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
          331     unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
          332     const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes  */
          333     Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
          334 };
          335 
          336 static unsigned int scratchtag = 1 << LENGTH(tags);
          337 
          338 /* compile-time check if all tags fit into an unsigned int bit array. */
          339 struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
          340 
          341 /* function implementations */
          342 void applyrules(Client *c)
          343 {
          344     const char *class, *instance;
          345     unsigned int i;
          346     const Rule *r;
          347     Monitor *m;
          348     XClassHint ch = { NULL, NULL };
          349 
          350     /* rule matching */
          351     c->isfloating = 0;
          352     c->neverfocus = 0;
          353     c->tags = 0;
          354     XGetClassHint(dpy, c->win, &ch);
          355     class    = ch.res_class ? ch.res_class : broken;
          356     instance = ch.res_name  ? ch.res_name  : broken;
          357 
          358     for (i = 0; i < LENGTH(rules); i++) {
          359         r = &rules[i];
          360         if ((!r->title || strstr(c->name, r->title))
          361                 && (!r->class || strstr(class, r->class))
          362                 && (!r->instance || strstr(instance, r->instance)))
          363         {
          364             c->isfloating = r->isfloating;
          365             c->neverfocus = r->neverfocus;
          366             c->tags |= r->tags;
          367             for (m = mons; m && m->num != r->monitor; m = m->next);
          368             if (m)
          369                 c->mon = m;
          370         }
          371     }
          372     if (ch.res_class)
          373         XFree(ch.res_class);
          374     if (ch.res_name)
          375         XFree(ch.res_name);
          376     c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
          377 }
          378 
          379 int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact)
          380 {
          381     int baseismin;
          382     Monitor *m = c->mon;
          383 
          384     /* set minimum possible */
          385     *w = MAX(1, *w);
          386     *h = MAX(1, *h);
          387     if (interact) {
          388         if (*x > sw)
          389             *x = sw - WIDTH(c);
          390         if (*y > sh)
          391             *y = sh - HEIGHT(c);
          392         if (*x + *w + 2 * c->bw < 0)
          393             *x = 0;
          394         if (*y + *h + 2 * c->bw < 0)
          395             *y = 0;
          396     } else {
          397         if (*x >= m->wx + m->ww)
          398             *x = m->wx + m->ww - WIDTH(c);
          399         if (*y >= m->wy + m->wh)
          400             *y = m->wy + m->wh - HEIGHT(c);
          401         if (*x + *w + 2 * c->bw <= m->wx)
          402             *x = m->wx;
          403         if (*y + *h + 2 * c->bw <= m->wy)
          404             *y = m->wy;
          405     }
          406     if (*h < bh)
          407         *h = bh;
          408     if (*w < bh)
          409         *w = bh;
          410     if (resizehints || !c->mon->lt[c->mon->sellt]->arrange) {
          411         /* see last two sentences in ICCCM 4.1.2.3 */
          412         baseismin = c->basew == c->minw && c->baseh == c->minh;
          413         if (!baseismin) { /* temporarily remove base dimensions */
          414             *w -= c->basew;
          415             *h -= c->baseh;
          416         }
          417         /* adjust for aspect limits */
          418         if (c->mina > 0 && c->maxa > 0) {
          419             if (c->maxa < (float)*w / *h)
          420                 *w = *h * c->maxa + 0.5;
          421             else if (c->mina < (float)*h / *w)
          422                 *h = *w * c->mina + 0.5;
          423         }
          424         if (baseismin) { /* increment calculation requires this */
          425             *w -= c->basew;
          426             *h -= c->baseh;
          427         }
          428         /* adjust for increment value */
          429         if (c->incw)
          430             *w -= *w % c->incw;
          431         if (c->inch)
          432             *h -= *h % c->inch;
          433         /* restore base dimensions */
          434         *w = MAX(*w + c->basew, c->minw);
          435         *h = MAX(*h + c->baseh, c->minh);
          436         if (c->maxw)
          437             *w = MIN(*w, c->maxw);
          438         if (c->maxh)
          439             *h = MIN(*h, c->maxh);
          440     }
          441     return *x != c->x || *y != c->y || *w != c->w || *h != c->h;
          442 }
          443 
          444 void arrange(Monitor *m)
          445 {
          446     if (m)
          447         showhide(m->stack);
          448     else for (m = mons; m; m = m->next)
          449         showhide(m->stack);
          450     if (m) {
          451         arrangemon(m);
          452         restack(m);
          453     } else for (m = mons; m; m = m->next)
          454         arrangemon(m);
          455 }
          456 
          457 void arrangemon(Monitor *m)
          458 {
          459     strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
          460     if (m->lt[m->sellt]->arrange)
          461         m->lt[m->sellt]->arrange(m);
          462 }
          463 
          464 void attach(Client *c)
          465 {
          466     c->next = c->mon->clients;
          467     c->mon->clients = c;
          468 }
          469 
          470 void attachstack(Client *c)
          471 {
          472     c->snext = c->mon->stack;
          473     c->mon->stack = c;
          474 }
          475 
          476 void buttonpress(XEvent *e)
          477 {
          478     unsigned int i, x, click;
          479     Arg arg = {0};
          480     Client *c;
          481     Monitor *m;
          482     XButtonPressedEvent *ev = &e->xbutton;
          483 
          484     click = ClkRootWin;
          485     /* focus monitor if necessary */
          486     if ((m = wintomon(ev->window)) && m != selmon) {
          487         unfocus(selmon->sel, 1);
          488         selmon = m;
          489         focus(NULL);
          490     }
          491     if (ev->window == selmon->barwin) {
          492         i = x = 0;
          493         do
          494             x += TEXTW(tags[i]);
          495         while (ev->x >= x && ++i < LENGTH(tags));
          496         if (i < LENGTH(tags)) {
          497             click = ClkTagBar;
          498             arg.ui = 1 << i;
          499         } else if (ev->x < x + blw)
          500             click = ClkLtSymbol;
          501         else if (ev->x > selmon->ww - TEXTW(stext) - getsystraywidth())
          502             click = ClkStatusText;
          503         else
          504             click = ClkWinTitle;
          505     } else if ((c = wintoclient(ev->window))) {
          506         focus(c);
          507         restack(selmon);
          508         XAllowEvents(dpy, ReplayPointer, CurrentTime);
          509         click = ClkClientWin;
          510     }
          511     for (i = 0; i < LENGTH(buttons); i++)
          512         if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
          513                 && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
          514             buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
          515 }
          516 
          517 void checkotherwm(void)
          518 {
          519     xerrorxlib = XSetErrorHandler(xerrorstart);
          520     /* this causes an error if some other window manager is running */
          521     XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
          522     XSync(dpy, False);
          523     XSetErrorHandler(xerror);
          524     XSync(dpy, False);
          525 }
          526 
          527 void cleanup(void)
          528 {
          529     Arg a = {.ui = ~0};
          530     Layout foo = { "", NULL };
          531     Monitor *m;
          532     size_t i;
          533 
          534     view(&a);
          535     selmon->lt[selmon->sellt] = &foo;
          536     for (m = mons; m; m = m->next)
          537         while (m->stack)
          538             unmanage(m->stack, 0);
          539     XUngrabKey(dpy, AnyKey, AnyModifier, root);
          540     XUnmapWindow(dpy, eb.win);
          541     XDestroyWindow(dpy, eb.win);
          542     while (mons)
          543         cleanupmon(mons);
          544     if (showsystray) {
          545         XUnmapWindow(dpy, systray->win);
          546         XDestroyWindow(dpy, systray->win);
          547         free(systray);
          548     }
          549     for (i = 0; i < CurLast; i++)
          550         drw_cur_free(drw, cursor[i]);
          551     for (i = 0; i < LENGTH(colors); i++)
          552         free(scheme[i]);
          553     XDestroyWindow(dpy, wmcheckwin);
          554     drw_free(drw);
          555     XSync(dpy, False);
          556     XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
          557     XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
          558 }
          559 
          560 void cleanupmon(Monitor *mon)
          561 {
          562     Monitor *m;
          563 
          564     if (mon == mons)
          565         mons = mons->next;
          566     else {
          567         for (m = mons; m && m->next != mon; m = m->next);
          568         m->next = mon->next;
          569     }
          570     XUnmapWindow(dpy, mon->barwin);
          571     XDestroyWindow(dpy, mon->barwin);
          572     free(mon);
          573 }
          574 
          575 void clientmessage(XEvent *e)
          576 {
          577     XWindowAttributes wa;
          578     XSetWindowAttributes swa;
          579     XClientMessageEvent *cme = &e->xclient;
          580     Client *c = wintoclient(cme->window);
          581 
          582     if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
          583         /* add systray icons */
          584         if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
          585             if (!(c = (Client *)calloc(1, sizeof(Client))))
          586                 die("fatal: could not malloc() %u bytes\n", sizeof(Client));
          587             if (!(c->win = cme->data.l[2])) {
          588                 free(c);
          589                 return;
          590             }
          591             c->mon = selmon;
          592             c->next = systray->icons;
          593             systray->icons = c;
          594             XGetWindowAttributes(dpy, c->win, &wa);
          595             c->x = c->oldx = c->y = c->oldy = 0;
          596             c->w = c->oldw = wa.width;
          597             c->h = c->oldh = wa.height;
          598             c->oldbw = wa.border_width;
          599             c->bw = 0;
          600             c->isfloating = True;
          601             /* reuse tags field as mapped status */
          602             c->tags = 1;
          603             updatesizehints(c);
          604             updatesystrayicongeom(c, wa.width, wa.height);
          605             XAddToSaveSet(dpy, c->win);
          606             XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
          607             XReparentWindow(dpy, c->win, systray->win, 0, 0);
          608             /* use parents background color */
          609             swa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
          610             XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
          611             sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
          612             /* FIXME not sure if I have to send these events, too */
          613             sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
          614             sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
          615             sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
          616             XSync(dpy, False);
          617             resizebarwin(selmon);
          618             updatesystray();
          619             setclientstate(c, NormalState);
          620         }
          621         return;
          622     }
          623     if (!c)
          624         return;
          625     if (cme->message_type == netatom[NetWMState]) {
          626         if (cme->data.l[1] == netatom[NetWMFullscreen]
          627                 || cme->data.l[2] == netatom[NetWMFullscreen])
          628             setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD    */
          629                         || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
          630     } else if (cme->message_type == netatom[NetActiveWindow]) {
          631         if (c != selmon->sel && !c->isurgent)
          632             seturgent(c, 1);
          633     }
          634 }
          635 
          636 void configure(Client *c)
          637 {
          638     XConfigureEvent ce;
          639 
          640     ce.type = ConfigureNotify;
          641     ce.display = dpy;
          642     ce.event = c->win;
          643     ce.window = c->win;
          644     ce.x = c->x;
          645     ce.y = c->y;
          646     ce.width = c->w;
          647     ce.height = c->h;
          648     ce.border_width = c->bw;
          649     ce.above = None;
          650     ce.override_redirect = False;
          651     XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
          652 }
          653 
          654 void configurenotify(XEvent *e)
          655 {
          656     Monitor *m;
          657     Client *c;
          658     XConfigureEvent *ev = &e->xconfigure;
          659     int dirty;
          660 
          661     /* TODO: updategeom handling sucks, needs to be simplified */
          662     if (ev->window == root) {
          663         dirty = (sw != ev->width || sh != ev->height);
          664         sw = ev->width;
          665         sh = ev->height;
          666         if (updategeom() || dirty) {
          667             drw_resize(drw, sw, bh);
          668             updatebars();
          669             for (m = mons; m; m = m->next) {
          670                 for (c = m->clients; c; c = c->next)
          671                     if (c->isfullscreen)
          672                         resizeclient(c, m->mx, m->my, m->mw, m->mh);
          673                 resizebarwin(m);
          674             }
          675             XMoveResizeWindow(dpy, eb.win, mons->wx, eb.y, mons->ww, bh);
          676             focus(NULL);
          677             arrange(NULL);
          678         }
          679     }
          680 }
          681 
          682 void configurerequest(XEvent *e)
          683 {
          684     Client *c;
          685     Monitor *m;
          686     XConfigureRequestEvent *ev = &e->xconfigurerequest;
          687     XWindowChanges wc;
          688 
          689     if ((c = wintoclient(ev->window))) {
          690         if (ev->value_mask & CWBorderWidth)
          691             c->bw = ev->border_width;
          692         else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
          693             m = c->mon;
          694             if (ev->value_mask & CWX) {
          695                 c->oldx = c->x;
          696                 c->x = m->mx + ev->x;
          697             }
          698             if (ev->value_mask & CWY) {
          699                 c->oldy = c->y;
          700                 c->y = m->my + ev->y;
          701             }
          702             if (ev->value_mask & CWWidth) {
          703                 c->oldw = c->w;
          704                 c->w = ev->width;
          705             }
          706             if (ev->value_mask & CWHeight) {
          707                 c->oldh = c->h;
          708                 c->h = ev->height;
          709             }
          710             if ((c->x + c->w) > m->mx + m->mw && c->isfloating)
          711                 c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */
          712             if ((c->y + c->h) > m->my + m->mh && c->isfloating)
          713                 c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */
          714             if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
          715                 configure(c);
          716             if (ISVISIBLE(c))
          717                 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
          718         } else
          719             configure(c);
          720     } else {
          721         wc.x = ev->x;
          722         wc.y = ev->y;
          723         wc.width = ev->width;
          724         wc.height = ev->height;
          725         wc.border_width = ev->border_width;
          726         wc.sibling = ev->above;
          727         wc.stack_mode = ev->detail;
          728         XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
          729     }
          730     XSync(dpy, False);
          731 }
          732 
          733 Monitor * createmon(void)
          734 {
          735     Monitor *m;
          736     int i;
          737 
          738     m = ecalloc(1, sizeof(Monitor));
          739     m->tagset[0] = m->tagset[1] = 1;
          740     m->mfact = mfact;
          741     m->nmaster = nmaster;
          742         m->rmaster = rmaster;
          743     m->showbar = showbar;
          744     m->topbar = topbar;
          745     m->lt[0] = &layouts[0];
          746     m->lt[1] = &layouts[1 % LENGTH(layouts)];
          747     strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
          748     if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
          749         die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
          750     m->pertag->curtag = m->pertag->prevtag = 1;
          751     for(i=0; i <= LENGTH(tags); i++) {
          752         /* init nmaster */
          753         m->pertag->nmasters[i] = m->nmaster;
          754 
          755         /* init mfacts */
          756         m->pertag->mfacts[i] = m->mfact;
          757 
          758         /* init layouts */
          759         m->pertag->ltidxs[i][0] = m->lt[0];
          760         m->pertag->ltidxs[i][1] = m->lt[1];
          761         m->pertag->sellts[i] = m->sellt;
          762 
          763         /* init showbar */
          764         m->pertag->showbars[i] = m->showbar;
          765     }
          766     return m;
          767 }
          768 
          769 void destroynotify(XEvent *e)
          770 {
          771     Client *c;
          772     XDestroyWindowEvent *ev = &e->xdestroywindow;
          773 
          774     if ((c = wintoclient(ev->window)))
          775         unmanage(c, 1);
          776     else if ((c = wintosystrayicon(ev->window))) {
          777         removesystrayicon(c);
          778         resizebarwin(selmon);
          779         updatesystray();
          780     }
          781 }
          782 
          783 void detach(Client *c)
          784 {
          785     Client **tc;
          786 
          787     for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
          788     *tc = c->next;
          789 }
          790 
          791 void detachstack(Client *c)
          792 {
          793     Client **tc, *t;
          794 
          795     for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
          796     *tc = c->snext;
          797 
          798     if (c == c->mon->sel) {
          799         for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
          800         c->mon->sel = t;
          801     }
          802 }
          803 
          804 Monitor * dirtomon(int dir)
          805 {
          806     Monitor *m = NULL;
          807 
          808     if (dir > 0) {
          809         if (!(m = selmon->next))
          810             m = mons;
          811     } else if (selmon == mons)
          812         for (m = mons; m->next; m = m->next);
          813     else
          814         for (m = mons; m->next != selmon; m = m->next);
          815     return m;
          816 }
          817 
          818 void drawbar(Monitor *m)
          819 {
          820     int x, w, sw = 0, stw = 0;
          821     int boxs = drw->fonts->h / 9;
          822     int boxw = drw->fonts->h / 6 + 2;
          823     unsigned int i, occ = 0, urg = 0;
          824     Client *c;
          825 
          826     if(showsystray && m == systraytomon(m))
          827         stw = getsystraywidth();
          828 
          829     /* draw status first so it can be overdrawn by tags later */
          830     if (m == selmon) { /* status is only drawn on selected monitor */
          831         drw_setscheme(drw, scheme[SchemeNorm]);
          832         sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */
          833         drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0);
          834     }
          835 
          836     resizebarwin(m);
          837     for (c = m->clients; c; c = c->next) {
          838         occ |= c->tags;
          839         if (c-