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-