dwm.c (149408B)
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 "patches.h" 45 #include "drw.h" 46 #include "util.h" 47 48 #if BAR_FLEXWINTITLE_PATCH 49 #ifndef FLEXTILE_DELUXE_LAYOUT 50 #define FLEXTILE_DELUXE_LAYOUT 1 51 #endif 52 #endif 53 54 #if BAR_PANGO_PATCH 55 #include <pango/pango.h> 56 #endif // BAR_PANGO_PATCH 57 58 #if RESTARTSIG_PATCH 59 #include <poll.h> 60 #endif // RESTARTSIG_PATCH 61 62 #if XKB_PATCH 63 #include <X11/XKBlib.h> 64 #endif // XKB_PATCH 65 66 #if SPAWNCMD_PATCH 67 #include <assert.h> 68 #include <libgen.h> 69 #include <sys/stat.h> 70 #define SPAWN_CWD_DELIM " []{}()<>\"':" 71 #endif // SPAWNCMD_PATCH 72 73 /* macros */ 74 #define Button6 6 75 #define Button7 7 76 #define Button8 8 77 #define Button9 9 78 #define NUMTAGS 9 79 #define NUMVIEWHIST NUMTAGS 80 #define BARRULES 20 81 #if TAB_PATCH 82 #define MAXTABS 50 83 #endif // TAB_PATCH 84 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) 85 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) 86 #if BAR_ANYBAR_PATCH 87 #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->mx+(m)->mw) - MAX((x),(m)->mx)) \ 88 * MAX(0, MIN((y)+(h),(m)->my+(m)->mh) - MAX((y),(m)->my))) 89 #else 90 #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ 91 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) 92 #endif // BAR_ANYBAR_PATCH 93 #if ATTACHASIDE_PATCH && STICKY_PATCH 94 #define ISVISIBLEONTAG(C, T) ((C->tags & T) || C->issticky) 95 #define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags]) 96 #elif ATTACHASIDE_PATCH 97 #define ISVISIBLEONTAG(C, T) ((C->tags & T)) 98 #define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags]) 99 #elif STICKY_PATCH 100 #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]) || C->issticky) 101 #else 102 #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) 103 #endif // ATTACHASIDE_PATCH 104 #define MOUSEMASK (BUTTONMASK|PointerMotionMask) 105 #define WIDTH(X) ((X)->w + 2 * (X)->bw) 106 #define HEIGHT(X) ((X)->h + 2 * (X)->bw) 107 #define WTYPE "_NET_WM_WINDOW_TYPE_" 108 #if SCRATCHPADS_PATCH && !RENAMED_SCRATCHPADS_PATCH 109 #define TOTALTAGS (NUMTAGS + LENGTH(scratchpads)) 110 #define TAGMASK ((1 << TOTALTAGS) - 1) 111 #define SPTAG(i) ((1 << NUMTAGS) << (i)) 112 #define SPTAGMASK (((1 << LENGTH(scratchpads))-1) << NUMTAGS) 113 #else 114 #define TAGMASK ((1 << NUMTAGS) - 1) 115 #endif // SCRATCHPADS_PATCH 116 #define TEXTWM(X) (drw_fontset_getwidth(drw, (X), True) + lrpad) 117 #define TEXTW(X) (drw_fontset_getwidth(drw, (X), False) + lrpad) 118 #define HIDDEN(C) ((getstate(C->win) == IconicState)) 119 120 /* enums */ 121 enum { 122 #if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH 123 CurResizeBR, 124 CurResizeBL, 125 CurResizeTR, 126 CurResizeTL, 127 #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH 128 #if DRAGMFACT_PATCH 129 CurResizeHorzArrow, 130 CurResizeVertArrow, 131 #endif // DRAGMFACT_PATCH 132 #if DRAGCFACT_PATCH 133 CurIronCross, 134 #endif // DRAGCFACT_PATCH 135 CurNormal, 136 CurResize, 137 CurMove, 138 CurLast 139 }; /* cursor */ 140 141 enum { 142 SchemeNorm, 143 SchemeSel, 144 SchemeTitleNorm, 145 SchemeTitleSel, 146 SchemeTagsNorm, 147 SchemeTagsSel, 148 SchemeHidNorm, 149 SchemeHidSel, 150 SchemeUrg, 151 #if BAR_LTSYMBOL_SCHEME_PATCH 152 SchemeLtSymbol, 153 #endif // BAR_LTSYMBOL_SCHEME_PATCH 154 #if RENAMED_SCRATCHPADS_PATCH 155 SchemeScratchSel, 156 SchemeScratchNorm, 157 #endif // RENAMED_SCRATCHPADS_PATCH 158 #if BAR_FLEXWINTITLE_PATCH 159 SchemeFlexActTTB, 160 SchemeFlexActLTR, 161 SchemeFlexActMONO, 162 SchemeFlexActGRID, 163 SchemeFlexActGRD1, 164 SchemeFlexActGRD2, 165 SchemeFlexActGRDM, 166 SchemeFlexActHGRD, 167 SchemeFlexActDWDL, 168 SchemeFlexActSPRL, 169 SchemeFlexInaTTB, 170 SchemeFlexInaLTR, 171 SchemeFlexInaMONO, 172 SchemeFlexInaGRID, 173 SchemeFlexInaGRD1, 174 SchemeFlexInaGRD2, 175 SchemeFlexInaGRDM, 176 SchemeFlexInaHGRD, 177 SchemeFlexInaDWDL, 178 SchemeFlexInaSPRL, 179 SchemeFlexSelTTB, 180 SchemeFlexSelLTR, 181 SchemeFlexSelMONO, 182 SchemeFlexSelGRID, 183 SchemeFlexSelGRD1, 184 SchemeFlexSelGRD2, 185 SchemeFlexSelGRDM, 186 SchemeFlexSelHGRD, 187 SchemeFlexSelDWDL, 188 SchemeFlexSelSPRL, 189 SchemeFlexActFloat, 190 SchemeFlexInaFloat, 191 SchemeFlexSelFloat, 192 #endif // BAR_FLEXWINTITLE_PATCH 193 }; /* color schemes */ 194 195 enum { 196 NetSupported, NetWMName, NetWMState, NetWMCheck, 197 NetWMFullscreen, NetActiveWindow, NetWMWindowType, 198 #if BAR_WINICON_PATCH 199 NetWMIcon, 200 #endif // BAR_WINICON_PATCH 201 #if BAR_SYSTRAY_PATCH 202 NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, 203 NetSystemTrayVisual, NetWMWindowTypeDock, NetSystemTrayOrientationHorz, 204 #endif // BAR_SYSTRAY_PATCH 205 #if BAR_EWMHTAGS_PATCH 206 NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop, 207 #endif // BAR_EWMHTAGS_PATCH 208 NetClientList, 209 #if NET_CLIENT_LIST_STACKING_PATCH 210 NetClientListStacking, 211 #endif // NET_CLIENT_LIST_STACKING_PATCH 212 NetLast 213 }; /* EWMH atoms */ 214 215 enum { 216 WMProtocols, 217 WMDelete, 218 WMState, 219 WMTakeFocus, 220 #if WINDOWROLERULE_PATCH 221 WMWindowRole, 222 #endif // WINDOWROLERULE_PATCH 223 WMLast 224 }; /* default atoms */ 225 226 #if SEAMLESS_RESTART_PATCH 227 enum { 228 ClientFields, 229 ClientTags, 230 ClientLast 231 }; /* dwm client atoms */ 232 #endif // SEAMLESS_RESTART_PATCH 233 234 enum { 235 #if BAR_STATUSBUTTON_PATCH 236 ClkButton, 237 #endif // BAR_STATUSBUTTON_PATCH 238 #if TAB_PATCH 239 ClkTabBar, 240 #endif // TAB_PATCH 241 ClkTagBar, 242 ClkLtSymbol, 243 ClkStatusText, 244 ClkWinTitle, 245 ClkClientWin, 246 ClkRootWin, 247 #if XKB_PATCH 248 ClkXKB, 249 #endif // XKB_PATCH 250 ClkLast 251 }; /* clicks */ 252 253 enum { 254 BAR_ALIGN_LEFT, 255 BAR_ALIGN_CENTER, 256 BAR_ALIGN_RIGHT, 257 BAR_ALIGN_LEFT_LEFT, 258 BAR_ALIGN_LEFT_RIGHT, 259 BAR_ALIGN_LEFT_CENTER, 260 BAR_ALIGN_NONE, 261 BAR_ALIGN_RIGHT_LEFT, 262 BAR_ALIGN_RIGHT_RIGHT, 263 BAR_ALIGN_RIGHT_CENTER, 264 BAR_ALIGN_LAST 265 }; /* bar alignment */ 266 267 #if IPC_PATCH 268 typedef struct TagState TagState; 269 struct TagState { 270 int selected; 271 int occupied; 272 int urgent; 273 }; 274 275 typedef struct ClientState ClientState; 276 struct ClientState { 277 int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; 278 }; 279 #endif // IPC_PATCH 280 281 typedef union { 282 #if IPC_PATCH 283 long i; 284 unsigned long ui; 285 #else 286 int i; 287 unsigned int ui; 288 #endif // IPC_PATCH 289 float f; 290 const void *v; 291 } Arg; 292 293 typedef struct Monitor Monitor; 294 typedef struct Bar Bar; 295 struct Bar { 296 Window win; 297 Monitor *mon; 298 Bar *next; 299 int idx; 300 int showbar; 301 int topbar; 302 int external; 303 int borderpx; 304 int borderscheme; 305 int bx, by, bw, bh; /* bar geometry */ 306 int w[BARRULES]; // width, array length == barrules, then use r index for lookup purposes 307 int x[BARRULES]; // x position, array length == ^ 308 }; 309 310 typedef struct { 311 int x; 312 int y; 313 int h; 314 int w; 315 } BarArg; 316 317 typedef struct { 318 int monitor; 319 int bar; 320 int alignment; // see bar alignment enum 321 int (*widthfunc)(Bar *bar, BarArg *a); 322 int (*drawfunc)(Bar *bar, BarArg *a); 323 int (*clickfunc)(Bar *bar, Arg *arg, BarArg *a); 324 int (*hoverfunc)(Bar *bar, BarArg *a, XMotionEvent *ev); 325 char *name; // for debugging 326 int x, w; // position, width for internal use 327 } BarRule; 328 329 typedef struct { 330 unsigned int click; 331 unsigned int mask; 332 unsigned int button; 333 void (*func)(const Arg *arg); 334 const Arg arg; 335 } Button; 336 337 #if XKB_PATCH 338 typedef struct XkbInfo XkbInfo; 339 struct XkbInfo { 340 XkbInfo *next; 341 XkbInfo *prev; 342 int group; 343 Window w; 344 }; 345 #endif // XKB_PATCH 346 347 typedef struct Client Client; 348 struct Client { 349 char name[256]; 350 float mina, maxa; 351 #if CFACTS_PATCH 352 float cfact; 353 #endif // CFACTS_PATCH 354 int x, y, w, h; 355 #if SAVEFLOATS_PATCH || EXRESIZE_PATCH 356 int sfx, sfy, sfw, sfh; /* stored float geometry, used on mode revert */ 357 #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH 358 #if SEAMLESS_RESTART_PATCH 359 unsigned int idx; 360 #endif // SEAMLESS_RESTART_PATCH 361 int oldx, oldy, oldw, oldh; 362 int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid; 363 int bw, oldbw; 364 unsigned int tags; 365 #if SWITCHTAG_PATCH 366 unsigned int switchtag; 367 #endif // SWITCHTAG_PATCH 368 int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; 369 #if ALWAYSONTOP_PATCH 370 int alwaysontop; 371 #endif // ALWAYSONTOP_PATCH 372 #if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH 373 int fakefullscreen; 374 #endif // FAKEFULLSCREEN_CLIENT_PATCH 375 #if GAMES_PATCH 376 int isgame; 377 #endif // GAMES_PATCH 378 #if EXRESIZE_PATCH 379 unsigned char expandmask; 380 int expandx1, expandy1, expandx2, expandy2; 381 #if !MAXIMIZE_PATCH 382 int wasfloating; 383 #endif // MAXIMIZE_PATCH 384 #endif // EXRESIZE_PATCH 385 #if MAXIMIZE_PATCH 386 int ismax, wasfloating; 387 #endif // MAXIMIZE_PATCH 388 #if AUTORESIZE_PATCH 389 int needresize; 390 #endif // AUTORESIZE_PATCH 391 #if CENTER_PATCH 392 int iscentered; 393 #endif // CENTER_PATCH 394 #if ISPERMANENT_PATCH 395 int ispermanent; 396 #endif // ISPERMANENT_PATCH 397 #if PLACEMOUSE_PATCH 398 int beingmoved; 399 #endif // PLACEMOUSE_PATCH 400 #if SIZEHINTS_ISFREESIZE_PATCH 401 int isfreesize; 402 #endif // SIZEHINTS_ISFREESIZE_PATCH 403 #if SWALLOW_PATCH 404 int isterminal, noswallow; 405 pid_t pid; 406 #endif // SWALLOW_PATCH 407 #if STEAM_PATCH 408 int issteam; 409 #endif // STEAM_PATCH 410 #if STICKY_PATCH 411 int issticky; 412 #endif // STICKY_PATCH 413 Client *next; 414 Client *snext; 415 #if SWALLOW_PATCH 416 Client *swallowing; 417 #endif // SWALLOW_PATCH 418 Monitor *mon; 419 Window win; 420 #if IPC_PATCH 421 ClientState prevstate; 422 #endif // IPC_PATCH 423 #if RENAMED_SCRATCHPADS_PATCH 424 char scratchkey; 425 #endif // RENAMED_SCRATCHPADS_PATCH 426 #if XKB_PATCH 427 XkbInfo *xkb; 428 #endif // XKB_PATCH 429 #if BAR_WINICON_PATCH 430 unsigned int icw, ich; 431 Picture icon; 432 #endif // BAR_WINICON_PATCH 433 }; 434 435 typedef struct { 436 unsigned int mod; 437 KeySym keysym; 438 void (*func)(const Arg *); 439 const Arg arg; 440 } Key; 441 442 #if FLEXTILE_DELUXE_LAYOUT 443 typedef struct { 444 int nmaster; 445 int nstack; 446 int layout; 447 int masteraxis; // master stack area 448 int stack1axis; // primary stack area 449 int stack2axis; // secondary stack area, e.g. centered master 450 void (*symbolfunc)(Monitor *, unsigned int); 451 } LayoutPreset; 452 #endif // FLEXTILE_DELUXE_LAYOUT 453 454 typedef struct { 455 const char *symbol; 456 void (*arrange)(Monitor *); 457 #if FLEXTILE_DELUXE_LAYOUT 458 LayoutPreset preset; 459 #endif // FLEXTILE_DELUXE_LAYOUT 460 } Layout; 461 462 #if INSETS_PATCH 463 typedef struct { 464 int x; 465 int y; 466 int w; 467 int h; 468 } Inset; 469 #endif // INSETS_PATCH 470 471 #if PERTAG_PATCH 472 typedef struct Pertag Pertag; 473 #endif // PERTAG_PATCH 474 struct Monitor { 475 char ltsymbol[16]; 476 float mfact; 477 #if FLEXTILE_DELUXE_LAYOUT 478 int ltaxis[4]; 479 int nstack; 480 #endif // FLEXTILE_DELUXE_LAYOUT 481 int nmaster; 482 int num; 483 int mx, my, mw, mh; /* screen size */ 484 int wx, wy, ww, wh; /* window area */ 485 #if TAB_PATCH 486 int ty; /* tab bar geometry */ 487 #endif // TAB_PATCH 488 #if VANITYGAPS_PATCH 489 int gappih; /* horizontal gap between windows */ 490 int gappiv; /* vertical gap between windows */ 491 int gappoh; /* horizontal outer gaps */ 492 int gappov; /* vertical outer gaps */ 493 #if PERMON_VANITYGAPS_PATCH 494 int enablegaps; /* whether gaps are enabled */ 495 #endif // PERMON_VANITYGAPS_PATCH 496 #endif // VANITYGAPS_PATCH 497 #if SETBORDERPX_PATCH 498 int borderpx; 499 #endif // SETBORDERPX_PATCH 500 unsigned int seltags; 501 unsigned int sellt; 502 #if VIEW_HISTORY_PATCH 503 unsigned int tagset[NUMVIEWHIST]; 504 #else 505 unsigned int tagset[2]; 506 #endif // VIEW_HISTORY_PATCH 507 int showbar; 508 #if TAB_PATCH 509 int showtab; 510 int toptab; 511 Window tabwin; 512 int ntabs; 513 int tab_widths[MAXTABS]; 514 #endif // TAB_PATCH 515 Client *clients; 516 Client *sel; 517 Client *stack; 518 #if FOCUSMASTER_RETURN_PATCH 519 Client *tagmarked[32]; 520 #endif // FOCUSMASTER_RETURN_PATCH 521 Monitor *next; 522 Bar *bar; 523 const Layout *lt[2]; 524 #if BAR_ALTERNATIVE_TAGS_PATCH 525 unsigned int alttag; 526 #endif // BAR_ALTERNATIVE_TAGS_PATCH 527 #if PERTAG_PATCH 528 Pertag *pertag; 529 #endif // PERTAG_PATCH 530 #if INSETS_PATCH 531 Inset inset; 532 #endif // INSETS_PATCH 533 #if BAR_TAGLABELS_PATCH 534 char taglabel[NUMTAGS][64]; 535 #endif // BAR_TAGLABELS_PATCH 536 #if IPC_PATCH 537 char lastltsymbol[16]; 538 TagState tagstate; 539 Client *lastsel; 540 const Layout *lastlt; 541 #endif // IPC_PATCH 542 #if BAR_TAGPREVIEW_PATCH 543 Window tagwin; 544 int previewshow; 545 Pixmap tagmap[NUMTAGS]; 546 #endif // BAR_TAGPREVIEW_PATCH 547 }; 548 549 typedef struct { 550 const char *class; 551 #if WINDOWROLERULE_PATCH 552 const char *role; 553 #endif // WINDOWROLERULE_PATCH 554 const char *instance; 555 const char *title; 556 const char *wintype; 557 unsigned int tags; 558 #if SWITCHTAG_PATCH 559 int switchtag; 560 #endif // SWITCHTAG_PATCH 561 #if CENTER_PATCH 562 int iscentered; 563 #endif // CENTER_PATCH 564 int isfloating; 565 #if SELECTIVEFAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH 566 int isfakefullscreen; 567 #endif // SELECTIVEFAKEFULLSCREEN_PATCH 568 #if SIZEHINTS_ISFREESIZE_PATCH 569 int isfreesize; 570 #endif // SIZEHINTS_ISFREESIZE_PATCH 571 #if ISPERMANENT_PATCH 572 int ispermanent; 573 #endif // ISPERMANENT_PATCH 574 #if SWALLOW_PATCH 575 int isterminal; 576 int noswallow; 577 #endif // SWALLOW_PATCH 578 #if FLOATPOS_PATCH 579 const char *floatpos; 580 #endif // FLOATPOS_PATCH 581 int monitor; 582 #if RENAMED_SCRATCHPADS_PATCH 583 const char scratchkey; 584 #endif // RENAMED_SCRATCHPADS_PATCH 585 #if UNMANAGED_PATCH 586 int unmanaged; 587 #endif // UNMANAGED_PATCH 588 #if XKB_PATCH 589 int xkb_layout; 590 #endif // XKB_PATCH 591 #if BORDER_RULE_PATCH 592 int bw; 593 #endif // BORDER_RULE_PATCH 594 #if GAMES_PATCH 595 int isgame; 596 #endif // GAMES_PATCH 597 } Rule; 598 599 #if BORDER_RULE_PATCH && XKB_PATCH 600 #define RULE(...) { .monitor = -1, .xkb_layout = -1, .bw = -1, __VA_ARGS__ }, 601 #elif XKB_PATCH 602 #define RULE(...) { .monitor = -1, .xkb_layout = -1, __VA_ARGS__ }, 603 #elif BORDER_RULE_PATCH 604 #define RULE(...) { .monitor = -1, .bw = -1, __VA_ARGS__ }, 605 #else 606 #define RULE(...) { .monitor = -1, __VA_ARGS__ }, 607 #endif // XKB_PATCH 608 609 /* Cross patch compatibility rule macro helper macros */ 610 #define FLOATING , .isfloating = 1 611 #if CENTER_PATCH 612 #define CENTERED , .iscentered = 1 613 #else 614 #define CENTERED 615 #endif // CENTER_PATCH 616 #if ISPERMANENT_PATCH 617 #define PERMANENT , .ispermanent = 1 618 #else 619 #define PERMANENT 620 #endif // ISPERMANENT_PATCH 621 #if SELECTIVEFAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH 622 #define FAKEFULLSCREEN , .isfakefullscreen = 1 623 #else 624 #define FAKEFULLSCREEN 625 #endif // SELECTIVEFAKEFULLSCREEN_PATCH 626 #if SWALLOW_PATCH 627 #define NOSWALLOW , .noswallow = 1 628 #define TERMINAL , .isterminal = 1 629 #else 630 #define NOSWALLOW 631 #define TERMINAL 632 #endif // SWALLOW_PATCH 633 #if SWITCHTAG_PATCH 634 #define SWITCHTAG , .switchtag = 1 635 #else 636 #define SWITCHTAG 637 #endif // SWITCHTAG_PATCH 638 639 #if MONITOR_RULES_PATCH 640 typedef struct { 641 int monitor; 642 #if PERTAG_PATCH 643 int tag; 644 #endif // PERTAG_PATCH 645 int layout; 646 float mfact; 647 int nmaster; 648 int showbar; 649 int topbar; 650 } MonitorRule; 651 #endif // MONITOR_RULES_PATCH 652 653 /* function declarations */ 654 static void applyrules(Client *c); 655 static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); 656 static void arrange(Monitor *m); 657 static void arrangemon(Monitor *m); 658 static void attach(Client *c); 659 static void attachstack(Client *c); 660 static void buttonpress(XEvent *e); 661 static void checkotherwm(void); 662 static void cleanup(void); 663 static void cleanupmon(Monitor *mon); 664 static void clientmessage(XEvent *e); 665 static void configure(Client *c); 666 static void configurenotify(XEvent *e); 667 static void configurerequest(XEvent *e); 668 static Monitor *createmon(void); 669 static void destroynotify(XEvent *e); 670 static void detach(Client *c); 671 static void detachstack(Client *c); 672 static Monitor *dirtomon(int dir); 673 static void drawbar(Monitor *m); 674 static void drawbars(void); 675 static void drawbarwin(Bar *bar); 676 #if !FOCUSONCLICK_PATCH 677 static void enternotify(XEvent *e); 678 #endif // FOCUSONCLICK_PATCH 679 static void expose(XEvent *e); 680 static void focus(Client *c); 681 static void focusin(XEvent *e); 682 static void focusmon(const Arg *arg); 683 #if !STACKER_PATCH 684 static void focusstack(const Arg *arg); 685 #endif // STACKER_PATCH 686 static Atom getatomprop(Client *c, Atom prop, Atom req); 687 static int getrootptr(int *x, int *y); 688 static long getstate(Window w); 689 static int gettextprop(Window w, Atom atom, char *text, unsigned int size); 690 static void grabbuttons(Client *c, int focused); 691 #if KEYMODES_PATCH 692 static void grabdefkeys(void); 693 #else 694 static void grabkeys(void); 695 #endif // KEYMODES_PATCH 696 static void incnmaster(const Arg *arg); 697 #if KEYMODES_PATCH 698 static void keydefpress(XEvent *e); 699 #else 700 static void keypress(XEvent *e); 701 #endif // KEYMODES_PATCH 702 static void killclient(const Arg *arg); 703 static void manage(Window w, XWindowAttributes *wa); 704 static void mappingnotify(XEvent *e); 705 static void maprequest(XEvent *e); 706 static void motionnotify(XEvent *e); 707 static void movemouse(const Arg *arg); 708 static Client *nexttiled(Client *c); 709 #if NOBORDER_PATCH 710 static int noborder(Client *c); 711 #endif // NOBORDER_PATCH 712 #if !ZOOMSWAP_PATCH || TAGINTOSTACK_ALLMASTER_PATCH || TAGINTOSTACK_ONEMASTER_PATCH 713 static void pop(Client *c); 714 #endif // !ZOOMSWAP_PATCH / TAGINTOSTACK_ALLMASTER_PATCH / TAGINTOSTACK_ONEMASTER_PATCH 715 static void propertynotify(XEvent *e); 716 static void quit(const Arg *arg); 717 static Monitor *recttomon(int x, int y, int w, int h); 718 static void resize(Client *c, int x, int y, int w, int h, int interact); 719 static void resizeclient(Client *c, int x, int y, int w, int h); 720 static void resizemouse(const Arg *arg); 721 static void restack(Monitor *m); 722 static void run(void); 723 static void scan(void); 724 #if BAR_SYSTRAY_PATCH 725 static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); 726 #else 727 static int sendevent(Client *c, Atom proto); 728 #endif // BAR_SYSTRAY_PATCH 729 static void sendmon(Client *c, Monitor *m); 730 static void setclientstate(Client *c, long state); 731 static void setfocus(Client *c); 732 static void setfullscreen(Client *c, int fullscreen); 733 static void setlayout(const Arg *arg); 734 static void setmfact(const Arg *arg); 735 static void setup(void); 736 static void seturgent(Client *c, int urg); 737 #if COOL_AUTOSTART_PATCH 738 static void sigchld(int unused); 739 #endif // COOL_AUTOSTART_PATCH 740 static void showhide(Client *c); 741 static void spawn(const Arg *arg); 742 #if RIODRAW_PATCH 743 static pid_t spawncmd(const Arg *arg); 744 #endif // RIODRAW_PATCH 745 static void tag(const Arg *arg); 746 static void tagmon(const Arg *arg); 747 static void togglebar(const Arg *arg); 748 static void togglefloating(const Arg *arg); 749 static void toggletag(const Arg *arg); 750 static void toggleview(const Arg *arg); 751 static void unfocus(Client *c, int setfocus, Client *nextfocus); 752 static void unmanage(Client *c, int destroyed); 753 static void unmapnotify(XEvent *e); 754 static void updatebarpos(Monitor *m); 755 static void updatebars(void); 756 static void updateclientlist(void); 757 static int updategeom(void); 758 static void updatenumlockmask(void); 759 static void updatesizehints(Client *c); 760 static void updatestatus(void); 761 static void updatetitle(Client *c); 762 static void updatewmhints(Client *c); 763 static void view(const Arg *arg); 764 static Client *wintoclient(Window w); 765 static Monitor *wintomon(Window w); 766 static int xerror(Display *dpy, XErrorEvent *ee); 767 static int xerrordummy(Display *dpy, XErrorEvent *ee); 768 static int xerrorstart(Display *dpy, XErrorEvent *ee); 769 static void zoom(const Arg *arg); 770 771 /* bar functions */ 772 773 #include "patch/include.h" 774 775 /* variables */ 776 static const char broken[] = "broken"; 777 #if BAR_PANGO_PATCH || BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH 778 static char stext[1024]; 779 #else 780 static char stext[512]; 781 #endif // BAR_PANGO_PATCH | BAR_STATUS2D_PATCH 782 #if BAR_EXTRASTATUS_PATCH || BAR_STATUSCMD_PATCH 783 #if BAR_STATUS2D_PATCH 784 static char rawstext[1024]; 785 #else 786 static char rawstext[512]; 787 #endif // BAR_STATUS2D_PATCH 788 #endif // BAR_EXTRASTATUS_PATCH | BAR_STATUSCMD_PATCH 789 #if BAR_EXTRASTATUS_PATCH 790 #if BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH 791 static char estext[1024]; 792 #else 793 static char estext[512]; 794 #endif // BAR_STATUS2D_PATCH 795 #if BAR_STATUSCMD_PATCH 796 static char rawestext[1024]; 797 #endif // BAR_STATUS2D_PATCH | BAR_STATUSCMD_PATCH 798 #endif // BAR_EXTRASTATUS_PATCH 799 800 #if XKB_PATCH 801 static int xkbEventType = 0; 802 #endif // XKB_PATCH 803 static int screen; 804 static int sw, sh; /* X display screen geometry width, height */ 805 static int bh; /* bar geometry */ 806 #if UNMANAGED_PATCH 807 static int unmanaged = 0; /* whether the window manager should manage the new window or not */ 808 #endif // UNMANAGED_PATCH 809 static int lrpad; /* sum of left and right padding for text */ 810 /* Some clients (e.g. alacritty) helpfully send configure requests with a new size or position 811 * when they detect that they have been moved to another monitor. This can cause visual glitches 812 * when moving (or resizing) client windows from one monitor to another. This variable is used 813 * internally to ignore such configure requests while movemouse or resizemouse are being used. */ 814 static int ignoreconfigurerequests = 0; 815 #if WARP_PATCH 816 static int force_warp = 0; // force warp in some situations, e.g. killclient 817 static int ignore_warp = 0; // force skip warp in some situations, e.g. dragmfact, dragcfact 818 #endif // WARP_PATCH 819 static int (*xerrorxlib)(Display *, XErrorEvent *); 820 static unsigned int numlockmask = 0; 821 #if RIODRAW_PATCH 822 static int riodimensions[4] = { -1, -1, -1, -1 }; 823 static pid_t riopid = 0; 824 #endif // RIODRAW_PATCH 825 static void (*handler[LASTEvent]) (XEvent *) = { 826 [ButtonPress] = buttonpress, 827 #if COMBO_PATCH || BAR_HOLDBAR_PATCH 828 [ButtonRelease] = keyrelease, 829 #endif // COMBO_PATCH / BAR_HOLDBAR_PATCH 830 [ClientMessage] = clientmessage, 831 [ConfigureRequest] = configurerequest, 832 [ConfigureNotify] = configurenotify, 833 [DestroyNotify] = destroynotify, 834 #if !FOCUSONCLICK_PATCH 835 [EnterNotify] = enternotify, 836 #endif // FOCUSONCLICK_PATCH 837 [Expose] = expose, 838 #if BANISH_PATCH 839 [GenericEvent] = genericevent, 840 #endif // BANISH_PATCH 841 [FocusIn] = focusin, 842 [KeyPress] = keypress, 843 #if COMBO_PATCH || BAR_HOLDBAR_PATCH 844 [KeyRelease] = keyrelease, 845 #endif // COMBO_PATCH / BAR_HOLDBAR_PATCH 846 [MappingNotify] = mappingnotify, 847 [MapRequest] = maprequest, 848 [MotionNotify] = motionnotify, 849 [PropertyNotify] = propertynotify, 850 #if BAR_SYSTRAY_PATCH 851 [ResizeRequest] = resizerequest, 852 #endif // BAR_SYSTRAY_PATCH 853 [UnmapNotify] = unmapnotify 854 }; 855 static Atom wmatom[WMLast], netatom[NetLast]; 856 #if BAR_SYSTRAY_PATCH 857 static Atom xatom[XLast]; 858 #endif // BAR_SYSTRAY_PATCH 859 #if SEAMLESS_RESTART_PATCH 860 static Atom clientatom[ClientLast]; 861 #endif // SEAMLESS_RESTART_PATCH 862 #if ON_EMPTY_KEYS_PATCH 863 static int isempty = 0; 864 #endif // ON_EMPTY_KEYS_PATCH 865 #if RESTARTSIG_PATCH 866 static volatile sig_atomic_t running = 1; 867 #else 868 static int running = 1; 869 #endif // RESTARTSIG_PATCH 870 static Cur *cursor[CurLast]; 871 static Clr **scheme; 872 static Display *dpy; 873 static Drw *drw; 874 static Monitor *mons, *selmon; 875 static Window root, wmcheckwin; 876 877 /* configuration, allows nested code to access above variables */ 878 #include "config.h" 879 880 #include "patch/include.c" 881 882 /* compile-time check if all tags fit into an unsigned int bit array. */ 883 #if SCRATCHPAD_ALT_1_PATCH 884 struct NumTags { char limitexceeded[NUMTAGS > 30 ? -1 : 1]; }; 885 #else 886 struct NumTags { char limitexceeded[NUMTAGS > 31 ? -1 : 1]; }; 887 #endif // SCRATCHPAD_ALT_1_PATCH 888 889 /* function implementations */ 890 void 891 applyrules(Client *c) 892 { 893 const char *class, *instance; 894 Atom wintype; 895 #if WINDOWROLERULE_PATCH 896 char role[64]; 897 #endif // WINDOWROLERULE_PATCH 898 unsigned int i; 899 #if SWITCHTAG_PATCH 900 unsigned int newtagset; 901 #endif // SWITCHTAG_PATCH 902 const Rule *r; 903 Monitor *m; 904 XClassHint ch = { NULL, NULL }; 905 906 /* rule matching */ 907 #if SWALLOW_PATCH 908 c->noswallow = -1; 909 #endif // SWALLOW_PATCH 910 #if SIZEHINTS_ISFREESIZE_PATCH 911 c->isfreesize = 1; 912 #endif // SIZEHINTS_ISFREESIZE_PATCH 913 c->isfloating = 0; 914 c->tags = 0; 915 #if RENAMED_SCRATCHPADS_PATCH 916 c->scratchkey = 0; 917 #endif // RENAMED_SCRATCHPADS_PATCH 918 XGetClassHint(dpy, c->win, &ch); 919 class = ch.res_class ? ch.res_class : broken; 920 instance = ch.res_name ? ch.res_name : broken; 921 wintype = getatomprop(c, netatom[NetWMWindowType], XA_ATOM); 922 #if WINDOWROLERULE_PATCH 923 gettextprop(c->win, wmatom[WMWindowRole], role, sizeof(role)); 924 #endif // WINDOWROLERULE_PATCH 925 926 #if STEAM_PATCH 927 if (strstr(class, "Steam") || strstr(class, "steam_app_")) 928 c->issteam = 1; 929 #endif // STEAM_PATCH 930 931 for (i = 0; i < LENGTH(rules); i++) { 932 r = &rules[i]; 933 if ((!r->title || strstr(c->name, r->title)) 934 && (!r->class || strstr(class, r->class)) 935 #if WINDOWROLERULE_PATCH 936 && (!r->role || strstr(role, r->role)) 937 #endif // WINDOWROLERULE_PATCH 938 && (!r->instance || strstr(instance, r->instance)) 939 && (!r->wintype || wintype == XInternAtom(dpy, r->wintype, False))) 940 { 941 #if CENTER_PATCH 942 c->iscentered = r->iscentered; 943 #endif // CENTER_PATCH 944 #if BORDER_RULE_PATCH 945 if (r->bw != -1) 946 c->bw = r->bw; 947 #endif // BORDER_RULE_PATCH 948 #if ISPERMANENT_PATCH 949 c->ispermanent = r->ispermanent; 950 #endif // ISPERMANENT_PATCH 951 #if SELECTIVEFAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH 952 c->fakefullscreen = r->isfakefullscreen; 953 #endif // SELECTIVEFAKEFULLSCREEN_PATCH 954 #if GAMES_PATCH 955 c->isgame = r->isgame; 956 #endif // GAMES_PATCH 957 #if SWALLOW_PATCH 958 c->isterminal = r->isterminal; 959 c->noswallow = r->noswallow; 960 #endif // SWALLOW_PATCH 961 #if SIZEHINTS_ISFREESIZE_PATCH 962 c->isfreesize = r->isfreesize; 963 #endif // SIZEHINTS_ISFREESIZE_PATCH 964 c->isfloating = r->isfloating; 965 c->tags |= r->tags; 966 #if RENAMED_SCRATCHPADS_PATCH 967 c->scratchkey = r->scratchkey; 968 #elif SCRATCHPADS_PATCH 969 if ((r->tags & SPTAGMASK) && r->isfloating) { 970 c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); 971 c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); 972 } 973 #endif // SCRATCHPADS_PATCH 974 #if UNMANAGED_PATCH 975 unmanaged = r->unmanaged; 976 #endif // UNMANAGED_PATCH 977 for (m = mons; m && m->num != r->monitor; m = m->next); 978 if (m) 979 c->mon = m; 980 #if FLOATPOS_PATCH 981 if (c->isfloating && r->floatpos) { 982 #if CENTER_PATCH 983 c->iscentered = 0; 984 #endif // CENTER_PATCH 985 setfloatpos(c, r->floatpos); 986 } 987 #endif // FLOATPOS_PATCH 988 989 #if SWITCHTAG_PATCH 990 #if SWALLOW_PATCH 991 if (r->switchtag && ( 992 c->noswallow > 0 || 993 !termforwin(c) || 994 !(c->isfloating && swallowfloating && c->noswallow < 0))) 995 #else 996 if (r->switchtag) 997 #endif // SWALLOW_PATCH 998 { 999 unfocus(selmon->sel, 1, NULL); 1000 selmon = c->mon; 1001 if (r->switchtag == 2 || r->switchtag == 4) 1002 newtagset = c->mon->tagset[c->mon->seltags] ^ c->tags; 1003 else 1004 newtagset = c->tags; 1005 1006 /* Switch to the client's tag, but only if that tag is not already shown */ 1007 if (newtagset && !(c->tags & c->mon->tagset[c->mon->seltags])) { 1008 if (r->switchtag == 3 || r->switchtag == 4) 1009 c->switchtag = c->mon->tagset[c->mon->seltags]; 1010 if (r->switchtag == 1 || r->switchtag == 3) { 1011 view(&((Arg) { .ui = newtagset })); 1012 } else { 1013 #if TAGSYNC_PATCH 1014 for (m = mons; m; m = m->next) 1015 m->tagset[m->seltags] = newtagset; 1016 arrange(NULL); 1017 #else 1018 c->mon->tagset[c->mon->seltags] = newtagset; 1019 arrange(c->mon); 1020 #endif // TAGSYNC_PATCH 1021 } 1022 } 1023 } 1024 #endif // SWITCHTAG_PATCH 1025 #if XKB_PATCH 1026 if (r->xkb_layout > -1) 1027 c->xkb->group = r->xkb_layout; 1028 #endif // XKB_PATCH 1029 #if ONLY_ONE_RULE_MATCH_PATCH 1030 break; 1031 #endif // ONLY_ONE_RULE_MATCH_PATCH 1032 } 1033 } 1034 if (ch.res_class) 1035 XFree(ch.res_class); 1036 if (ch.res_name) 1037 XFree(ch.res_name); 1038 #if EMPTYVIEW_PATCH 1039 if (c->tags & TAGMASK) c->tags = c->tags & TAGMASK; 1040 #if SCRATCHPADS_PATCH && !RENAMED_SCRATCHPADS_PATCH 1041 else if (c->mon->tagset[c->mon->seltags]) c->tags = c->mon->tagset[c->mon->seltags] & ~SPTAGMASK; 1042 #elif SCRATCHPAD_ALT_1_PATCH 1043 else if (c->tags != SCRATCHPAD_MASK && c->mon->tagset[c->mon->seltags]) c->tags = c->mon->tagset[c->mon->seltags]; 1044 #else 1045 else if (c->mon->tagset[c->mon->seltags]) c->tags = c->mon->tagset[c->mon->seltags]; 1046 #endif // SCRATCHPADS_PATCH 1047 else c->tags = 1; 1048 #elif SCRATCHPADS_PATCH && !RENAMED_SCRATCHPADS_PATCH 1049 c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : (c->mon->tagset[c->mon->seltags] & ~SPTAGMASK); 1050 #elif SCRATCHPAD_ALT_1_PATCH 1051 if (c->tags != SCRATCHPAD_MASK) 1052 c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; 1053 #else 1054 c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; 1055 #endif // EMPTYVIEW_PATCH 1056 } 1057 1058 int 1059 applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) 1060 { 1061 int baseismin; 1062 Monitor *m = c->mon; 1063 1064 /* set minimum possible */ 1065 *w = MAX(1, *w); 1066 *h = MAX(1, *h); 1067 if (interact) { 1068 if (*x > sw) 1069 *x = sw - WIDTH(c); 1070 if (*y > sh) 1071 *y = sh - HEIGHT(c); 1072 if (*x + *w + 2 * c->bw < 0) 1073 *x = 0; 1074 if (*y + *h + 2 * c->bw < 0) 1075 *y = 0; 1076 } else { 1077 if (*x >= m->wx + m->ww) 1078 *x = m->wx + m->ww - WIDTH(c); 1079 if (*y >= m->wy + m->wh) 1080 *y = m->wy + m->wh - HEIGHT(c); 1081 if (*x + *w + 2 * c->bw <= m->wx) 1082 *x = m->wx; 1083 if (*y + *h + 2 * c->bw <= m->wy) 1084 *y = m->wy; 1085 } 1086 if (*h < bh) 1087 *h = bh; 1088 if (*w < bh) 1089 *w = bh; 1090 if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { 1091 if (!c->hintsvalid) 1092 updatesizehints(c); 1093 /* see last two sentences in ICCCM 4.1.2.3 */ 1094 baseismin = c->basew == c->minw && c->baseh == c->minh; 1095 if (!baseismin) { /* temporarily remove base dimensions */ 1096 *w -= c->basew; 1097 *h -= c->baseh; 1098 } 1099 /* adjust for aspect limits */ 1100 if (c->mina > 0 && c->maxa > 0) { 1101 if (c->maxa < (float)*w / *h) 1102 *w = *h * c->maxa + 0.5; 1103 else if (c->mina < (float)*h / *w) 1104 *h = *w * c->mina + 0.5; 1105 } 1106 if (baseismin) { /* increment calculation requires this */ 1107 *w -= c->basew; 1108 *h -= c->baseh; 1109 } 1110 /* adjust for increment value */ 1111 if (c->incw) 1112 *w -= *w % c->incw; 1113 if (c->inch) 1114 *h -= *h % c->inch; 1115 /* restore base dimensions */ 1116 *w = MAX(*w + c->basew, c->minw); 1117 *h = MAX(*h + c->baseh, c->minh); 1118 if (c->maxw) 1119 *w = MIN(*w, c->maxw); 1120 if (c->maxh) 1121 *h = MIN(*h, c->maxh); 1122 } 1123 return *x != c->x || *y != c->y || *w != c->w || *h != c->h; 1124 } 1125 1126 void 1127 arrange(Monitor *m) 1128 { 1129 if (m) 1130 showhide(m->stack); 1131 else for (m = mons; m; m = m->next) 1132 showhide(m->stack); 1133 if (m) { 1134 arrangemon(m); 1135 restack(m); 1136 } else for (m = mons; m; m = m->next) 1137 arrangemon(m); 1138 } 1139 1140 void 1141 arrangemon(Monitor *m) 1142 { 1143 #if BAR_PADDING_SMART_PATCH 1144 updatebarpos(selmon); 1145 for (Bar *bar = selmon->bar; bar; bar = bar->next) 1146 XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); 1147 #endif // BAR_PADDING_SMART_PATCH 1148 #if TAB_PATCH 1149 updatebarpos(m); 1150 XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); 1151 #endif // TAB_PATCH 1152 strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); 1153 if (m->lt[m->sellt]->arrange) 1154 m->lt[m->sellt]->arrange(m); 1155 } 1156 1157 void 1158 attach(Client *c) 1159 { 1160 c->next = c->mon->clients; 1161 c->mon->clients = c; 1162 } 1163 1164 void 1165 attachstack(Client *c) 1166 { 1167 c->snext = c->mon->stack; 1168 c->mon->stack = c; 1169 } 1170 1171 void 1172 buttonpress(XEvent *e) 1173 { 1174 int click, i, r; 1175 #if TAB_PATCH 1176 int x; 1177 #endif // TAB_PATCH 1178 Arg arg = {0}; 1179 Client *c; 1180 Monitor *m; 1181 Bar *bar; 1182 XButtonPressedEvent *ev = &e->xbutton; 1183 const BarRule *br; 1184 BarArg carg = { 0, 0, 0, 0 }; 1185 click = ClkRootWin; 1186 1187 #if BAR_STATUSCMD_PATCH && !BAR_DWMBLOCKS_PATCH 1188 *lastbutton = '0' + ev->button; 1189 #endif // BAR_STATUSCMD_PATCH | BAR_DWMBLOCKS_PATCH 1190 1191 /* focus monitor if necessary */ 1192 if ((m = wintomon(ev->window)) && m != selmon 1193 #if FOCUSONCLICK_PATCH 1194 && (focusonwheel || (ev->button != Button4 && ev->button != Button5)) 1195 #endif // FOCUSONCLICK_PATCH 1196 ) { 1197 unfocus(selmon->sel, 1, NULL); 1198 selmon = m; 1199 focus(NULL); 1200 } 1201 1202 #if BANISH_PATCH 1203 c = wintoclient(ev->window); 1204 1205 if (!c && cursor_hidden) { 1206 c = recttoclient(mouse_x, mouse_y, 1, 1, 1); 1207 showcursor(NULL); 1208 } 1209 1210 if (c) { 1211 #if FOCUSONCLICK_PATCH 1212 if (focusonwheel || (ev->button != Button4 && ev->button != Button5)) 1213 focus(c); 1214 #else 1215 focus(c); 1216 restack(selmon); 1217 #endif // FOCUSONCLICK_PATCH 1218 XAllowEvents(dpy, ReplayPointer, CurrentTime); 1219 click = ClkClientWin; 1220 } 1221 #endif // BANISH_PATCH 1222 1223 for (bar = selmon->bar; bar; bar = bar->next) { 1224 if (ev->window == bar->win) { 1225 for (r = 0; r < LENGTH(barrules); r++) { 1226 br = &barrules[r]; 1227 if (br->bar != bar->idx || (br->monitor == 'A' && m != selmon) || br->clickfunc == NULL) 1228 continue; 1229 if (br->monitor != 'A' && br->monitor != -1 && br->monitor != bar->mon->num) 1230 continue; 1231 if (bar->x[r] <= ev->x && ev->x <= bar->x[r] + bar->w[r]) { 1232 carg.x = ev->x - bar->x[r]; 1233 carg.y = ev->y - bar->borderpx; 1234 carg.w = bar->w[r]; 1235 carg.h = bar->bh - 2 * bar->borderpx; 1236 click = br->clickfunc(bar, &arg, &carg); 1237 if (click < 0) 1238 return; 1239 break; 1240 } 1241 } 1242 break; 1243 } 1244 } 1245 1246 #if TAB_PATCH 1247 if (ev->window == selmon->tabwin) { 1248 for (i = 0, x = 0, c = selmon->clients; c; c = c->next) { 1249 if (!ISVISIBLE(c) || HIDDEN(c)) 1250 continue; 1251 x += selmon->tab_widths[i]; 1252 if (ev->x > x) 1253 ++i; 1254 else 1255 break; 1256 if (i >= m->ntabs) 1257 break; 1258 } 1259 if (c) { 1260 click = ClkTabBar; 1261 arg.ui = i; 1262 } 1263 } 1264 #endif // TAB_PATCH 1265 1266 #if !BANISH_PATCH 1267 if (click == ClkRootWin && (c = wintoclient(ev->window))) { 1268 #if FOCUSONCLICK_PATCH 1269 if (focusonwheel || (ev->button != Button4 && ev->button != Button5)) 1270 focus(c); 1271 #else 1272 focus(c); 1273 restack(selmon); 1274 #endif // FOCUSONCLICK_PATCH 1275 XAllowEvents(dpy, ReplayPointer, CurrentTime); 1276 click = ClkClientWin; 1277 } 1278 #endif // BANISH_PATCH 1279 1280 for (i = 0; i < LENGTH(buttons); i++) { 1281 if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button 1282 && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) { 1283 buttons[i].func( 1284 ( 1285 click == ClkTagBar 1286 #if TAB_PATCH 1287 || click == ClkTabBar 1288 #endif // TAB_PATCH 1289 #if BAR_WINTITLEACTIONS_PATCH 1290 || click == ClkWinTitle 1291 #endif // BAR_WINTITLEACTIONS_PATCH 1292 ) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg 1293 ); 1294 } 1295 } 1296 1297 #if BANISH_PATCH 1298 last_button_press = now(); 1299 #endif // BANISH_PATCH 1300 } 1301 1302 void 1303 checkotherwm(void) 1304 { 1305 xerrorxlib = XSetErrorHandler(xerrorstart); 1306 /* this causes an error if some other window manager is running */ 1307 XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask); 1308 XSync(dpy, False); 1309 XSetErrorHandler(xerror); 1310 XSync(dpy, False); 1311 } 1312 1313 void 1314 cleanup(void) 1315 { 1316 Monitor *m; 1317 Layout foo = { "", NULL }; 1318 size_t i; 1319 1320 #if ALT_TAB_PATCH 1321 alttabend(); 1322 #endif // ALT_TAB_PATCH 1323 1324 #if SEAMLESS_RESTART_PATCH 1325 for (m = mons; m; m = m->next) 1326 persistmonitorstate(m); 1327 #endif // SEAMLESS_RESTART_PATCH 1328 1329 #if COOL_AUTOSTART_PATCH 1330 /* kill child processes, but not on restart (autostart_exec will handle it) */ 1331 #if RESTARTSIG_PATCH 1332 if (!restart) { 1333 #endif // RESTARTSIG_PATCH 1334 for (i = 0; i < autostart_len; i++) { 1335 if (0 < autostart_pids[i]) { 1336 kill(autostart_pids[i], SIGTERM); 1337 waitpid(autostart_pids[i], NULL, 0); 1338 } 1339 } 1340 #if RESTARTSIG_PATCH 1341 } 1342 #endif // RESTARTSIG_PATCH 1343 #endif // COOL_AUTOSTART_PATCH 1344 1345 selmon->lt[selmon->sellt] = &foo; 1346 for (m = mons; m; m = m->next) 1347 while (m->stack) 1348 unmanage(m->stack, 0); 1349 XUngrabKey(dpy, AnyKey, AnyModifier, root); 1350 while (mons) 1351 cleanupmon(mons); 1352 #if BAR_SYSTRAY_PATCH 1353 if (showsystray && systray) { 1354 while (systray->icons) 1355 removesystrayicon(systray->icons); 1356 if (systray->win) { 1357 XUnmapWindow(dpy, systray->win); 1358 XDestroyWindow(dpy, systray->win); 1359 } 1360 free(systray); 1361 } 1362 #endif // BAR_SYSTRAY_PATCH 1363 for (i = 0; i < CurLast; i++) 1364 drw_cur_free(drw, cursor[i]); 1365 #if BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH 1366 for (i = 0; i < LENGTH(colors) + 1; i++) 1367 #else 1368 for (i = 0; i < LENGTH(colors); i++) 1369 #endif // BAR_STATUS2D_PATCH 1370 free(scheme[i]); 1371 free(scheme); 1372 XDestroyWindow(dpy, wmcheckwin); 1373 drw_free(drw); 1374 XSync(dpy, False); 1375 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); 1376 XDeleteProperty(dpy, root, netatom[NetActiveWindow]); 1377 1378 #if IPC_PATCH 1379 ipc_cleanup(); 1380 1381 if (close(epoll_fd) < 0) 1382 fprintf(stderr, "Failed to close epoll file descriptor\n"); 1383 #endif // IPC_PATCH 1384 } 1385 1386 void 1387 cleanupmon(Monitor *mon) 1388 { 1389 Monitor *m; 1390 Bar *bar; 1391 1392 if (mon == mons) 1393 mons = mons->next; 1394 else { 1395 for (m = mons; m && m->next != mon; m = m->next); 1396 m->next = mon->next; 1397 } 1398 for (bar = mon->bar; bar; bar = mon->bar) { 1399 if (!bar->external) { 1400 XUnmapWindow(dpy, bar->win); 1401 XDestroyWindow(dpy, bar->win); 1402 } 1403 mon->bar = bar->next; 1404 #if BAR_SYSTRAY_PATCH 1405 if (systray && bar == systray->bar) 1406 systray->bar = NULL; 1407 #endif // BAR_SYSTRAY_PATCH 1408 free(bar); 1409 } 1410 #if TAB_PATCH 1411 XUnmapWindow(dpy, mon->tabwin); 1412 XDestroyWindow(dpy, mon->tabwin); 1413 #endif // TAB_PATCH 1414 #if PERTAG_PATCH 1415 free(mon->pertag); 1416 #endif // PERTAG_PATCH 1417 #if BAR_TAGPREVIEW_PATCH 1418 for (size_t i = 0; i < NUMTAGS; i++) 1419 if (mon->tagmap[i]) 1420 XFreePixmap(dpy, mon->tagmap[i]); 1421 XUnmapWindow(dpy, mon->tagwin); 1422 XDestroyWindow(dpy, mon->tagwin); 1423 #endif // BAR_TAGPREVIEW_PATCH 1424 free(mon); 1425 } 1426 1427 void 1428 clientmessage(XEvent *e) 1429 { 1430 #if BAR_SYSTRAY_PATCH 1431 XWindowAttributes wa; 1432 XSetWindowAttributes swa; 1433 #endif // BAR_SYSTRAY_PATCH 1434 XClientMessageEvent *cme = &e->xclient; 1435 Client *c = wintoclient(cme->window); 1436 #if FOCUSONNETACTIVE_PATCH 1437 unsigned int i; 1438 #endif // FOCUSONNETACTIVE_PATCH 1439 1440 #if BAR_SYSTRAY_PATCH 1441 if (showsystray && systray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { 1442 /* add systray icons */ 1443 if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { 1444 if (!(c = (Client *)calloc(1, sizeof(Client)))) 1445 die("fatal: could not malloc() %u bytes\n", sizeof(Client)); 1446 if (!(c->win = cme->data.l[2])) { 1447 free(c); 1448 return; 1449 } 1450 1451 c->mon = selmon; 1452 c->next = systray->icons; 1453 systray->icons = c; 1454 XGetWindowAttributes(dpy, c->win, &wa); 1455 c->x = c->oldx = c->y = c->oldy = 0; 1456 c->w = c->oldw = wa.width; 1457 c->h = c->oldh = wa.height; 1458 c->oldbw = wa.border_width; 1459 c->bw = 0; 1460 c->isfloating = True; 1461 /* reuse tags field as mapped status */ 1462 c->tags = 1; 1463 updatesizehints(c); 1464 updatesystrayicongeom(c, wa.width, wa.height); 1465 XAddToSaveSet(dpy, c->win); 1466 XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); 1467 XClassHint ch = {"dwmsystray", "dwmsystray"}; 1468 XSetClassHint(dpy, c->win, &ch); 1469 XReparentWindow(dpy, c->win, systray->win, 0, 0); 1470 /* use parents background color */ 1471 swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; 1472 XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); 1473 sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); 1474 XSync(dpy, False); 1475 setclientstate(c, NormalState); 1476 } 1477 return; 1478 } 1479 #endif // BAR_SYSTRAY_PATCH 1480 1481 if (!c) 1482 return; 1483 if (cme->message_type == netatom[NetWMState]) { 1484 if (cme->data.l[1] == netatom[NetWMFullscreen] 1485 || cme->data.l[2] == netatom[NetWMFullscreen]) { 1486 #if FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH 1487 if (c->fakefullscreen == 2 && c->isfullscreen) 1488 c->fakefullscreen = 3; 1489 #endif // FAKEFULLSCREEN_CLIENT_PATCH 1490 setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ 1491 || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ 1492 #if !FAKEFULLSCREEN_PATCH 1493 && !c->isfullscreen 1494 #endif // !FAKEFULLSCREEN_PATCH 1495 ))); 1496 } 1497 } else if (cme->message_type == netatom[NetActiveWindow]) { 1498 #if FOCUSONNETACTIVE_PATCH 1499 if (c->tags & c->mon->tagset[c->mon->seltags]) 1500 focus(c); 1501 else { 1502 for (i = 0; i < NUMTAGS && !((1 << i) & c->tags); i++); 1503 if (i < NUMTAGS) { 1504 if (c != selmon->sel) 1505 unfocus(selmon->sel, 0, NULL); 1506 selmon = c->mon; 1507 if (((1 << i) & TAGMASK) != selmon->tagset[selmon->seltags]) 1508 view(&((Arg) { .ui = 1 << i })); 1509 focus(c); 1510 restack(selmon); 1511 } 1512 } 1513 #else 1514 if (c != selmon->sel && !c->isurgent) 1515 seturgent(c, 1); 1516 #endif // FOCUSONNETACTIVE_PATCH 1517 } 1518 } 1519 1520 void 1521 configure(Client *c) 1522 { 1523 XConfigureEvent ce; 1524 1525 ce.type = ConfigureNotify; 1526 ce.display = dpy; 1527 ce.event = c->win; 1528 ce.window = c->win; 1529 ce.x = c->x; 1530 ce.y = c->y; 1531 ce.width = c->w; 1532 ce.height = c->h; 1533 ce.border_width = c->bw; 1534 1535 #if NOBORDER_PATCH 1536 if (noborder(c)) { 1537 ce.width += c->bw * 2; 1538 ce.height += c->bw * 2; 1539 ce.border_width = 0; 1540 } 1541 #endif // NOBORDER_PATCH 1542 1543 ce.above = None; 1544 ce.override_redirect = False; 1545 XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); 1546 } 1547 1548 void 1549 configurenotify(XEvent *e) 1550 { 1551 Monitor *m; 1552 Bar *bar; 1553 #if !FAKEFULLSCREEN_PATCH 1554 Client *c; 1555 #endif // !FAKEFULLSCREEN_PATCH 1556 XConfigureEvent *ev = &e->xconfigure; 1557 int dirty; 1558 /* TODO: updategeom handling sucks, needs to be simplified */ 1559 if (ev->window == root) { 1560 dirty = (sw != ev->width || sh != ev->height); 1561 sw = ev->width; 1562 sh = ev->height; 1563 if (updategeom() || dirty) { 1564 drw_resize(drw, sw, sh); 1565 updatebars(); 1566 for (m = mons; m; m = m->next) { 1567 #if !FAKEFULLSCREEN_PATCH 1568 for (c = m->clients; c; c = c->next) 1569 #if FAKEFULLSCREEN_CLIENT_PATCH 1570 if (c->isfullscreen && c->fakefullscreen != 1) 1571 #else 1572 if (c->isfullscreen) 1573 #endif // FAKEFULLSCREEN_CLIENT_PATCH 1574 resizeclient(c, m->mx, m->my, m->mw, m->mh); 1575 #endif // !FAKEFULLSCREEN_PATCH 1576 for (bar = m->bar; bar; bar = bar->next) 1577 XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); 1578 #if BAR_TAGPREVIEW_PATCH 1579 createpreview(m); 1580 #endif // BAR_TAGPREVIEW_PATCH 1581 } 1582 arrange(NULL); 1583 focus(NULL); 1584 } 1585 } 1586 } 1587 1588 void 1589 configurerequest(XEvent *e) 1590 { 1591 Client *c; 1592 Monitor *m; 1593 #if BAR_ANYBAR_PATCH 1594 Bar *bar; 1595 #endif // BAR_ANYBAR_PATCH 1596 XConfigureRequestEvent *ev = &e->xconfigurerequest; 1597 XWindowChanges wc; 1598 1599 if (ignoreconfigurerequests) 1600 return; 1601 1602 if ((c = wintoclient(ev->window))) { 1603 if (ev->value_mask & CWBorderWidth) 1604 c->bw = ev->border_width; 1605 else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { 1606 m = c->mon; 1607 #if STEAM_PATCH 1608 if (!c->issteam) { 1609 if (ev->value_mask & CWX) { 1610 c->oldx = c->x; 1611 c->x = m->mx + ev->x; 1612 } 1613 if (ev->value_mask & CWY) { 1614 c->oldy = c->y; 1615 c->y = m->my + ev->y; 1616 } 1617 } 1618 #else 1619 if (ev->value_mask & CWX) { 1620 c->oldx = c->x; 1621 c->x = m->mx + ev->x; 1622 } 1623 if (ev->value_mask & CWY) { 1624 c->oldy = c->y; 1625 c->y = m->my + ev->y; 1626 } 1627 #endif // STEAM_PATCH 1628 if (ev->value_mask & CWWidth) { 1629 c->oldw = c->w; 1630 c->w = ev->width; 1631 } 1632 if (ev->value_mask & CWHeight) { 1633 c->oldh = c->h; 1634 c->h = ev->height; 1635 } 1636 if ((c->x + c->w) > m->mx + m->mw && c->isfloating) 1637 c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */ 1638 if ((c->y + c->h) > m->my + m->mh && c->isfloating) 1639 c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */ 1640 if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) 1641 configure(c); 1642 if (ISVISIBLE(c)) 1643 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); 1644 #if AUTORESIZE_PATCH 1645 else 1646 c->needresize = 1; 1647 #endif // AUTORESIZE_PATCH 1648 } else 1649 configure(c); 1650 } else { 1651 wc.x = ev->x; 1652 wc.y = ev->y; 1653 #if BAR_ANYBAR_PATCH 1654 m = wintomon(ev->window); 1655 for (bar = m->bar; bar; bar = bar->next) { 1656 if (bar->win == ev->window) { 1657 wc.y = bar->by; 1658 wc.x = bar->bx; 1659 } 1660 } 1661 #endif // BAR_ANYBAR_PATCH 1662 wc.width = ev->width; 1663 wc.height = ev->height; 1664 wc.border_width = ev->border_width; 1665 wc.sibling = ev->above; 1666 wc.stack_mode = ev->detail; 1667 XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); 1668 } 1669 XSync(dpy, False); 1670 } 1671 1672 Monitor * 1673 createmon(void) 1674 { 1675 Monitor *m, *mon; 1676 int i, n, mi, max_bars = 2, istopbar = topbar; 1677 #if MONITOR_RULES_PATCH 1678 int layout; 1679 #endif // MONITOR_RULES_PATCH 1680 1681 const BarRule *br; 1682 Bar *bar; 1683 #if MONITOR_RULES_PATCH 1684 int j; 1685 const MonitorRule *mr; 1686 #endif // MONITOR_RULES_PATCH 1687 1688 m = ecalloc(1, sizeof(Monitor)); 1689 #if !EMPTYVIEW_PATCH 1690 #if VIEW_HISTORY_PATCH 1691 for (i = 0; i < LENGTH(m->tagset); i++) 1692 m->tagset[i] = 1; 1693 #else 1694 m->tagset[0] = m->tagset[1] = 1; 1695 #endif // VIEW_HISTORY_PATCH 1696 #endif // EMPTYVIEW_PATCH 1697 m->mfact = mfact; 1698 m->nmaster = nmaster; 1699 #if FLEXTILE_DELUXE_LAYOUT 1700 m->nstack = nstack; 1701 #endif // FLEXTILE_DELUXE_LAYOUT 1702 m->showbar = showbar; 1703 #if TAB_PATCH 1704 m->showtab = showtab; 1705 m->toptab = toptab; 1706 m->ntabs = 0; 1707 #endif // TAB_PATCH 1708 #if SETBORDERPX_PATCH 1709 m->borderpx = borderpx; 1710 #endif // SETBORDERPX_PATCH 1711 #if VANITYGAPS_PATCH 1712 m->gappih = gappih; 1713 m->gappiv = gappiv; 1714 m->gappoh = gappoh; 1715 m->gappov = gappov; 1716 #endif // VANITYGAPS_PATCH 1717 for (mi = 0, mon = mons; mon; mon = mon->next, mi++); // monitor index 1718 m->num = mi; 1719 #if MONITOR_RULES_PATCH 1720 for (j = 0; j < LENGTH(monrules); j++) { 1721 mr = &monrules[j]; 1722 if ((mr->monitor == -1 || mr->monitor == m->num) 1723 #if PERTAG_PATCH 1724 && (mr->tag <= 0 || (m->tagset[0] & (1 << (mr->tag - 1)))) 1725 #endif // PERTAG_PATCH 1726 ) { 1727 layout = MAX(mr->layout, 0); 1728 layout = MIN(layout, LENGTH(layouts) - 1); 1729 m->lt[0] = &layouts[layout]; 1730 m->lt[1] = &layouts[1 % LENGTH(layouts)]; 1731 strncpy(m->ltsymbol, layouts[layout].symbol, sizeof m->ltsymbol); 1732 1733 if (mr->mfact > -1) 1734 m->mfact = mr->mfact; 1735 if (mr->nmaster > -1) 1736 m->nmaster = mr->nmaster; 1737 if (mr->showbar > -1) 1738 m->showbar = mr->showbar; 1739 if (mr->topbar > -1) 1740 istopbar = mr->topbar; 1741 break; 1742 } 1743 } 1744 #else 1745 m->lt[0] = &layouts[0]; 1746 m->lt[1] = &layouts[1 % LENGTH(layouts)]; 1747 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); 1748 #endif // MONITOR_RULES_PATCH 1749 1750 /* Derive the number of bars for this monitor based on bar rules */ 1751 for (n = -1, i = 0; i < LENGTH(barrules); i++) { 1752 br = &barrules[i]; 1753 if (br->monitor == 'A' || br->monitor == -1 || br->monitor == m->num) 1754 n = MAX(br->bar, n); 1755 } 1756 1757 m->bar = NULL; 1758 for (i = 0; i <= n && i < max_bars; i++) { 1759 bar = ecalloc(1, sizeof(Bar)); 1760 bar->mon = m; 1761 bar->idx = i; 1762 bar->next = m->bar; 1763 bar->topbar = istopbar; 1764 m->bar = bar; 1765 istopbar = !istopbar; 1766 bar->showbar = 1; 1767 bar->external = 0; 1768 #if BAR_BORDER_PATCH 1769 bar->borderpx = (barborderpx ? barborderpx : borderpx); 1770 #else 1771 bar->borderpx = 0; 1772 #endif // BAR_BORDER_PATCH 1773 bar->bh = bh + bar->borderpx * 2; 1774 bar->borderscheme = SchemeNorm; 1775 } 1776 1777 #if FLEXTILE_DELUXE_LAYOUT 1778 m->ltaxis[LAYOUT] = m->lt[0]->preset.layout; 1779 m->ltaxis[MASTER] = m->lt[0]->preset.masteraxis; 1780 m->ltaxis[STACK] = m->lt[0]->preset.stack1axis; 1781 m->ltaxis[STACK2] = m->lt[0]->preset.stack2axis; 1782 #endif // FLEXTILE_DELUXE_LAYOUT 1783 1784 #if PERTAG_PATCH 1785 if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) 1786 die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); 1787 m->pertag->curtag = 1; 1788 for (i = 0; i <= NUMTAGS; i++) { 1789 #if FLEXTILE_DELUXE_LAYOUT 1790 m->pertag->nstacks[i] = m->nstack; 1791 #endif // FLEXTILE_DELUXE_LAYOUT 1792 1793 #if !MONITOR_RULES_PATCH 1794 /* init nmaster */ 1795 m->pertag->nmasters[i] = m->nmaster; 1796 1797 /* init mfacts */ 1798 m->pertag->mfacts[i] = m->mfact; 1799 1800 #if PERTAGBAR_PATCH 1801 /* init showbar */ 1802 m->pertag->showbars[i] = m->showbar; 1803 #endif // PERTAGBAR_PATCH 1804 #endif // MONITOR_RULES_PATCH 1805 1806 #if ZOOMSWAP_PATCH 1807 m->pertag->prevzooms[i] = NULL; 1808 #endif // ZOOMSWAP_PATCH 1809 1810 /* init layouts */ 1811 #if MONITOR_RULES_PATCH 1812 for (j = 0; j < LENGTH(monrules); j++) { 1813 mr = &monrules[j]; 1814 if ((mr->monitor == -1 || mr->monitor == m->num) && (mr->tag == -1 || mr->tag == i)) { 1815 layout = MAX(mr->layout, 0); 1816 layout = MIN(layout, LENGTH(layouts) - 1); 1817 m->pertag->ltidxs[i][0] = &layouts[layout]; 1818 m->pertag->ltidxs[i][1] = m->lt[0]; 1819 m->pertag->nmasters[i] = (mr->nmaster > -1 ? mr->nmaster : m->nmaster); 1820 m->pertag->mfacts[i] = (mr->mfact > -1 ? mr->mfact : m->mfact); 1821 #if PERTAGBAR_PATCH 1822 m->pertag->showbars[i] = (mr->showbar > -1 ? mr->showbar : m->showbar); 1823 #endif // PERTAGBAR_PATCH 1824 #if FLEXTILE_DELUXE_LAYOUT 1825 m->pertag->ltaxis[i][LAYOUT] = m->pertag->ltidxs[i][0]->preset.layout; 1826 m->pertag->ltaxis[i][MASTER] = m->pertag->ltidxs[i][0]->preset.masteraxis; 1827 m->pertag->ltaxis[i][STACK] = m->pertag->ltidxs[i][0]->preset.stack1axis; 1828 m->pertag->ltaxis[i][STACK2] = m->pertag->ltidxs[i][0]->preset.stack2axis; 1829 #endif // FLEXTILE_DELUXE_LAYOUT 1830 break; 1831 } 1832 } 1833 #else 1834 m->pertag->ltidxs[i][0] = m->lt[0]; 1835 m->pertag->ltidxs[i][1] = m->lt[1]; 1836 #if FLEXTILE_DELUXE_LAYOUT 1837 /* init flextile axes */ 1838 m->pertag->ltaxis[i][LAYOUT] = m->ltaxis[LAYOUT]; 1839 m->pertag->ltaxis[i][MASTER] = m->ltaxis[MASTER]; 1840 m->pertag->ltaxis[i][STACK] = m->ltaxis[STACK]; 1841 m->pertag->ltaxis[i][STACK2] = m->ltaxis[STACK2]; 1842 #endif // FLEXTILE_DELUXE_LAYOUT 1843 #endif // MONITOR_RULES_PATCH 1844 m->pertag->sellts[i] = m->sellt; 1845 1846 #if PERTAG_VANITYGAPS_PATCH && VANITYGAPS_PATCH 1847 m->pertag->enablegaps[i] = 1; 1848 m->pertag->gaps[i] = 1849 ((gappoh & 0xFF) << 0) | ((gappov & 0xFF) << 8) | ((gappih & 0xFF) << 16) | ((gappiv & 0xFF) << 24); 1850 #endif // PERTAG_VANITYGAPS_PATCH | VANITYGAPS_PATCH 1851 } 1852 #endif // PERTAG_PATCH 1853 1854 #if PERMON_VANITYGAPS_PATCH 1855 m->enablegaps = 1; 1856 #endif // PERMON_VANITYGAPS_PATCH 1857 1858 #if SEAMLESS_RESTART_PATCH 1859 restoremonitorstate(m); 1860 #endif // SEAMLESS_RESTART_PATCH 1861 1862 #if INSETS_PATCH 1863 m->inset = default_inset; 1864 #endif // INSETS_PATCH 1865 return m; 1866 } 1867 1868 void 1869 destroynotify(XEvent *e) 1870 { 1871 Client *c; 1872 #if BAR_ANYBAR_PATCH 1873 Monitor *m; 1874 Bar *bar; 1875 #endif // BAR_ANYBAR_PATCH 1876 XDestroyWindowEvent *ev = &e->xdestroywindow; 1877 1878 if ((c = wintoclient(ev->window))) 1879 unmanage(c, 1); 1880 #if SWALLOW_PATCH 1881 else if ((c = swallowingclient(ev->window))) 1882 unmanage(c->swallowing, 1); 1883 #endif // SWALLOW_PATCH 1884 #if BAR_SYSTRAY_PATCH 1885 else if (showsystray && (c = wintosystrayicon(ev->window))) { 1886 removesystrayicon(c); 1887 drawbarwin(systray->bar); 1888 } 1889 #endif // BAR_SYSTRAY_PATCH 1890 #if BAR_ANYBAR_PATCH 1891 else { 1892 m = wintomon(ev->window); 1893 for (bar = m->bar; bar; bar = bar->next) { 1894 if (bar->win == ev->window) { 1895 unmanagealtbar(ev->window); 1896 break; 1897 } 1898 } 1899 } 1900 #endif // BAR_ANYBAR_PATCH 1901 } 1902 1903 void 1904 detach(Client *c) 1905 { 1906 Client **tc; 1907 #if SEAMLESS_RESTART_PATCH 1908 c->idx = 0; 1909 #endif // SEAMLESS_RESTART_PATCH 1910 #if FOCUSMASTER_RETURN_PATCH 1911 for (int i = 1; i < NUMTAGS; i++) 1912 if (c == c->mon->tagmarked[i]) 1913 c->mon->tagmarked[i] = NULL; 1914 #endif // FOCUSMASTER_RETURN_PATCH 1915 1916 for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next); 1917 *tc = c->next; 1918 c->next = NULL; 1919 } 1920 1921 void 1922 detachstack(Client *c) 1923 { 1924 Client **tc, *t; 1925 1926 for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext); 1927 *tc = c->snext; 1928 1929 if (c == c->mon->sel) { 1930 for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext); 1931 c->mon->sel = t; 1932 } 1933 c->snext = NULL; 1934 } 1935 1936 Monitor * 1937 dirtomon(int dir) 1938 { 1939 Monitor *m = NULL; 1940 1941 if (dir > 0) { 1942 if (!(m = selmon->next)) 1943 m = mons; 1944 } else if (selmon == mons) 1945 for (m = mons; m->next; m = m->next); 1946 else 1947 for (m = mons; m->next != selmon; m = m->next); 1948 return m; 1949 } 1950 1951 void 1952 drawbar(Monitor *m) 1953 { 1954 Bar *bar; 1955 1956 #if !BAR_FLEXWINTITLE_PATCH 1957 if (m->showbar) 1958 #endif // BAR_FLEXWINTITLE_PATCH 1959 for (bar = m->bar; bar; bar = bar->next) 1960 drawbarwin(bar); 1961 } 1962 1963 void 1964 drawbars(void) 1965 { 1966 Monitor *m; 1967 for (m = mons; m; m = m->next) 1968 drawbar(m); 1969 } 1970 1971 void 1972 drawbarwin(Bar *bar) 1973 { 1974 if (!bar || !bar->win || bar->external) 1975 return; 1976 int r, w, total_drawn = 0; 1977 int rx, lx, rw, lw; // bar size, split between left and right if a center module is added 1978 const BarRule *br; 1979 1980 if (bar->borderpx) { 1981 #if BAR_BORDER_COLBG_PATCH 1982 XSetForeground(drw->dpy, drw->gc, scheme[bar->borderscheme][ColBg].pixel); 1983 #else 1984 XSetForeground(drw->dpy, drw->gc, scheme[bar->borderscheme][ColBorder].pixel); 1985 #endif // BAR_BORDER_COLBG_PATCH 1986 XFillRectangle(drw->dpy, drw->drawable, drw->gc, 0, 0, bar->bw, bar->bh); 1987 } 1988 1989 BarArg warg = { 0 }; 1990 BarArg darg = { 0 }; 1991 warg.h = bar->bh - 2 * bar->borderpx; 1992 1993 rw = lw = bar->bw - 2 * bar->borderpx; 1994 rx = lx = bar->borderpx; 1995 1996 drw_setscheme(drw, scheme[SchemeNorm]); 1997 drw_rect(drw, lx, bar->borderpx, lw, bar->bh - 2 * bar->borderpx, 1, 1); 1998 for (r = 0; r < LENGTH(barrules); r++) { 1999 br = &barrules[r]; 2000 if (br->bar != bar->idx || !br->widthfunc || (br->monitor == 'A' && bar->mon != selmon)) 2001 continue; 2002 if (br->monitor != 'A' && br->monitor != -1 && br->monitor != bar->mon->num) 2003 continue; 2004 drw_setscheme(drw, scheme[SchemeNorm]); 2005 warg.w = (br->alignment < BAR_ALIGN_RIGHT_LEFT ? lw : rw); 2006 2007 w = br->widthfunc(bar, &warg); 2008 w = MIN(warg.w, w); 2009 2010 if (lw <= 0) { // if left is exhausted then switch to right side, and vice versa 2011 lw = rw; 2012 lx = rx; 2013 } else if (rw <= 0) { 2014 rw = lw; 2015 rx = lx; 2016 } 2017 2018 switch(br->alignment) { 2019 default: 2020 case BAR_ALIGN_NONE: 2021 case BAR_ALIGN_LEFT_LEFT: 2022 case BAR_ALIGN_LEFT: 2023 bar->x[r] = lx; 2024 if (lx == rx) { 2025 rx += w; 2026 rw -= w; 2027 } 2028 lx += w; 2029 lw -= w; 2030 break; 2031 case BAR_ALIGN_LEFT_RIGHT: 2032 case BAR_ALIGN_RIGHT: 2033 bar->x[r] = lx + lw - w; 2034 if (lx == rx) 2035 rw -= w; 2036 lw -= w; 2037 break; 2038 case BAR_ALIGN_LEFT_CENTER: 2039 case BAR_ALIGN_CENTER: 2040 bar->x[r] = lx + lw / 2 - w / 2; 2041 if (lx == rx) { 2042 rw = rx + rw - bar->x[r] - w; 2043 rx = bar->x[r] + w; 2044 } 2045 lw = bar->x[r] - lx; 2046 break; 2047 case BAR_ALIGN_RIGHT_LEFT: 2048 bar->x[r] = rx; 2049 if (lx == rx) { 2050 lx += w; 2051 lw -= w; 2052 } 2053 rx += w; 2054 rw -= w; 2055 break; 2056 case BAR_ALIGN_RIGHT_RIGHT: 2057 bar->x[r] = rx + rw - w; 2058 if (lx == rx) 2059 lw -= w; 2060 rw -= w; 2061 break; 2062 case BAR_ALIGN_RIGHT_CENTER: 2063 bar->x[r] = rx + rw / 2 - w / 2; 2064 if (lx == rx) { 2065 lw = lx + lw - bar->x[r] + w; 2066 lx = bar->x[r] + w; 2067 } 2068 rw = bar->x[r] - rx; 2069 break; 2070 } 2071 bar->w[r] = w; 2072 darg.x = bar->x[r]; 2073 darg.y = bar->borderpx; 2074 darg.h = bar->bh - 2 * bar->borderpx; 2075 darg.w = bar->w[r]; 2076 if (br->drawfunc) 2077 total_drawn += br->drawfunc(bar, &darg); 2078 } 2079 2080 if (total_drawn == 0 && bar->showbar) { 2081 bar->showbar = 0; 2082 updatebarpos(bar->mon); 2083 XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); 2084 arrange(bar->mon); 2085 } 2086 else if (total_drawn > 0 && !bar->showbar) { 2087 bar->showbar = 1; 2088 updatebarpos(bar->mon); 2089 XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); 2090 drw_map(drw, bar->win, 0, 0, bar->bw, bar->bh); 2091 arrange(bar->mon); 2092 } else 2093 drw_map(drw, bar->win, 0, 0, bar->bw, bar->bh); 2094 } 2095 2096 #if !FOCUSONCLICK_PATCH 2097 void 2098 enternotify(XEvent *e) 2099 { 2100 Client *c; 2101 #if LOSEFULLSCREEN_PATCH 2102 Client *sel; 2103 #endif // LOSEFULLSCREEN_PATCH 2104 Monitor *m; 2105 XCrossingEvent *ev = &e->xcrossing; 2106 2107 #if BANISH_PATCH 2108 if (cursor_hidden) 2109 return; 2110 #endif // BANISH_PATCH 2111 2112 if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) 2113 return; 2114 c = wintoclient(ev->window); 2115 m = c ? c->mon : wintomon(ev->window); 2116 if (m != selmon) { 2117 #if LOSEFULLSCREEN_PATCH 2118 sel = selmon->sel; 2119 selmon = m; 2120 unfocus(sel, 1, c); 2121 #else 2122 unfocus(selmon->sel, 1, c); 2123 selmon = m; 2124 #endif // LOSEFULLSCREEN_PATCH 2125 } else if (!c || c == selmon->sel) 2126 return; 2127 focus(c); 2128 } 2129 #endif // FOCUSONCLICK_PATCH 2130 2131 void 2132 expose(XEvent *e) 2133 { 2134 Monitor *m; 2135 XExposeEvent *ev = &e->xexpose; 2136 2137 if (ev->count == 0 && (m = wintomon(ev->window))) { 2138 drawbar(m); 2139 #if TAB_PATCH 2140 drawtabs(); 2141 #endif // TAB_PATCH 2142 } 2143 } 2144 2145 void 2146 focus(Client *c) 2147 { 2148 #if FOCUSFOLLOWMOUSE_PATCH 2149 if (!c || !ISVISIBLE(c)) 2150 c = getpointerclient(); 2151 #endif // FOCUSFOLLOWMOUSE_PATCH 2152 #if STICKY_PATCH 2153 if (!c || !ISVISIBLE(c)) 2154 for (c = selmon->stack; c && (!ISVISIBLE(c) || c->issticky); c = c->snext); 2155 #endif // STICKY_PATCH 2156 if (!c || !ISVISIBLE(c)) 2157 for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); 2158 if (selmon->sel && selmon->sel != c) 2159 unfocus(selmon->sel, 0, c); 2160 if (c) { 2161 if (c->mon != selmon) 2162 selmon = c->mon; 2163 if (c->isurgent) 2164 seturgent(c, 0); 2165 detachstack(c); 2166 attachstack(c); 2167 grabbuttons(c, 1); 2168 #if !BAR_FLEXWINTITLE_PATCH 2169 #if RENAMED_SCRATCHPADS_PATCH 2170 if (c->scratchkey != 0 && c->isfloating) 2171 XSetWindowBorder(dpy, c->win, scheme[SchemeScratchSel][ColFloat].pixel); 2172 else if (c->scratchkey != 0) 2173 XSetWindowBorder(dpy, c->win, scheme[SchemeScratchSel][ColBorder].pixel); 2174 else if (c->isfloating) 2175 XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel); 2176 else 2177 XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); 2178 #else 2179 if (c->isfloating) 2180 XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel); 2181 else 2182 XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); 2183 #endif // RENAMED_SCRATCHPADS_PATCH 2184 #endif // BAR_FLEXWINTITLE_PATCH 2185 setfocus(c); 2186 } else { 2187 #if NODMENU_PATCH 2188 XSetInputFocus(dpy, selmon->bar && selmon->bar->win ? selmon->bar->win : root, RevertToPointerRoot, CurrentTime); 2189 #else 2190 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); 2191 #endif // NODMENU_PATCH 2192 XDeleteProperty(dpy, root, netatom[NetActiveWindow]); 2193 } 2194 selmon->sel = c; 2195 drawbars(); 2196 2197 #if ON_EMPTY_KEYS_PATCH 2198 if ((isempty && selmon->sel) || (!isempty && !selmon->sel)) { 2199 isempty = !isempty; 2200 grabkeys(); 2201 } 2202 #endif // ON_EMPTY_KEYS_PATCH 2203 } 2204 2205 /* there are some broken focus acquiring clients needing extra handling */ 2206 void 2207 focusin(XEvent *e) 2208 { 2209 XFocusChangeEvent *ev = &e->xfocus; 2210 2211 if (selmon->sel && ev->window != selmon->sel->win) 2212 setfocus(selmon->sel); 2213 } 2214 2215 void 2216 focusmon(const Arg *arg) 2217 { 2218 Monitor *m; 2219 #if LOSEFULLSCREEN_PATCH 2220 Client *sel; 2221 #endif // LOSEFULLSCREEN_PATCH 2222 2223 if (!mons->next) 2224 return; 2225 if ((m = dirtomon(arg->i)) == selmon) 2226 return; 2227 #if LOSEFULLSCREEN_PATCH 2228 sel = selmon->sel; 2229 selmon = m; 2230 unfocus(sel, 0, NULL); 2231 #else 2232 unfocus(selmon->sel, 0, NULL); 2233 selmon = m; 2234 #endif // LOSEFULLSCREEN_PATCH 2235 focus(NULL); 2236 #if WARP_PATCH 2237 warp(selmon->sel); 2238 #endif // WARP_PATCH 2239 } 2240 2241 #if !STACKER_PATCH 2242 void 2243 focusstack(const Arg *arg) 2244 { 2245 Client *c = NULL, *i; 2246 2247 #if LOSEFULLSCREEN_PATCH 2248 if (!selmon->sel) 2249 return; 2250 #elif FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH 2251 if (!selmon->sel || (selmon->sel->isfullscreen && !selmon->sel->fakefullscreen)) 2252 return; 2253 #else 2254 if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen)) 2255 return; 2256 #endif // LOSEFULLSCREEN_PATCH 2257 #if BAR_WINTITLEACTIONS_PATCH 2258 if (arg->i > 0) { 2259 for (c = selmon->sel->next; c && (!ISVISIBLE(c) || (arg->i == 1 && HIDDEN(c))); c = c->next); 2260 if (!c) 2261 for (c = selmon->clients; c && (!ISVISIBLE(c) || (arg->i == 1 && HIDDEN(c))); c = c->next); 2262 } else { 2263 for (i = selmon->clients; i != selmon->sel; i = i->next) 2264 if (ISVISIBLE(i) && !(arg->i == -1 && HIDDEN(i))) 2265 c = i; 2266 if (!c) 2267 for (; i; i = i->next) 2268 if (ISVISIBLE(i) && !(arg->i == -1 && HIDDEN(i))) 2269 c = i; 2270 } 2271 #else 2272 if (arg->i > 0) { 2273 for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); 2274 if (!c) 2275 for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); 2276 } else { 2277 for (i = selmon->clients; i != selmon->sel; i = i->next) 2278 if (ISVISIBLE(i)) 2279 c = i; 2280 if (!c) 2281 for (; i; i = i->next) 2282 if (ISVISIBLE(i)) 2283 c = i; 2284 } 2285 #endif // BAR_WINTITLEACTIONS_PATCH 2286 if (c) { 2287 focus(c); 2288 restack(selmon); 2289 } 2290 } 2291 #endif // STACKER_PATCH 2292 2293 Atom 2294 getatomprop(Client *c, Atom prop, Atom req) 2295 { 2296 int di; 2297 unsigned long nitems, dl; 2298 unsigned char *p = NULL; 2299 Atom da, atom = None; 2300 2301 #if BAR_SYSTRAY_PATCH 2302 if (prop == xatom[XembedInfo]) 2303 req = xatom[XembedInfo]; 2304 #endif // BAR_SYSTRAY_PATCH 2305 2306 /* FIXME getatomprop should return the number of items and a pointer to 2307 * the stored data instead of this workaround */ 2308 if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, 2309 &da, &di, &nitems, &dl, &p) == Success && p) { 2310 if (nitems > 0) 2311 atom = *(Atom *)p; 2312 #if BAR_SYSTRAY_PATCH 2313 if (da == xatom[XembedInfo] && dl == 2) 2314 atom = ((Atom *)p)[1]; 2315 #endif // BAR_SYSTRAY_PATCH 2316 XFree(p); 2317 } 2318 return atom; 2319 } 2320 2321 int 2322 getrootptr(int *x, int *y) 2323 { 2324 int di; 2325 unsigned int dui; 2326 Window dummy; 2327 2328 #if BANISH_PATCH 2329 if (cursor_hidden) { 2330 *x = mouse_x; 2331 *y = mouse_y; 2332 return 1; 2333 } 2334 #endif // BANISH_PATCH 2335 2336 return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui); 2337 } 2338 2339 long 2340 getstate(Window w) 2341 { 2342 int format; 2343 long result = -1; 2344 unsigned char *p = NULL; 2345 unsigned long n, extra; 2346 Atom real; 2347 2348 if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState], 2349 &real, &format, &n, &extra, (unsigned char **)&p) != Success) 2350 return -1; 2351 if (n != 0) 2352 result = *p; 2353 XFree(p); 2354 return result; 2355 } 2356 2357 int 2358 gettextprop(Window w, Atom atom, char *text, unsigned int size) 2359 { 2360 char **list = NULL; 2361 int n; 2362 XTextProperty name; 2363 2364 if (!text || size == 0) 2365 return 0; 2366 text[0] = '\0'; 2367 if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems) 2368 return 0; 2369 if (name.encoding == XA_STRING) { 2370 strncpy(text, (char *)name.value, size - 1); 2371 } else if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) { 2372 strncpy(text, *list, size - 1); 2373 XFreeStringList(list); 2374 } 2375 text[size - 1] = '\0'; 2376 XFree(name.value); 2377 return 1; 2378 } 2379 2380 void 2381 grabbuttons(Client *c, int focused) 2382 { 2383 updatenumlockmask(); 2384 { 2385 unsigned int i, j; 2386 unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; 2387 XUngrabButton(dpy, AnyButton, AnyModifier, c->win); 2388 if (!focused) 2389 XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, 2390 BUTTONMASK, GrabModeSync, GrabModeSync, None, None); 2391 for (i = 0; i < LENGTH(buttons); i++) 2392 if (buttons[i].click == ClkClientWin 2393 #if NO_MOD_BUTTONS_PATCH 2394 && (nomodbuttons || buttons[i].mask != 0) 2395 #endif // NO_MOD_BUTTONS_PATCH 2396 ) 2397 for (j = 0; j < LENGTH(modifiers); j++) 2398 XGrabButton(dpy, buttons[i].button, 2399 buttons[i].mask | modifiers[j], 2400 c->win, False, BUTTONMASK, 2401 GrabModeAsync, GrabModeSync, None, None); 2402 } 2403 } 2404 2405 void 2406 #if KEYMODES_PATCH 2407 grabdefkeys(void) 2408 #else 2409 grabkeys(void) 2410 #endif // KEYMODES_PATCH 2411 { 2412 updatenumlockmask(); 2413 { 2414 unsigned int i, j, k; 2415 unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; 2416 int start, end, skip; 2417 KeySym *syms; 2418 2419 XUngrabKey(dpy, AnyKey, AnyModifier, root); 2420 XDisplayKeycodes(dpy, &start, &end); 2421 syms = XGetKeyboardMapping(dpy, start, end - start + 1, &skip); 2422 if (!syms) 2423 return; 2424 for (k = start; k <= end; k++) 2425 for (i = 0; i < LENGTH(keys); i++) 2426 /* skip modifier codes, we do that ourselves */ 2427 if (keys[i].keysym == syms[(k - start) * skip]) 2428 for (j = 0; j < LENGTH(modifiers); j++) 2429 XGrabKey(dpy, k, 2430 keys[i].mod | modifiers[j], 2431 root, True, 2432 GrabModeAsync, GrabModeAsync); 2433 #if ON_EMPTY_KEYS_PATCH 2434 if (!selmon->sel) 2435 for (k = start; k <= end; k++) 2436 for (i = 0; i < LENGTH(on_empty_keys); i++) 2437 /* skip modifier codes, we do that ourselves */ 2438 if (on_empty_keys[i].keysym == syms[(k - start) * skip]) 2439 for (j = 0; j < LENGTH(modifiers); j++) 2440 XGrabKey(dpy, k, 2441 on_empty_keys[i].mod | modifiers[j], 2442 root, True, 2443 GrabModeAsync, GrabModeAsync); 2444 #endif // ON_EMPTY_KEYS_PATCH 2445 XFree(syms); 2446 } 2447 } 2448 2449 void 2450 incnmaster(const Arg *arg) 2451 { 2452 #if PERTAG_PATCH 2453 selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); 2454 #else 2455 selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); 2456 #endif // PERTAG_PATCH 2457 arrange(selmon); 2458 } 2459 2460 #ifdef XINERAMA 2461 static int 2462 isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) 2463 { 2464 while (n--) 2465 if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org 2466 && unique[n].width == info->width && unique[n].height == info->height) 2467 return 0; 2468 return 1; 2469 } 2470 #endif /* XINERAMA */ 2471 2472 void 2473 #if KEYMODES_PATCH 2474 keydefpress(XEvent *e) 2475 #else 2476 keypress(XEvent *e) 2477 #endif // KEYMODES_PATCH 2478 { 2479 unsigned int i; 2480 int keysyms_return; 2481 KeySym* keysym; 2482 XKeyEvent *ev; 2483 2484 ev = &e->xkey; 2485 keysym = XGetKeyboardMapping(dpy, (KeyCode)ev->keycode, 1, &keysyms_return); 2486 for (i = 0; i < LENGTH(keys); i++) 2487 if (*keysym == keys[i].keysym 2488 && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) 2489 && keys[i].func) 2490 keys[i].func(&(keys[i].arg)); 2491 #if ON_EMPTY_KEYS_PATCH 2492 if (!selmon->sel) 2493 for (i = 0; i < LENGTH(on_empty_keys); i++) 2494 if (*keysym == on_empty_keys[i].keysym 2495 && CLEANMASK(on_empty_keys[i].mod) == CLEANMASK(ev->state) 2496 && on_empty_keys[i].func) 2497 on_empty_keys[i].func(&(on_empty_keys[i].arg)); 2498 #endif // ON_EMPTY_KEYS_PATCH 2499 XFree(keysym); 2500 } 2501 2502 void 2503 killclient(const Arg *arg) 2504 { 2505 #if ISPERMANENT_PATCH 2506 if (!selmon->sel || selmon->sel->ispermanent) 2507 #else 2508 if (!selmon->sel) 2509 #endif // ISPERMANENT_PATCH 2510 return; 2511 #if BAR_SYSTRAY_PATCH 2512 if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0, 0, 0)) 2513 #else 2514 if (!sendevent(selmon->sel, wmatom[WMDelete])) 2515 #endif // BAR_SYSTRAY_PATCH 2516 { 2517 XGrabServer(dpy); 2518 XSetErrorHandler(xerrordummy); 2519 XSetCloseDownMode(dpy, DestroyAll); 2520 XKillClient(dpy, selmon->sel->win); 2521 XSync(dpy, False); 2522 XSetErrorHandler(xerror); 2523 XUngrabServer(dpy); 2524 #if WARP_PATCH 2525 force_warp = 1; 2526 #endif // WARP_PATCH 2527 } 2528 #if SWAPFOCUS_PATCH && PERTAG_PATCH 2529 selmon->pertag->prevclient[selmon->pertag->curtag] = NULL; 2530 #endif // SWAPFOCUS_PATCH 2531 } 2532 2533 void 2534 manage(Window w, XWindowAttributes *wa) 2535 { 2536 Client *c, *t = NULL; 2537 #if SWALLOW_PATCH 2538 Client *term = NULL; 2539 #endif // SWALLOW_PATCH 2540 #if SEAMLESS_RESTART_PATCH 2541 int settings_restored; 2542 #endif // SEAMLESS_RESTART_PATCH 2543 Window trans = None; 2544 XWindowChanges wc; 2545 2546 c = ecalloc(1, sizeof(Client)); 2547 c->win = w; 2548 #if SWALLOW_PATCH 2549 c->pid = winpid(w); 2550 #endif // SWALLOW_PATCH 2551 /* geometry */ 2552 #if SAVEFLOATS_PATCH || EXRESIZE_PATCH 2553 c->sfx = c->sfy = c->sfw = c->sfh = -9999; 2554 #endif // SAVEFLOATS_PATCH | EXRESIZE_PATCH 2555 c->x = c->oldx = wa->x; 2556 c->y = c->oldy = wa->y; 2557 c->w = c->oldw = wa->width; 2558 c->h = c->oldh = wa->height; 2559 c->oldbw = wa->border_width; 2560 #if CFACTS_PATCH 2561 c->cfact = 1.0; 2562 #endif // CFACTS_PATCH 2563 #if SEAMLESS_RESTART_PATCH 2564 settings_restored = restoreclientstate(c); 2565 #endif // SEAMLESS_RESTART_PATCH 2566 #if BAR_WINICON_PATCH 2567 updateicon(c); 2568 #endif // BAR_WINICON_PATCH 2569 updatetitle(c); 2570 2571 #if XKB_PATCH 2572 /* Setting current xkb state must be before applyrules */ 2573 if (!(c->xkb = findxkb(c->win))) 2574 c->xkb = createxkb(c->win); 2575 #endif // XKB_PATCH 2576 2577 if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { 2578 c->mon = t->mon; 2579 c->tags = t->tags; 2580 #if SETBORDERPX_PATCH 2581 c->bw = c->mon->borderpx; 2582 #else 2583 c->bw = borderpx; 2584 #endif // SETBORDERPX_PATCH 2585 #if CENTER_TRANSIENT_WINDOWS_BY_PARENT_PATCH 2586 c->x = t->x + WIDTH(t) / 2 - WIDTH(c) / 2; 2587 c->y = t->y + HEIGHT(t) / 2 - HEIGHT(c) / 2; 2588 #elif CENTER_PATCH && CENTER_TRANSIENT_WINDOWS_PATCH 2589 c->iscentered = 1; 2590 #elif CENTER_TRANSIENT_WINDOWS_PATCH 2591 c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2; 2592 c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2; 2593 #elif CENTER_PATCH 2594 if (c->x == c->mon->wx && c->y == c->mon->wy) 2595 c->iscentered = 1; 2596 #endif // CENTER_TRANSIENT_WINDOWS_PATCH | CENTER_TRANSIENT_WINDOWS_BY_PARENT_PATCH | CENTER_PATCH 2597 } else { 2598 #if SEAMLESS_RESTART_PATCH 2599 if (!settings_restored || c->mon == NULL) { 2600 c->mon = selmon; 2601 settings_restored = 0; 2602 } 2603 #else 2604 c->mon = selmon; 2605 #endif // SEAMLESS_RESTART_PATCH 2606 #if CENTER_PATCH 2607 if (c->x == c->mon->wx && c->y == c->mon->wy) 2608 c->iscentered = 1; 2609 #endif // CENTER_PATCH 2610 #if SETBORDERPX_PATCH 2611 c->bw = c->mon->borderpx; 2612 #else 2613 c->bw = borderpx; 2614 #endif // SETBORDERPX_PATCH 2615 #if SEAMLESS_RESTART_PATCH 2616 if (!settings_restored) 2617 applyrules(c); 2618 #else 2619 applyrules(c); 2620 #endif // SEAMLESS_RESTART_PATCH 2621 #if SWALLOW_PATCH 2622 term = termforwin(c); 2623 if (term) 2624 c->mon = term->mon; 2625 #endif // SWALLOW_PATCH 2626 } 2627 2628 #if UNMANAGED_PATCH 2629 if (unmanaged) { 2630 XMapWindow(dpy, c->win); 2631 if (unmanaged == 1) 2632 XRaiseWindow(dpy, c->win); 2633 else if (unmanaged == 2) 2634 XLowerWindow(dpy, c->win); 2635 2636 updatewmhints(c); 2637 if (!c->neverfocus) 2638 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); 2639 #if BAR_SYSTRAY_PATCH 2640 sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); 2641 #else 2642 sendevent(c, wmatom[WMTakeFocus]); 2643 #endif // BAR_SYSTRAY_PATCH 2644 2645 free(c); 2646 unmanaged = 0; 2647 return; 2648 } 2649 #endif // UNMANAGED_PATCH 2650 2651 if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww) 2652 c->x = c->mon->wx + c->mon->ww - WIDTH(c); 2653 if (c->y + HEIGHT(c) > c->mon->wy + c->mon->wh) 2654 c->y = c->mon->wy + c->mon->wh - HEIGHT(c); 2655 c->x = MAX(c->x, c->mon->wx); 2656 c->y = MAX(c->y, c->mon->wy); 2657 2658 wc.border_width = c->bw; 2659 XConfigureWindow(dpy, w, CWBorderWidth, &wc); 2660 #if !BAR_FLEXWINTITLE_PATCH 2661 if (c->isfloating) 2662 XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel); 2663 else 2664 XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel); 2665 #endif // BAR_FLEXWINTITLE_PATCH 2666 configure(c); /* propagates border_width, if size doesn't change */ 2667 updatesizehints(c); 2668 updatewmhints(c); 2669 #if DECORATION_HINTS_PATCH 2670 updatemotifhints(c); 2671 #endif // DECORATION_HINTS_PATCH 2672 2673 #if CENTER_PATCH && SAVEFLOATS_PATCH || CENTER_PATCH && EXRESIZE_PATCH 2674 if (c->iscentered) { 2675 c->sfx = c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2; 2676 c->sfy = c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2; 2677 } 2678 #elif CENTER_PATCH 2679 if (c->iscentered) { 2680 c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2; 2681 c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2; 2682 } 2683 #elif ALWAYSCENTER_PATCH && SAVEFLOATS_PATCH || ALWAYSCENTER_PATCH && EXRESIZE_PATCH 2684 c->sfx = c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2; 2685 c->sfy = c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2; 2686 #elif ALWAYSCENTER_PATCH 2687 c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2; 2688 c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2; 2689 #endif // CENTER_PATCH / ALWAYSCENTER_PATCH / SAVEFLOATS_PATCH 2690 #if SAVEFLOATS_PATCH || EXRESIZE_PATCH 2691 if (c->sfw == -9999) { 2692 c->sfw = c->w; 2693 c->sfh = c->h; 2694 } 2695 #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH 2696 2697 if (getatomprop(c, netatom[NetWMState], XA_ATOM) == netatom[NetWMFullscreen]) 2698 setfullscreen(c, 1); 2699 2700 XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); 2701 grabbuttons(c, 0); 2702 #if MAXIMIZE_PATCH 2703 c->wasfloating = 0; 2704 c->ismax = 0; 2705 #elif EXRESIZE_PATCH 2706 c->wasfloating = 0; 2707 #endif // MAXIMIZE_PATCH / EXRESIZE_PATCH 2708 2709 if (!c->isfloating) 2710 c->isfloating = c->oldstate = trans != None || c->isfixed; 2711 if (c->isfloating) { 2712 XRaiseWindow(dpy, c->win); 2713 XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel); 2714 } 2715 #if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH || SEAMLESS_RESTART_PATCH 2716 attachx(c); 2717 #else 2718 attach(c); 2719 #endif 2720 attachstack(c); 2721 XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, 2722 (unsigned char *) &(c->win), 1); 2723 #if NET_CLIENT_LIST_STACKING_PATCH 2724 XChangeProperty(dpy, root, netatom[NetClientListStacking], XA_WINDOW, 32, PropModePrepend, 2725 (unsigned char *) &(c->win), 1); 2726 #endif // NET_CLIENT_LIST_STACKING_PATCH 2727 XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ 2728 2729 #if BAR_WINTITLEACTIONS_PATCH 2730 if (!HIDDEN(c)) 2731 setclientstate(c, NormalState); 2732 #else 2733 setclientstate(c, NormalState); 2734 #endif // BAR_WINTITLEACTIONS_PATCH 2735 if (c->mon == selmon) 2736 unfocus(selmon->sel, 0, c); 2737 c->mon->sel = c; 2738 #if SWALLOW_PATCH 2739 if (!(term && swallow(term, c))) { 2740 #if RIODRAW_PATCH 2741 if (riopid && (!riodraw_matchpid || isdescprocess(riopid, c->pid))) { 2742 if (riodimensions[3] != -1) 2743 rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]); 2744 else { 2745 killclient(&((Arg) { .v = c })); 2746 return; 2747 } 2748 } 2749 #endif // RIODRAW_PATCH 2750 arrange(c->mon); 2751 #if BAR_WINTITLEACTIONS_PATCH 2752 if (!HIDDEN(c)) 2753 XMapWindow(dpy, c->win); 2754 #else 2755 XMapWindow(dpy, c->win); 2756 #endif // BAR_WINTITLEACTIONS_PATCH 2757 } 2758 #else 2759 #if RIODRAW_PATCH 2760 if (riopid) { 2761 if (riodimensions[3] != -1) 2762 rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]); 2763 else { 2764 killclient(&((Arg) { .v = c })); 2765 return; 2766 } 2767 } 2768 #endif // RIODRAW_PATCH 2769 arrange(c->mon); 2770 #if BAR_WINTITLEACTIONS_PATCH 2771 if (!HIDDEN(c)) 2772 XMapWindow(dpy, c->win); 2773 #else 2774 XMapWindow(dpy, c->win); 2775 #endif // BAR_WINTITLEACTIONS_PATCH 2776 #endif // SWALLOW_PATCH 2777 focus(NULL); 2778 2779 #if BAR_EWMHTAGS_PATCH 2780 setfloatinghint(c); 2781 #endif // BAR_EWMHTAGS_PATCH 2782 } 2783 2784 void 2785 mappingnotify(XEvent *e) 2786 { 2787 XMappingEvent *ev = &e->xmapping; 2788 2789 XRefreshKeyboardMapping(ev); 2790 if (ev->request == MappingKeyboard) 2791 grabkeys(); 2792 } 2793 2794 void 2795 maprequest(XEvent *e) 2796 { 2797 static XWindowAttributes wa; 2798 XMapRequestEvent *ev = &e->xmaprequest; 2799 2800 #if BAR_SYSTRAY_PATCH 2801 Client *i; 2802 if (showsystray && systray && (i = wintosystrayicon(ev->window))) { 2803 sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); 2804 drawbarwin(systray->bar); 2805 } 2806 #endif // BAR_SYSTRAY_PATCH 2807 2808 if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect) 2809 return; 2810 #if BAR_ANYBAR_PATCH 2811 if (wmclasscontains(ev->window, altbarclass, "")) 2812 managealtbar(ev->window, &wa); 2813 else 2814 #endif // BAR_ANYBAR_PATCH 2815 if (!wintoclient(ev->window)) 2816 manage(ev->window, &wa); 2817 } 2818 2819 void 2820 motionnotify(XEvent *e) 2821 { 2822 #if !FOCUSONCLICK_PATCH 2823 static Monitor *mon = NULL; 2824 Monitor *m; 2825 #if LOSEFULLSCREEN_PATCH 2826 Client *sel; 2827 #endif // LOSEFULLSCREEN_PATCH 2828 #endif // FOCUSONCLICK_PATCH 2829 Bar *bar; 2830 XMotionEvent *ev = &e->xmotion; 2831 2832 if ((bar = wintobar(ev->window))) { 2833 barhover(e, bar); 2834 return; 2835 } 2836 2837 #if BAR_TAGPREVIEW_PATCH 2838 if (selmon->previewshow != 0) 2839 hidetagpreview(selmon); 2840 #endif // BAR_TAGPREVIEW_PATCH 2841 2842 #if !FOCUSONCLICK_PATCH 2843 if (ev->window != root) 2844 return; 2845 if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { 2846 #if LOSEFULLSCREEN_PATCH 2847 sel = selmon->sel; 2848 selmon = m; 2849 unfocus(sel, 1, NULL); 2850 #else 2851 unfocus(selmon->sel, 1, NULL); 2852 selmon = m; 2853 #endif // LOSEFULLSCREEN_PATCH 2854 focus(NULL); 2855 } 2856 mon = m; 2857 #endif // FOCUSONCLICK_PATCH 2858 } 2859 2860 void 2861 movemouse(const Arg *arg) 2862 { 2863 int x, y, ocx, ocy, nx, ny; 2864 Client *c; 2865 Monitor *m; 2866 XEvent ev; 2867 Time lasttime = 0; 2868 2869 if (!(c = selmon->sel)) 2870 return; 2871 #if !FAKEFULLSCREEN_PATCH 2872 #if FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH 2873 if (c->isfullscreen && c->fakefullscreen != 1) /* no support moving fullscreen windows by mouse */ 2874 return; 2875 #else 2876 if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ 2877 return; 2878 #endif // FAKEFULLSCREEN_CLIENT_PATCH 2879 #endif // FAKEFULLSCREEN_PATCH 2880 restack(selmon); 2881 nx = ocx = c->x; 2882 ny = ocy = c->y; 2883 if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, 2884 None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) 2885 return; 2886 if (!getrootptr(&x, &y)) 2887 return; 2888 ignoreconfigurerequests = 1; 2889 do { 2890 XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); 2891 switch(ev.type) { 2892 case ConfigureRequest: 2893 case Expose: 2894 case MapRequest: 2895 handler[ev.type](&ev); 2896 break; 2897 case MotionNotify: 2898 if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate)) 2899 continue; 2900 lasttime = ev.xmotion.time; 2901 2902 nx = ocx + (ev.xmotion.x - x); 2903 ny = ocy + (ev.xmotion.y - y); 2904 if (abs(selmon->wx - nx) < snap) 2905 nx = selmon->wx; 2906 else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) 2907 nx = selmon->wx + selmon->ww - WIDTH(c); 2908 if (abs(selmon->wy - ny) < snap) 2909 ny = selmon->wy; 2910 else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap) 2911 ny = selmon->wy + selmon->wh - HEIGHT(c); 2912 if (!c->isfloating && selmon->lt[selmon->sellt]->arrange 2913 && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) { 2914 #if SAVEFLOATS_PATCH || EXRESIZE_PATCH 2915 c->sfx = -9999; // disable savefloats when using movemouse 2916 #endif // SAVEFLOATS_PATCH | EXRESIZE_PATCH 2917 togglefloating(NULL); 2918 } 2919 if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) { 2920 resize(c, nx, ny, c->w, c->h, 1); 2921 } 2922 break; 2923 } 2924 } while (ev.type != ButtonRelease); 2925 2926 XUngrabPointer(dpy, CurrentTime); 2927 if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { 2928 #if SCRATCHPADS_PATCH && !RENAMED_SCRATCHPADS_PATCH 2929 if (c->tags & SPTAGMASK) { 2930 c->mon->tagset[c->mon->seltags] ^= (c->tags & SPTAGMASK); 2931 m->tagset[m->seltags] |= (c->tags & SPTAGMASK); 2932 } 2933 #endif // SCRATCHPADS_PATCH 2934 sendmon(c, m); 2935 selmon = m; 2936 focus(NULL); 2937 } 2938 #if SAVEFLOATS_PATCH || EXRESIZE_PATCH 2939 /* save last known float coordinates */ 2940 if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) { 2941 c->sfx = nx; 2942 c->sfy = ny; 2943 } 2944 #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH 2945 ignoreconfigurerequests = 0; 2946 } 2947 2948 Client * 2949 nexttiled(Client *c) 2950 { 2951 #if BAR_WINTITLEACTIONS_PATCH 2952 for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next); 2953 #else 2954 for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); 2955 #endif // BAR_WINTITLEACTIONS_PATCH 2956 return c; 2957 } 2958 2959 #if NOBORDER_PATCH 2960 int 2961 noborder(Client *c) 2962 { 2963 int monocle_layout = 0; 2964 2965 #if MONOCLE_LAYOUT 2966 if (&monocle == c->mon->lt[c->mon->sellt]->arrange) 2967 monocle_layout = 1; 2968 #endif // MONOCLE_LAYOUT 2969 2970 #if DECK_LAYOUT 2971 if (&deck == c->mon->lt[c->mon->sellt]->arrange && c->mon->nmaster == 0) 2972 monocle_layout = 1; 2973 #endif // DECK_LAYOUT 2974 2975 #if FLEXTILE_DELUXE_LAYOUT 2976 if (&flextile == c->mon->lt[c->mon->sellt]->arrange && ( 2977 (c->mon->ltaxis[LAYOUT] == NO_SPLIT && c->mon->ltaxis[MASTER] == MONOCLE) || 2978 (c->mon->ltaxis[STACK] == MONOCLE && c->mon->nmaster == 0) 2979 )) { 2980 monocle_layout = 1; 2981 } 2982 #endif //FLEXTILE_DELUXE_LAYOUT 2983 2984 if (!monocle_layout && (nexttiled(c->mon->clients) != c || nexttiled(c->next))) 2985 return 0; 2986 2987 if (c->isfloating) 2988 return 0; 2989 2990 if (!c->mon->lt[c->mon->sellt]->arrange) 2991 return 0; 2992 2993 #if FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH 2994 if (c->fakefullscreen != 1 && c->isfullscreen) 2995 return 0; 2996 #elif !FAKEFULLSCREEN_PATCH 2997 if (c->isfullscreen) 2998 return 0; 2999 #endif // FAKEFULLSCREEN_CLIENT_PATCH 3000 3001 return 1; 3002 } 3003 #endif // NOBORDER_PATCH 3004 3005 #if !ZOOMSWAP_PATCH || TAGINTOSTACK_ALLMASTER_PATCH || TAGINTOSTACK_ONEMASTER_PATCH 3006 void 3007 pop(Client *c) 3008 { 3009 #if FOCUSMASTER_RETURN_PATCH 3010 int i; 3011 for (i = 0; !(selmon->tagset[selmon->seltags] & 1 << i); i++); 3012 i++; 3013 3014 c->mon->tagmarked[i] = nexttiled(c->mon->clients); 3015 #endif // FOCUSMASTER_RETURN_PATCH 3016 detach(c); 3017 attach(c); 3018 focus(c); 3019 arrange(c->mon); 3020 } 3021 #endif // !ZOOMSWAP_PATCH / TAGINTOSTACK_ALLMASTER_PATCH / TAGINTOSTACK_ONEMASTER_PATCH 3022 3023 void 3024 propertynotify(XEvent *e) 3025 { 3026 Client *c; 3027 Window trans; 3028 XPropertyEvent *ev = &e->xproperty; 3029 3030 #if BAR_SYSTRAY_PATCH 3031 if (showsystray && (c = wintosystrayicon(ev->window))) { 3032 if (ev->atom == XA_WM_NORMAL_HINTS) { 3033 updatesizehints(c); 3034 updatesystrayicongeom(c, c->w, c->h); 3035 } 3036 else 3037 updatesystrayiconstate(c, ev); 3038 drawbarwin(systray->bar); 3039 } 3040 #endif // BAR_SYSTRAY_PATCH 3041 3042 if ((ev->window == root) && (ev->atom == XA_WM_NAME)) { 3043 #if DWMC_PATCH || FSIGNAL_PATCH 3044 if (!fake_signal()) 3045 updatestatus(); 3046 #else 3047 updatestatus(); 3048 #endif // DWMC_PATCH / FSIGNAL_PATCH 3049 } else if (ev->state == PropertyDelete) { 3050 return; /* ignore */ 3051 } else if ((c = wintoclient(ev->window))) { 3052 switch(ev->atom) { 3053 default: break; 3054 case XA_WM_TRANSIENT_FOR: 3055 if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) && 3056 (c->isfloating = (wintoclient(trans)) != NULL)) 3057 arrange(c->mon); 3058 break; 3059 case XA_WM_NORMAL_HINTS: 3060 c->hintsvalid = 0; 3061 break; 3062 case XA_WM_HINTS: 3063 updatewmhints(c); 3064 if (c->isurgent) 3065 drawbars(); 3066 #if TAB_PATCH 3067 drawtabs(); 3068 #endif // TAB_PATCH 3069 break; 3070 } 3071 if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { 3072 updatetitle(c); 3073 if (c == c->mon->sel) 3074 drawbar(c->mon); 3075 #if TAB_PATCH 3076 drawtab(c->mon); 3077 #endif // TAB_PATCH 3078 } 3079 #if DECORATION_HINTS_PATCH 3080 if (ev->atom == motifatom) 3081 updatemotifhints(c); 3082 #endif // DECORATION_HINTS_PATCH 3083 #if BAR_WINICON_PATCH 3084 else if (ev->atom == netatom[NetWMIcon]) { 3085 updateicon(c); 3086 if (c == c->mon->sel) 3087 drawbar(c->mon); 3088 } 3089 #endif // BAR_WINICON_PATCH 3090 } 3091 } 3092 3093 void 3094 quit(const Arg *arg) 3095 { 3096 #if RESTARTSIG_PATCH 3097 restart = arg->i; 3098 #endif // RESTARTSIG_PATCH 3099 #if ONLYQUITONEMPTY_PATCH 3100 Monitor *m; 3101 Client *c; 3102 unsigned int n = 0; 3103 3104 for (m = mons; m; m = m->next) 3105 for (c = m->clients; c; c = c->next, n++); 3106 3107 #if RESTARTSIG_PATCH 3108 if (restart || n <= quit_empty_window_count) 3109 #else 3110 if (n <= quit_empty_window_count) 3111 #endif // RESTARTSIG_PATCH 3112 running = 0; 3113 else 3114 fprintf(stderr, "[dwm] not exiting (n=%d)\n", n); 3115 3116 #else // !ONLYQUITONEMPTY_PATCH 3117 running = 0; 3118 #endif // ONLYQUITONEMPTY_PATCH 3119 } 3120 3121 Monitor * 3122 recttomon(int x, int y, int w, int h) 3123 { 3124 Monitor *m, *r = selmon; 3125 int a, area = 0; 3126 3127 for (m = mons; m; m = m->next) 3128 if ((a = INTERSECT(x, y, w, h, m)) > area) { 3129 area = a; 3130 r = m; 3131 } 3132 return r; 3133 } 3134 3135 void 3136 resize(Client *c, int x, int y, int w, int h, int interact) 3137 { 3138 if (applysizehints(c, &x, &y, &w, &h, interact)) 3139 resizeclient(c, x, y, w, h); 3140 } 3141 3142 void 3143 resizeclient(Client *c, int x, int y, int w, int h) 3144 { 3145 XWindowChanges wc; 3146 3147 c->oldx = c->x; c->x = wc.x = x; 3148 c->oldy = c->y; c->y = wc.y = y; 3149 c->oldw = c->w; c->w = wc.width = w; 3150 c->oldh = c->h; c->h = wc.height = h; 3151 #if EXRESIZE_PATCH 3152 c->expandmask = 0; 3153 #endif // EXRESIZE_PATCH 3154 wc.border_width = c->bw; 3155 #if ROUNDED_CORNERS_PATCH 3156 drawroundedcorners(c); 3157 #endif // ROUNDED_CORNERS_PATCH 3158 #if NOBORDER_PATCH 3159 if (noborder(c)) { 3160 wc.width += c->bw * 2; 3161 wc.height += c->bw * 2; 3162 wc.border_width = 0; 3163 } 3164 #endif // NOBORDER_PATCH 3165 XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); 3166 configure(c); 3167 XSync(dpy, False); 3168 } 3169 3170 void 3171 resizemouse(const Arg *arg) 3172 { 3173 int ocx, ocy, nw, nh, nx, ny; 3174 #if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH 3175 int opx, opy, och, ocw; 3176 int horizcorner, vertcorner; 3177 unsigned int dui; 3178 Window dummy; 3179 #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH 3180 Client *c; 3181 Monitor *m; 3182 XEvent ev; 3183 Time lasttime = 0; 3184 3185 if (!(c = selmon->sel)) 3186 return; 3187 #if !FAKEFULLSCREEN_PATCH 3188 #if FAKEFULLSCREEN_CLIENT_PATCH 3189 if (c->isfullscreen && c->fakefullscreen != 1) /* no support resizing fullscreen windows by mouse */ 3190 return; 3191 #else 3192 if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ 3193 return; 3194 #endif // FAKEFULLSCREEN_CLIENT_PATCH 3195 #endif // !FAKEFULLSCREEN_PATCH 3196 restack(selmon); 3197 nx = ocx = c->x; 3198 ny = ocy = c->y; 3199 nh = c->h; 3200 nw = c->w; 3201 #if RESIZEPOINT_PATCH 3202 och = c->h; 3203 ocw = c->w; 3204 #elif RESIZECORNERS_PATCH 3205 och = c->y + c->h; 3206 ocw = c->x + c->w; 3207 #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH 3208 #if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH 3209 if (!XQueryPointer(dpy, c->win, &dummy, &dummy, &opx, &opy, &nx, &ny, &dui)) 3210 return; 3211 horizcorner = nx < c->w / 2; 3212 vertcorner = ny < c->h / 2; 3213 if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, 3214 None, cursor[horizcorner | (vertcorner << 1)]->cursor, CurrentTime) != GrabSuccess) 3215 return; 3216 #if RESIZECORNERS_PATCH 3217 XWarpPointer (dpy, None, c->win, 0, 0, 0, 0, 3218 horizcorner ? (-c->bw) : (c->w + c->bw - 1), 3219 vertcorner ? (-c->bw) : (c->h + c->bw - 1)); 3220 #endif // RESIZECORNERS_PATCH 3221 #else 3222 if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, 3223 None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) 3224 return; 3225 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); 3226 #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH 3227 ignoreconfigurerequests = 1; 3228 do { 3229 XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); 3230 switch(ev.type) { 3231 case ConfigureRequest: 3232 case Expose: 3233 case MapRequest: 3234 handler[ev.type](&ev); 3235 break; 3236 case MotionNotify: 3237 if ((ev.xmotion.time - lasttime) <= (1000 / refreshrate)) 3238 continue; 3239 lasttime = ev.xmotion.time; 3240 3241 #if RESIZEPOINT_PATCH 3242 nx = horizcorner ? (ocx + ev.xmotion.x - opx) : c->x; 3243 ny = vertcorner ? (ocy + ev.xmotion.y - opy) : c->y; 3244 nw = MAX(horizcorner ? (ocx + ocw - nx) : (ocw + (ev.xmotion.x - opx)), 1); 3245 nh = MAX(vertcorner ? (ocy + och - ny) : (och + (ev.xmotion.y - opy)), 1); 3246 #elif RESIZECORNERS_PATCH 3247 nx = horizcorner ? ev.xmotion.x : c->x; 3248 ny = vertcorner ? ev.xmotion.y : c->y; 3249 nw = MAX(horizcorner ? (ocw - nx) : (ev.xmotion.x - ocx - 2 * c->bw + 1), 1); 3250 nh = MAX(vertcorner ? (och - ny) : (ev.xmotion.y - ocy - 2 * c->bw + 1), 1); 3251 #else 3252 nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); 3253 nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); 3254 #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH 3255 if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww 3256 && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) 3257 { 3258 if (!c->isfloating && selmon->lt[selmon->sellt]->arrange 3259 && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) { 3260 #if SAVEFLOATS_PATCH || EXRESIZE_PATCH 3261 c->sfx = -9999; // disable savefloats when using resizemouse 3262 #endif // SAVEFLOATS_PATCH | EXRESIZE_PATCH 3263 togglefloating(NULL); 3264 } 3265 } 3266 if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) { 3267 resize(c, nx, ny, nw, nh, 1); 3268 } 3269 break; 3270 } 3271 } while (ev.type != ButtonRelease); 3272 3273 #if !RESIZEPOINT_PATCH 3274 #if RESIZECORNERS_PATCH 3275 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, 3276 horizcorner ? (-c->bw) : (c->w + c->bw - 1), 3277 vertcorner ? (-c->bw) : (c->h + c->bw - 1)); 3278 #else 3279 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); 3280 #endif // RESIZECORNERS_PATCH 3281 #endif // RESIZEPOINT_PATCH 3282 XUngrabPointer(dpy, CurrentTime); 3283 while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); 3284 if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { 3285 #if SCRATCHPADS_PATCH && !RENAMED_SCRATCHPADS_PATCH 3286 if (c->tags & SPTAGMASK) { 3287 c->mon->tagset[c->mon->seltags] ^= (c->tags & SPTAGMASK); 3288 m->tagset[m->seltags] |= (c->tags & SPTAGMASK); 3289 } 3290 #endif // SCRATCHPADS_PATCH 3291 sendmon(c, m); 3292 selmon = m; 3293 focus(NULL); 3294 } 3295 #if SAVEFLOATS_PATCH || EXRESIZE_PATCH 3296 /* save last known float dimensions */ 3297 if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) { 3298 c->sfx = nx; 3299 c->sfy = ny; 3300 c->sfw = nw; 3301 c->sfh = nh; 3302 } 3303 #endif // SAVEFLOATS_PATCH | EXRESIZE_PATCH 3304 ignoreconfigurerequests = 0; 3305 } 3306 3307 void 3308 restack(Monitor *m) 3309 { 3310 Client *c, *f = NULL; 3311 XEvent ev; 3312 XWindowChanges wc; 3313 #if WARP_PATCH && FLEXTILE_DELUXE_LAYOUT 3314 int n; 3315 #endif // WARP_PATCH 3316 #if ALWAYSONTOP_PATCH 3317 Monitor *mon; 3318 #endif // ALWAYSONTOP_PATCH 3319 3320 drawbar(m); 3321 #if TAB_PATCH 3322 drawtab(m); 3323 #endif // TAB_PATCH 3324 if (!m->sel) 3325 return; 3326 if (m->sel->isfloating || !m->lt[m->sellt]->arrange) 3327 XRaiseWindow(dpy, m->sel->win); 3328 3329 #if ALWAYSONTOP_PATCH 3330 /* raise the aot windows */ 3331 for (mon = mons; mon; mon = mon->next) { 3332 for (c = mon->clients; c; c = c->next) { 3333 if (c->alwaysontop) { 3334 XRaiseWindow(dpy, c->win); 3335 } 3336 } 3337 } 3338 #endif // ALWAYSONTOP_PATCH 3339 3340 if (m->lt[m->sellt]->arrange) { 3341 wc.stack_mode = Below; 3342 if (m->bar) { 3343 wc.sibling = m->bar->win; 3344 } else { 3345 for (f = m->stack; f && (f->isfloating || !ISVISIBLE(f)); f = f->snext); // find first tiled stack client 3346 if (f) 3347 wc.sibling = f->win; 3348 } 3349 for (c = m->stack; c; c = c->snext) 3350 if (!c->isfloating && ISVISIBLE(c) && c != f) { 3351 XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); 3352 wc.sibling = c->win; 3353 } 3354 } 3355 XSync(dpy, False); 3356 while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); 3357 #if WARP_PATCH && FLEXTILE_DELUXE_LAYOUT || WARP_PATCH && MONOCLE_LAYOUT 3358 #if FLEXTILE_DELUXE_LAYOUT 3359 for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); 3360 #endif // FLEXTILE_DELUXE_LAYOUT 3361 if (m == selmon && (m->tagset[m->seltags] & m->sel->tags) && ( 3362 #if MONOCLE_LAYOUT && FLEXTILE_DELUXE_LAYOUT 3363 (m->lt[m->sellt]->arrange != &monocle 3364 && !(m->ltaxis[MASTER] == MONOCLE && (abs(m->ltaxis[LAYOUT] == NO_SPLIT || !m->nmaster || n <= m->nmaster)))) 3365 #elif MONOCLE_LAYOUT 3366 m->lt[m->sellt]->arrange != &monocle 3367 #else 3368 !(m->ltaxis[MASTER] == MONOCLE && (abs(m->ltaxis[LAYOUT] == NO_SPLIT || !m->nmaster || n <= m->nmaster))) 3369 #endif // FLEXTILE_DELUXE_LAYOUT 3370 || m->sel->isfloating) 3371 ) 3372 warp(m->sel); 3373 #endif // WARP_PATCH 3374 } 3375 3376 #if IPC_PATCH 3377 void 3378 run(void) 3379 { 3380 int event_count = 0; 3381 const int MAX_EVENTS = 10; 3382 struct epoll_event events[MAX_EVENTS]; 3383 3384 XSync(dpy, False); 3385 3386 /* main event loop */ 3387 while (running) { 3388 event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); 3389 3390 for (int i = 0; i < event_count; i++) { 3391 int event_fd = events[i].data.fd; 3392 DEBUG("Got event from fd %d\n", event_fd); 3393 3394 if (event_fd == dpy_fd) { 3395 // -1 means EPOLLHUP 3396 if (handlexevent(events + i) == -1) 3397 return; 3398 } else if (event_fd == ipc_get_sock_fd()) { 3399 ipc_handle_socket_epoll_event(events + i); 3400 } else if (ipc_is_client_registered(event_fd)) { 3401 if (ipc_handle_client_epoll_event(events + i, mons, &lastselmon, selmon, 3402 NUMTAGS, layouts, LENGTH(layouts)) < 0) { 3403 fprintf(stderr, "Error handling IPC event on fd %d\n", event_fd); 3404 } 3405 } else { 3406 fprintf(stderr, "Got event from unknown fd %d, ptr %p, u32 %d, u64 %lu", 3407 event_fd, events[i].data.ptr, events[i].data.u32, 3408 events[i].data.u64); 3409 fprintf(stderr, " with events %d\n", events[i].events); 3410 } 3411 } 3412 } 3413 } 3414 #elif RESTARTSIG_PATCH 3415 void 3416 run(void) 3417 { 3418 XEvent ev; 3419 XSync(dpy, False); 3420 /* main event loop */ 3421 while (running) { 3422 struct pollfd pfd = { 3423 .fd = ConnectionNumber(dpy), 3424 .events = POLLIN, 3425 }; 3426 int pending = XPending(dpy) > 0 || poll(&pfd, 1, -1) > 0; 3427 3428 if (!running) 3429 break; 3430 if (!pending) 3431 continue; 3432 3433 XNextEvent(dpy, &ev); 3434 if (handler[ev.type]) 3435 handler[ev.type](&ev); /* call handler */ 3436 } 3437 } 3438 #else 3439 void 3440 run(void) 3441 { 3442 XEvent ev; 3443 /* main event loop */ 3444 XSync(dpy, False); 3445 while (running && !XNextEvent(dpy, &ev)) { 3446 3447 #if XKB_PATCH 3448 /* Unfortunately the xkbEventType is not constant hence it can't be part of the 3449 * normal event handler below */ 3450 if (ev.type == xkbEventType) { 3451 xkbeventnotify(&ev); 3452 continue; 3453 } 3454 #endif // XKB_PATCH 3455 3456 if (handler[ev.type]) 3457 handler[ev.type](&ev); /* call handler */ 3458 } 3459 } 3460 #endif // IPC_PATCH | RESTARTSIG_PATCH 3461 3462 void 3463 scan(void) 3464 { 3465 #if SWALLOW_PATCH 3466 scanner = 1; 3467 char swin[256]; 3468 #endif // SWALLOW_PATCH 3469 unsigned int i, num; 3470 Window d1, d2, *wins = NULL; 3471 XWindowAttributes wa; 3472 3473 if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { 3474 for (i = 0; i < num; i++) { 3475 if (!XGetWindowAttributes(dpy, wins[i], &wa) 3476 || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) 3477 continue; 3478 #if BAR_ANYBAR_PATCH 3479 if (wmclasscontains(wins[i], altbarclass, "")) 3480 managealtbar(wins[i], &wa); 3481 else 3482 #endif // BAR_ANYBAR_PATCH 3483 if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) 3484 manage(wins[i], &wa); 3485 #if SWALLOW_PATCH 3486 else if (gettextprop(wins[i], netatom[NetClientList], swin, sizeof swin)) 3487 manage(wins[i], &wa); 3488 #endif // SWALLOW_PATCH 3489 } 3490 for (i = 0; i < num; i++) { /* now the transients */ 3491 if (!XGetWindowAttributes(dpy, wins[i], &wa)) 3492 continue; 3493 if (XGetTransientForHint(dpy, wins[i], &d1) 3494 && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)) 3495 manage(wins[i], &wa); 3496 } 3497 XFree(wins); 3498 } 3499 #if SWALLOW_PATCH 3500 scanner = 0; 3501 #endif // SWALLOW_PATCH 3502 } 3503 3504 void 3505 sendmon(Client *c, Monitor *m) 3506 { 3507 #if EXRESIZE_PATCH 3508 Monitor *oldm = selmon; 3509 #endif // EXRESIZE_PATCH 3510 if (c->mon == m) 3511 return; 3512 #if SENDMON_KEEPFOCUS_PATCH && !EXRESIZE_PATCH 3513 int hadfocus = (c == selmon->sel); 3514 #endif // SENDMON_KEEPFOCUS_PATCH 3515 unfocus(c, 1, NULL); 3516 detach(c); 3517 detachstack(c); 3518 #if SENDMON_KEEPFOCUS_PATCH && !EXRESIZE_PATCH 3519 arrange(c->mon); 3520 #endif // SENDMON_KEEPFOCUS_PATCH 3521 c->mon = m; 3522 #if SCRATCHPADS_PATCH && !RENAMED_SCRATCHPADS_PATCH 3523 if (!(c->tags & SPTAGMASK)) 3524 #endif // SCRATCHPADS_PATCH 3525 #if EMPTYVIEW_PATCH 3526 c->tags = (m->tagset[m->seltags] ? m->tagset[m->seltags] : 1); 3527 #else 3528 c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ 3529 #endif // EMPTYVIEW_PATCH 3530 #if SENDMON_CENTER_PATCH 3531 c->x = m->mx + (m->mw - WIDTH(c)) / 2; 3532 c->y = m->my + (m->mh - HEIGHT(c)) / 2; 3533 #if SAVEFLOATS_PATCH 3534 c->sfx = m->mx + (m->mw - c->sfw - 2 * c->bw) / 2; 3535 c->sfy = m->my + (m->mh - c->sfh - 2 * c->bw) / 2; 3536 #endif // SAVEFLOATS_PATCH 3537 #endif // SENDMON_CENTER_PATCH 3538 #if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH 3539 attachx(c); 3540 #else 3541 attach(c); 3542 #endif 3543 attachstack(c); 3544 #if EXRESIZE_PATCH 3545 if (oldm != m) 3546 arrange(oldm); 3547 arrange(m); 3548 focus(c); 3549 restack(m); 3550 #elif SENDMON_KEEPFOCUS_PATCH 3551 arrange(m); 3552 if (hadfocus) { 3553 focus(c); 3554 restack(m); 3555 } else { 3556 focus(NULL); 3557 } 3558 #else 3559 arrange(NULL); 3560 focus(NULL); 3561 #endif // EXRESIZE_PATCH / SENDMON_KEEPFOCUS_PATCH 3562 #if SWITCHTAG_PATCH 3563 if (c->switchtag) 3564 c->switchtag = 0; 3565 #endif // SWITCHTAG_PATCH 3566 } 3567 3568 void 3569 setclientstate(Client *c, long state) 3570 { 3571 long data[] = { state, None }; 3572 3573 XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, 3574 PropModeReplace, (unsigned char *)data, 2); 3575 } 3576 3577 int 3578 #if BAR_SYSTRAY_PATCH 3579 sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) 3580 #else 3581 sendevent(Client *c, Atom proto) 3582 #endif // BAR_SYSTRAY_PATCH 3583 { 3584 int n; 3585 Atom *protocols; 3586 #if BAR_SYSTRAY_PATCH 3587 Atom mt; 3588 #endif // BAR_SYSTRAY_PATCH 3589 int exists = 0; 3590 XEvent ev; 3591 3592 #if BAR_SYSTRAY_PATCH 3593 if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { 3594 mt = wmatom[WMProtocols]; 3595 if (XGetWMProtocols(dpy, w, &protocols, &n)) { 3596 while (!exists && n--) 3597 exists = protocols[n] == proto; 3598 XFree(protocols); 3599 } 3600 } else { 3601 exists = True; 3602 mt = proto; 3603 } 3604 #else 3605 if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { 3606 while (!exists && n--) 3607 exists = protocols[n] == proto; 3608 XFree(protocols); 3609 } 3610 #endif // BAR_SYSTRAY_PATCH 3611 3612 if (exists) { 3613 #if BAR_SYSTRAY_PATCH 3614 ev.type = ClientMessage; 3615 ev.xclient.window = w; 3616 ev.xclient.message_type = mt; 3617 ev.xclient.format = 32; 3618 ev.xclient.data.l[0] = d0; 3619 ev.xclient.data.l[1] = d1; 3620 ev.xclient.data.l[2] = d2; 3621 ev.xclient.data.l[3] = d3; 3622 ev.xclient.data.l[4] = d4; 3623 XSendEvent(dpy, w, False, mask, &ev); 3624 #else 3625 ev.type = ClientMessage; 3626 ev.xclient.window = c->win; 3627 ev.xclient.message_type = wmatom[WMProtocols]; 3628 ev.xclient.format = 32; 3629 ev.xclient.data.l[0] = proto; 3630 ev.xclient.data.l[1] = CurrentTime; 3631 XSendEvent(dpy, c->win, False, NoEventMask, &ev); 3632 #endif // BAR_SYSTRAY_PATCH 3633 } 3634 return exists; 3635 } 3636 3637 void 3638 setfocus(Client *c) 3639 { 3640 if (!c->neverfocus) { 3641 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); 3642 XChangeProperty(dpy, root, netatom[NetActiveWindow], 3643 XA_WINDOW, 32, PropModeReplace, 3644 (unsigned char *) &(c->win), 1); 3645 #if XKB_PATCH 3646 XkbLockGroup(dpy, XkbUseCoreKbd, c->xkb->group); 3647 #endif // XKB_PATCH 3648 } 3649 3650 #if GAMES_PATCH 3651 if (c->isgame && c->isfullscreen) 3652 unminimize(c); 3653 #endif // GAMES_PATCH 3654 3655 #if BAR_SYSTRAY_PATCH 3656 sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); 3657 #else 3658 sendevent(c, wmatom[WMTakeFocus]); 3659 #endif // BAR_SYSTRAY_PATCH 3660 } 3661 3662 #if FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH 3663 void 3664 setfullscreen(Client *c, int fullscreen) 3665 { 3666 XEvent ev; 3667 int savestate = 0, restorestate = 0; 3668 3669 if ((c->fakefullscreen == 0 && fullscreen && !c->isfullscreen) // normal fullscreen 3670 || (c->fakefullscreen == 2 && fullscreen)) // fake fullscreen --> actual fullscreen 3671 savestate = 1; // go actual fullscreen 3672 else if ((c->fakefullscreen == 0 && !fullscreen && c->isfullscreen) // normal fullscreen exit 3673 || (c->fakefullscreen >= 2 && !fullscreen)) // fullscreen exit --> fake fullscreen 3674 restorestate = 1; // go back into tiled 3675 3676 /* If leaving fullscreen and the window was previously fake fullscreen (2), then restore 3677 * that while staying in fullscreen. The exception to this is if we are in said state, but 3678 * the client itself disables fullscreen (3) then we let the client go out of fullscreen 3679 * while keeping fake fullscreen enabled (as otherwise there will be a mismatch between the 3680 * client and the window manager's perception of the client's fullscreen state). */ 3681 if (c->fakefullscreen == 2 && !fullscreen && c->isfullscreen) { 3682 c->fakefullscreen = 1; 3683 c->isfullscreen = 1; 3684 fullscreen = 1; 3685 } else if (c->fakefullscreen == 3) // client exiting actual fullscreen 3686 c->fakefullscreen = 1; 3687 3688 if (fullscreen != c->isfullscreen) { // only send property change if necessary 3689 if (fullscreen) 3690 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, 3691 PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); 3692 else 3693 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, 3694 PropModeReplace, (unsigned char*)0, 0); 3695 } 3696 3697 c->isfullscreen = fullscreen; 3698 3699 /* Some clients, e.g. firefox, will send a client message informing the window manager 3700 * that it is going into fullscreen after receiving the above signal. This has the side 3701 * effect of this function (setfullscreen) sometimes being called twice when toggling 3702 * fullscreen on and off via the window manager as opposed to the application itself. 3703 * To protect against obscure issues where the client settings are stored or restored 3704 * when they are not supposed to we add an additional bit-lock on the old state so that 3705 * settings can only be stored and restored in that precise order. */ 3706 if (savestate && !(c->oldstate & (1 << 1))) { 3707 c->oldbw = c->bw; 3708 c->oldstate = c->isfloating | (1 << 1); 3709 c->bw = 0; 3710 c->isfloating = 1; 3711 resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); 3712 XRaiseWindow(dpy, c->win); 3713 } else if (restorestate && (c->oldstate & (1 << 1))) { 3714 c->bw = c->oldbw; 3715 c->isfloating = c->oldstate = c->oldstate & 1; 3716 c->x = c->oldx; 3717 c->y = c->oldy; 3718 c->w = c->oldw; 3719 c->h = c->oldh; 3720 resizeclient(c, c->x, c->y, c->w, c->h); 3721 restack(c->mon); 3722 } else 3723 resizeclient(c, c->x, c->y, c->w, c->h); 3724 3725 /* Exception: if the client was in actual fullscreen and we exit out to fake fullscreen 3726 * mode, then the focus would sometimes drift to whichever window is under the mouse cursor 3727 * at the time. To avoid this we ask X for all EnterNotify events and just ignore them. 3728 */ 3729 if (!c->isfullscreen) 3730 while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); 3731 } 3732 #else 3733 void 3734 setfullscreen(Client *c, int fullscreen) 3735 { 3736 if (fullscreen && !c->isfullscreen) { 3737 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, 3738 PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); 3739 c->isfullscreen = 1; 3740 #if !FAKEFULLSCREEN_PATCH 3741 c->oldbw = c->bw; 3742 c->oldstate = c->isfloating; 3743 c->bw = 0; 3744 c->isfloating = 1; 3745 resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); 3746 XRaiseWindow(dpy, c->win); 3747 #endif // !FAKEFULLSCREEN_PATCH 3748 } else if (!fullscreen && c->isfullscreen){ 3749 XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, 3750 PropModeReplace, (unsigned char*)0, 0); 3751 c->isfullscreen = 0; 3752 #if !FAKEFULLSCREEN_PATCH 3753 c->bw = c->oldbw; 3754 c->isfloating = c->oldstate; 3755 c->x = c->oldx; 3756 c->y = c->oldy; 3757 c->w = c->oldw; 3758 c->h = c->oldh; 3759 resizeclient(c, c->x, c->y, c->w, c->h); 3760 arrange(c->mon); 3761 #endif // !FAKEFULLSCREEN_PATCH 3762 } 3763 #if FAKEFULLSCREEN_PATCH 3764 resizeclient(c, c->x, c->y, c->w, c->h); 3765 #endif // FAKEFULLSCREEN_PATCH 3766 } 3767 #endif // FAKEFULLSCREEN_CLIENT_PATCH 3768 3769 void 3770 setlayout(const Arg *arg) 3771 { 3772 #if !TOGGLELAYOUT_PATCH 3773 if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { 3774 #endif // TOGGLELAYOUT_PATCH 3775 #if PERTAG_PATCH 3776 selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; 3777 selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; 3778 #else 3779 selmon->sellt ^= 1; 3780 #endif // PERTAG_PATCH 3781 #if EXRESIZE_PATCH 3782 if (!selmon->lt[selmon->sellt]->arrange) { 3783 for (Client *c = selmon->clients ; c ; c = c->next) { 3784 if (!c->isfloating) { 3785 /*restore last known float dimensions*/ 3786 resize(c, selmon->mx + c->sfx, selmon->my + c->sfy, 3787 c->sfw, c->sfh, False); 3788 } 3789 } 3790 } 3791 #endif // EXRESIZE_PATCH 3792 #if !TOGGLELAYOUT_PATCH 3793 } 3794 #endif // TOGGLELAYOUT_PATCH 3795 #if TOGGLELAYOUT_PATCH 3796 if (arg && arg->v && arg->v != selmon->lt[selmon->sellt ^ 1]) 3797 #else 3798 if (arg && arg->v) 3799 #endif // TOGGLELAYOUT_PATCH 3800 #if PERTAG_PATCH 3801 selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; 3802 selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; 3803 #else 3804 selmon->lt[selmon->sellt] = (Layout *)arg->v; 3805 #endif // PERTAG_PATCH 3806 3807 #if FLEXTILE_DELUXE_LAYOUT 3808 if (selmon->lt[selmon->sellt]->preset.nmaster && selmon->lt[selmon->sellt]->preset.nmaster != -1) 3809 selmon->nmaster = selmon->lt[selmon->sellt]->preset.nmaster; 3810 if (selmon->lt[selmon->sellt]->preset.nstack && selmon->lt[selmon->sellt]->preset.nstack != -1) 3811 selmon->nstack = selmon->lt[selmon->sellt]->preset.nstack; 3812 3813 selmon->ltaxis[LAYOUT] = selmon->lt[selmon->sellt]->preset.layout; 3814 selmon->ltaxis[MASTER] = selmon->lt[selmon->sellt]->preset.masteraxis; 3815 selmon->ltaxis[STACK] = selmon->lt[selmon->sellt]->preset.stack1axis; 3816 selmon->ltaxis[STACK2] = selmon->lt[selmon->sellt]->preset.stack2axis; 3817 3818 #if PERTAG_PATCH 3819 selmon->pertag->ltaxis[selmon->pertag->curtag][LAYOUT] = selmon->ltaxis[LAYOUT]; 3820 selmon->pertag->ltaxis[selmon->pertag->curtag][MASTER] = selmon->ltaxis[MASTER]; 3821 selmon->pertag->ltaxis[selmon->pertag->curtag][STACK] = selmon->ltaxis[STACK]; 3822 selmon->pertag->ltaxis[selmon->pertag->curtag][STACK2] = selmon->ltaxis[STACK2]; 3823 #endif // PERTAG_PATCH 3824 #endif // FLEXTILE_DELUXE_LAYOUT 3825 strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); 3826 if (selmon->sel) 3827 arrange(selmon); 3828 else 3829 drawbar(selmon); 3830 } 3831 3832 /* arg > 1.0 will set mfact absolutely */ 3833 void 3834 setmfact(const Arg *arg) 3835 { 3836 float f; 3837 3838 if (!arg || !selmon->lt[selmon->sellt]->arrange) 3839 return; 3840 f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; 3841 if (f < 0.05 || f > 0.95) 3842 return; 3843 #if PERTAG_PATCH 3844 selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; 3845 #else 3846 selmon->mfact = f; 3847 #endif // PERTAG_PATCH 3848 arrange(selmon); 3849 } 3850 3851 void 3852 setup(void) 3853 { 3854 int i; 3855 XSetWindowAttributes wa; 3856 #if XKB_PATCH 3857 XkbStateRec xkbstate; 3858 #endif // XKB_PATCH 3859 Atom utf8string; 3860 #if COOL_AUTOSTART_PATCH 3861 /* clean up any zombies immediately */ 3862 sigchld(0); 3863 #else 3864 struct sigaction sa; 3865 3866 /* do not transform children into zombies when they terminate */ 3867 sigemptyset(&sa.sa_mask); 3868 sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART; 3869 sa.sa_handler = SIG_IGN; 3870 sigaction(SIGCHLD, &sa, NULL); 3871 3872 /* clean up any zombies (inherited from .xinitrc etc) immediately */ 3873 while (waitpid(-1, NULL, WNOHANG) > 0); 3874 #endif // COOL_AUTOSTART_PATCH 3875 3876 #if RESTARTSIG_PATCH 3877 signal(SIGHUP, sighup); 3878 signal(SIGTERM, sigterm); 3879 #endif // RESTARTSIG_PATCH 3880 3881 /* the one line of bloat that would have saved a lot of time for a lot of people */ 3882 putenv("_JAVA_AWT_WM_NONREPARENTING=1"); 3883 3884 /* init screen */ 3885 screen = DefaultScreen(dpy); 3886 sw = DisplayWidth(dpy, screen); 3887 sh = DisplayHeight(dpy, screen); 3888 root = RootWindow(dpy, screen); 3889 #if BAR_ALPHA_PATCH 3890 xinitvisual(); 3891 drw = drw_create(dpy, screen, root, sw, sh, visual, depth, cmap); 3892 #else 3893 drw = drw_create(dpy, screen, root, sw, sh); 3894 #endif // BAR_ALPHA_PATCH 3895 #if BAR_PANGO_PATCH 3896 if (!drw_font_create(drw, font)) 3897 #else 3898 if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) 3899 #endif // BAR_PANGO_PATCH 3900 die("no fonts could be loaded."); 3901 #if BAR_STATUSPADDING_PATCH 3902 lrpad = drw->fonts->h + horizpadbar; 3903 bh = drw->fonts->h + vertpadbar; 3904 #else 3905 lrpad = drw->fonts->h; 3906 #if BAR_HEIGHT_PATCH 3907 bh = bar_height ? bar_height : drw->fonts->h + 2; 3908 #else 3909 bh = drw->fonts->h + 2; 3910 #endif // BAR_HEIGHT_PATCH 3911 #endif // BAR_STATUSPADDING_PATCH 3912 #if TAB_PATCH 3913 th = bh; 3914 #endif // TAB_PATCH 3915 updategeom(); 3916 /* init atoms */ 3917 utf8string = XInternAtom(dpy, "UTF8_STRING", False); 3918 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); 3919 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); 3920 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); 3921 wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); 3922 #if WINDOWROLERULE_PATCH 3923 wmatom[WMWindowRole] = XInternAtom(dpy, "WM_WINDOW_ROLE", False); 3924 #endif // WINDOWROLERULE_PATCH 3925 #if SEAMLESS_RESTART_PATCH 3926 clientatom[ClientFields] = XInternAtom(dpy, "_DWM_CLIENT_FIELDS", False); 3927 clientatom[ClientTags] = XInternAtom(dpy, "_DWM_CLIENT_TAGS", False); 3928 #endif // SEAMLESS_RESTART_PATCH 3929 netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); 3930 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); 3931 #if BAR_SYSTRAY_PATCH 3932 netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); 3933 netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); 3934 netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); 3935 netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False); 3936 netatom[NetSystemTrayVisual] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_VISUAL", False); 3937 netatom[NetWMWindowTypeDock] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); 3938 xatom[Manager] = XInternAtom(dpy, "MANAGER", False); 3939 xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); 3940 xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); 3941 #endif // BAR_SYSTRAY_PATCH 3942 #if BAR_EWMHTAGS_PATCH 3943 netatom[NetDesktopViewport] = XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False); 3944 netatom[NetNumberOfDesktops] = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False); 3945 netatom[NetCurrentDesktop] = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False); 3946 netatom[NetDesktopNames] = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False); 3947 #endif // BAR_EWMHTAGS_PATCH 3948 #if BAR_WINICON_PATCH 3949 netatom[NetWMIcon] = XInternAtom(dpy, "_NET_WM_ICON", False); 3950 #endif // BAR_WINICON_PATCH 3951 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); 3952 netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); 3953 netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); 3954 netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); 3955 netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); 3956 netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); 3957 #if NET_CLIENT_LIST_STACKING_PATCH 3958 netatom[NetClientListStacking] = XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", False); 3959 #endif // NET_CLIENT_LIST_STACKING_PATCH 3960 #if DECORATION_HINTS_PATCH 3961 motifatom = XInternAtom(dpy, "_MOTIF_WM_HINTS", False); 3962 #endif // DECORATION_HINTS_PATCH 3963 /* init cursors */ 3964 cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); 3965 cursor[CurResize] = drw_cur_create(drw, XC_sizing); 3966 #if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH 3967 cursor[CurResizeBR] = drw_cur_create(drw, XC_bottom_right_corner); 3968 cursor[CurResizeBL] = drw_cur_create(drw, XC_bottom_left_corner); 3969 cursor[CurResizeTR] = drw_cur_create(drw, XC_top_right_corner); 3970 cursor[CurResizeTL] = drw_cur_create(drw, XC_top_left_corner); 3971 #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH 3972 #if DRAGMFACT_PATCH 3973 cursor[CurResizeHorzArrow] = drw_cur_create(drw, XC_sb_h_double_arrow); 3974 cursor[CurResizeVertArrow] = drw_cur_create(drw, XC_sb_v_double_arrow); 3975 #endif // DRAGMFACT_PATCH 3976 #if DRAGCFACT_PATCH 3977 cursor[CurIronCross] = drw_cur_create(drw, XC_iron_cross); 3978 #endif // DRAGCFACT_PATCH 3979 cursor[CurMove] = drw_cur_create(drw, XC_fleur); 3980 /* init appearance */ 3981 #if BAR_VTCOLORS_PATCH 3982 get_vt_colors(); 3983 if (get_luminance(colors[SchemeTagsNorm][ColBg]) > 50) { 3984 strcpy(colors[SchemeTitleNorm][ColBg], title_bg_light); 3985 strcpy(colors[SchemeTitleSel][ColBg], title_bg_light); 3986 } else { 3987 strcpy(colors[SchemeTitleNorm][ColBg], title_bg_dark); 3988 strcpy(colors[SchemeTitleSel][ColBg], title_bg_dark); 3989 } 3990 #endif // BAR_VTCOLORS_PATCH 3991 #if BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH 3992 scheme = ecalloc(LENGTH(colors) + 1, sizeof(Clr *)); 3993 #if BAR_ALPHA_PATCH 3994 scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], alphas[0], ColCount); 3995 #else 3996 scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], ColCount); 3997 #endif // BAR_ALPHA_PATCH 3998 #else 3999 scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); 4000 #endif // BAR_STATUS2D_PATCH 4001 for (i = 0; i < LENGTH(colors); i++) 4002 #if BAR_ALPHA_PATCH 4003 scheme[i] = drw_scm_create(drw, colors[i], alphas[i], ColCount); 4004 #else 4005 scheme[i] = drw_scm_create(drw, colors[i], ColCount); 4006 #endif // BAR_ALPHA_PATCH 4007 #if BAR_POWERLINE_STATUS_PATCH 4008 statusscheme = ecalloc(LENGTH(statuscolors), sizeof(Clr *)); 4009 for (i = 0; i < LENGTH(statuscolors); i++) 4010 #if BAR_ALPHA_PATCH 4011 statusscheme[i] = drw_scm_create(drw, statuscolors[i], alphas[0], ColCount); 4012 #else 4013 statusscheme[i] = drw_scm_create(drw, statuscolors[i], ColCount); 4014 #endif // BAR_ALPHA_PATCH 4015 #endif // BAR_POWERLINE_STATUS_PATCH 4016 4017 updatebars(); 4018 updatestatus(); 4019 4020 /* supporting window for NetWMCheck */ 4021 wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); 4022 XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, 4023 PropModeReplace, (unsigned char *) &wmcheckwin, 1); 4024 #if LG3D_PATCH 4025 XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8, 4026 PropModeReplace, (unsigned char *) "LG3D", 4); 4027 #else 4028 XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8, 4029 PropModeReplace, (unsigned char *) "dwm", 3); 4030 #endif // LG3D_PATCH 4031 XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32, 4032 PropModeReplace, (unsigned char *) &wmcheckwin, 1); 4033 /* EWMH support per view */ 4034 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, 4035 PropModeReplace, (unsigned char *) netatom, NetLast); 4036 #if BAR_EWMHTAGS_PATCH 4037 setnumdesktops(); 4038 setcurrentdesktop(); 4039 setdesktopnames(); 4040 setviewport(); 4041 #endif // BAR_EWMHTAGS_PATCH 4042 XDeleteProperty(dpy, root, netatom[NetClientList]); 4043 #if NET_CLIENT_LIST_STACKING_PATCH 4044 XDeleteProperty(dpy, root, netatom[NetClientListStacking]); 4045 #endif // NET_CLIENT_LIST_STACKING_PATCH 4046 /* select events */ 4047 wa.cursor = cursor[CurNormal]->cursor; 4048 wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask 4049 |ButtonPressMask|PointerMotionMask|EnterWindowMask 4050 |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; 4051 XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); 4052 XSelectInput(dpy, root, wa.event_mask); 4053 4054 #if XKB_PATCH 4055 /* get xkb extension info, events and current state */ 4056 if (!XkbQueryExtension(dpy, NULL, &xkbEventType, NULL, NULL, NULL)) 4057 fputs("warning: can not query xkb extension\n", stderr); 4058 XkbSelectEventDetails(dpy, XkbUseCoreKbd, XkbStateNotify, 4059 XkbAllStateComponentsMask, XkbGroupStateMask); 4060 XkbGetState(dpy, XkbUseCoreKbd, &xkbstate); 4061 xkbGlobal.group = xkbstate.locked_group; 4062 #endif // XKB_PATCH 4063 4064 #if BANISH_PATCH 4065 if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &i, &i)) { 4066 fprintf(stderr, "Warning: XInput is not available."); 4067 } 4068 /* Tell XInput to send us all RawMotion events. */ 4069 unsigned char mask_bytes[XIMaskLen(XI_LASTEVENT)]; 4070 memset(mask_bytes, 0, sizeof(mask_bytes)); 4071 XISetMask(mask_bytes, XI_RawMotion); 4072 XISetMask(mask_bytes, XI_RawKeyRelease); 4073 XISetMask(mask_bytes, XI_RawTouchBegin); 4074 XISetMask(mask_bytes, XI_RawTouchEnd); 4075 XISetMask(mask_bytes, XI_RawTouchUpdate); 4076 4077 XIEventMask mask; 4078 mask.deviceid = XIAllMasterDevices; 4079 mask.mask_len = sizeof(mask_bytes); 4080 mask.mask = mask_bytes; 4081 XISelectEvents(dpy, root, &mask, 1); 4082 #endif // BANISH_PATCH 4083 4084 grabkeys(); 4085 focus(NULL); 4086 #if IPC_PATCH 4087 setupepoll(); 4088 #endif // IPC_PATCH 4089 #if BAR_ANYBAR_PATCH 4090 if (usealtbar) 4091 spawnbar(); 4092 #endif // BAR_ANYBAR_PATCH 4093 } 4094 4095 4096 void 4097 seturgent(Client *c, int urg) 4098 { 4099 XWMHints *wmh; 4100 4101 c->isurgent = urg; 4102 if (!(wmh = XGetWMHints(dpy, c->win))) 4103 return; 4104 wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint); 4105 XSetWMHints(dpy, c->win, wmh); 4106 XFree(wmh); 4107 } 4108 4109 void 4110 showhide(Client *c) 4111 { 4112 if (!c) 4113 return; 4114 if (ISVISIBLE(c)) { 4115 #if !RENAMED_SCRATCHPADS_PATCH 4116 #if SCRATCHPADS_PATCH && SCRATCHPADS_KEEP_POSITION_AND_SIZE_PATCH 4117 if ( 4118 (c->tags & SPTAGMASK) && 4119 c->isfloating && 4120 ( 4121 c->x < c->mon->mx || 4122 c->x > c->mon->mx + c->mon->mw || 4123 c->y < c->mon->my || 4124 c->y > c->mon->my + c->mon->mh 4125 ) 4126 ) { 4127 c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); 4128 c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); 4129 } 4130 #elif SCRATCHPADS_PATCH 4131 if ((c->tags & SPTAGMASK) && c->isfloating) { 4132 c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); 4133 c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); 4134 } 4135 #endif // SCRATCHPADS_KEEP_POSITION_AND_SIZE_PATCH | SCRATCHPADS_PATCH 4136 #endif // RENAMED_SCRATCHPADS_PATCH 4137 /* show clients top down */ 4138 #if SAVEFLOATS_PATCH || EXRESIZE_PATCH 4139 if (!c->mon->lt[c->mon->sellt]->arrange && c->sfx != -9999 && !c->isfullscreen) { 4140 XMoveResizeWindow(dpy, c->win, c->sfx, c->sfy, c->sfw, c->sfh); 4141 resize(c, c->sfx, c->sfy, c->sfw, c->sfh, 0); 4142 showhide(c->snext); 4143 return; 4144 } 4145 #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH 4146 #if AUTORESIZE_PATCH 4147 if (c->needresize) { 4148 c->needresize = 0; 4149 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); 4150 } else { 4151 XMoveWindow(dpy, c->win, c->x, c->y); 4152 } 4153 #else 4154 XMoveWindow(dpy, c->win, c->x, c->y); 4155 #endif // AUTORESIZE_PATCH 4156 if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) 4157 #if !FAKEFULLSCREEN_PATCH 4158 && !c->isfullscreen 4159 #endif // !FAKEFULLSCREEN_PATCH 4160 ) 4161 resize(c, c->x, c->y, c->w, c->h, 0); 4162 showhide(c->snext); 4163 } else { 4164 #if RENAMED_SCRATCHPADS_PATCH && RENAMED_SCRATCHPADS_AUTO_HIDE_PATCH 4165 /* optional: auto-hide scratchpads when moving to other tags */ 4166 if (c->scratchkey != 0 && !(c->tags & c->mon->tagset[c->mon->seltags])) 4167 c->tags = 0; 4168 #endif // RENAMED_SCRATCHPADS_AUTO_HIDE_PATCH 4169 /* hide clients bottom up */ 4170 showhide(c->snext); 4171 XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); 4172 } 4173 } 4174 4175 #if COOL_AUTOSTART_PATCH 4176 void 4177 sigchld(int unused) 4178 { 4179 pid_t pid; 4180 4181 if (signal(SIGCHLD, sigchld) == SIG_ERR) 4182 die("can't install SIGCHLD handler:"); 4183 4184 while (0 < (pid = waitpid(-1, NULL, WNOHANG))) { 4185 pid_t *p, *lim; 4186 4187 if (!(p = autostart_pids)) 4188 continue; 4189 lim = &p[autostart_len]; 4190 4191 for (; p < lim; p++) { 4192 if (*p == pid) { 4193 *p = -1; 4194 break; 4195 } 4196 } 4197 } 4198 } 4199 #endif // COOL_AUTOSTART_PATCH 4200 4201 #if RIODRAW_PATCH 4202 void 4203 spawn(const Arg *arg) 4204 { 4205 spawncmd(arg); 4206 } 4207 4208 pid_t 4209 spawncmd(const Arg *arg) 4210 #else 4211 void 4212 spawn(const Arg *arg) 4213 #endif // RIODRAW_PATCH 4214 { 4215 struct sigaction sa; 4216 4217 #if RIODRAW_PATCH 4218 pid_t pid; 4219 #endif // RIODRAW_PATCH 4220 #if !NODMENU_PATCH 4221 if (arg->v == dmenucmd) 4222 dmenumon[0] = '0' + selmon->num; 4223 #endif // NODMENU_PATCH 4224 4225 #if RIODRAW_PATCH 4226 if ((pid = fork()) == 0) 4227 #else 4228 if (fork() == 0) 4229 #endif // RIODRAW_PATCH 4230 { 4231 if (dpy) 4232 close(ConnectionNumber(dpy)); 4233 4234 #if BAR_STATUSCMD_PATCH && !BAR_DWMBLOCKS_PATCH 4235 if (arg->v == statuscmd) { 4236 for (int i = 0; i < LENGTH(statuscmds); i++) { 4237 if (statuscmdn == statuscmds[i].id) { 4238 statuscmd[2] = statuscmds[i].cmd; 4239 setenv("BUTTON", lastbutton, 1); 4240 break; 4241 } 4242 } 4243 if (!statuscmd[2]) 4244 exit(EXIT_SUCCESS); 4245 } 4246 #endif // BAR_STATUSCMD_PATCH | BAR_DWMBLOCKS_PATCH 4247 #if SPAWNCMD_PATCH 4248 if (selmon->sel) { 4249 const char* const home = getenv("HOME"); 4250 assert(home && strchr(home, '/')); 4251 const size_t homelen = strlen(home); 4252 char *cwd, *pathbuf = NULL; 4253 struct stat statbuf; 4254 4255 cwd = strtok(selmon->sel->name, SPAWN_CWD_DELIM); 4256 /* NOTE: strtok() alters selmon->sel->name in-place, 4257 * but that does not matter because we are going to 4258 * exec() below anyway; nothing else will use it */ 4259 while (cwd) { 4260 if (*cwd == '~') { /* replace ~ with $HOME */ 4261 if (!(pathbuf = malloc(homelen + strlen(cwd)))) /* ~ counts for NULL term */ 4262 die("fatal: could not malloc() %u bytes\n", homelen + strlen(cwd)); 4263 strcpy(strcpy(pathbuf, home) + homelen, cwd + 1); 4264 cwd = pathbuf; 4265 } 4266 4267 if (strchr(cwd, '/') && !stat(cwd, &statbuf)) { 4268 if (!S_ISDIR(statbuf.st_mode)) 4269 cwd = dirname(cwd); 4270 4271 if (!chdir(cwd)) 4272 break; 4273 } 4274 4275 cwd = strtok(NULL, SPAWN_CWD_DELIM); 4276 } 4277 4278 free(pathbuf); 4279 } 4280 #endif // SPAWNCMD_PATCH 4281 setsid(); 4282 4283 sigemptyset(&sa.sa_mask); 4284 sa.sa_flags = 0; 4285 sa.sa_handler = SIG_DFL; 4286 sigaction(SIGCHLD, &sa, NULL); 4287 4288 execvp(((char **)arg->v)[0], (char **)arg->v); 4289 die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]); 4290 } 4291 #if RIODRAW_PATCH 4292 return pid; 4293 #endif // RIODRAW_PATCH 4294 } 4295 4296 void 4297 tag(const Arg *arg) 4298 { 4299 #if SWAPFOCUS_PATCH && PERTAG_PATCH 4300 unsigned int tagmask, tagindex; 4301 #endif // SWAPFOCUS_PATCH 4302 4303 if (selmon->sel && arg->ui & TAGMASK) { 4304 selmon->sel->tags = arg->ui & TAGMASK; 4305 #if SWITCHTAG_PATCH 4306 if (selmon->sel->switchtag) 4307 selmon->sel->switchtag = 0; 4308 #endif // SWITCHTAG_PATCH 4309 arrange(selmon); 4310 focus(NULL); 4311 #if SWAPFOCUS_PATCH && PERTAG_PATCH 4312 selmon->pertag->prevclient[selmon->pertag->curtag] = NULL; 4313 for (tagmask = arg->ui & TAGMASK, tagindex = 1; tagmask!=0; tagmask >>= 1, tagindex++) 4314 if (tagmask & 1) 4315 selmon->pertag->prevclient[tagindex] = NULL; 4316 #endif // SWAPFOCUS_PATCH 4317 #if VIEWONTAG_PATCH 4318 if ((arg->ui & TAGMASK) != selmon->tagset[selmon->seltags]) 4319 view(arg); 4320 #endif // VIEWONTAG_PATCH 4321 } 4322 } 4323 4324 void 4325 tagmon(const Arg *arg) 4326 { 4327 Client *c = selmon->sel; 4328 Monitor *dest; 4329 #if SEAMLESS_RESTART_PATCH && SAVEFLOATS_PATCH 4330 int restored; 4331 #endif // SEAMLESS_RESTART_PATCH | SAVEFLOATS_PATCH 4332 if (!c || !mons->next) 4333 return; 4334 dest = dirtomon(arg->i); 4335 #if SEAMLESS_RESTART_PATCH && SAVEFLOATS_PATCH 4336 savewindowfloatposition(c, c->mon); 4337 restored = restorewindowfloatposition(c, dest); 4338 if (restored && (!dest->lt[dest->sellt]->arrange || c->isfloating)) { 4339 XMoveResizeWindow(dpy, c->win, c->sfx, c->sfy, c->sfw, c->sfh); 4340 resize(c, c->sfx, c->sfy, c->sfw, c->sfh, 1); 4341 } 4342 #endif // SEAMLESS_RESTART_PATCH | SAVEFLOATS_PATCH 4343 #if TAGMONFIXFS_PATCH 4344 if (c->isfullscreen) { 4345 c->isfullscreen = 0; 4346 sendmon(c, dest); 4347 c->isfullscreen = 1; 4348 #if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH 4349 if (c->fakefullscreen != 1) { 4350 resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); 4351 XRaiseWindow(dpy, c->win); 4352 } 4353 #elif !FAKEFULLSCREEN_PATCH 4354 resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); 4355 XRaiseWindow(dpy, c->win); 4356 #endif // FAKEFULLSCREEN_CLIENT_PATCH 4357 } else 4358 sendmon(c, dest); 4359 #else 4360 sendmon(c, dest); 4361 #endif // TAGMONFIXFS_PATCH 4362 } 4363 4364 void 4365 togglebar(const Arg *arg) 4366 { 4367 Bar *bar; 4368 #if BAR_HOLDBAR_PATCH && PERTAG_PATCH && PERTAGBAR_PATCH 4369 selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = (selmon->showbar == 2 ? 1 : !selmon->showbar); 4370 #elif BAR_HOLDBAR_PATCH 4371 selmon->showbar = (selmon->showbar == 2 ? 1 : !selmon->showbar); 4372 #elif PERTAG_PATCH && PERTAGBAR_PATCH 4373 selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; 4374 #else 4375 selmon->showbar = !selmon->showbar; 4376 #endif // BAR_HOLDBAR_PATCH | PERTAG_PATCH 4377 updatebarpos(selmon); 4378 for (bar = selmon->bar; bar; bar = bar->next) 4379 XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); 4380 #if BAR_SYSTRAY_PATCH 4381 if (!selmon->showbar && systray) 4382 XMoveWindow(dpy, systray->win, -32000, -32000); 4383 #endif // BAR_SYSTRAY_PATCH 4384 arrange(selmon); 4385 } 4386 4387 void 4388 togglefloating(const Arg *arg) 4389 { 4390 Client *c = selmon->sel; 4391 if (arg && arg->v) 4392 c = (Client*)arg->v; 4393 if (!c) 4394 return; 4395 #if !FAKEFULLSCREEN_PATCH 4396 #if FAKEFULLSCREEN_CLIENT_PATCH 4397 if (c->isfullscreen && c->fakefullscreen != 1) /* no support for fullscreen windows */ 4398 return; 4399 #else 4400 if (c->isfullscreen) /* no support for fullscreen windows */ 4401 return; 4402 #endif // FAKEFULLSCREEN_CLIENT_PATCH 4403 #endif // !FAKEFULLSCREEN_PATCH 4404 c->isfloating = !c->isfloating || c->isfixed; 4405 #if !BAR_FLEXWINTITLE_PATCH 4406 #if RENAMED_SCRATCHPADS_PATCH 4407 if (c->scratchkey != 0 && c->isfloating) 4408 XSetWindowBorder(dpy, c->win, scheme[SchemeScratchSel][ColFloat].pixel); 4409 else if (c->scratchkey != 0) 4410 XSetWindowBorder(dpy, c->win, scheme[SchemeScratchSel][ColBorder].pixel); 4411 else if (c->isfloating) 4412 XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel); 4413 else 4414 XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); 4415 #else 4416 if (c->isfloating) 4417 XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel); 4418 else 4419 XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); 4420 #endif // RENAMED_SCRATCHPADS_PATCH 4421 #endif // BAR_FLEXWINTITLE_PATCH 4422 if (c->isfloating) { 4423 #if SAVEFLOATS_PATCH || EXRESIZE_PATCH 4424 if (c->sfx != -9999) { 4425 /* restore last known float dimensions */ 4426 resize(c, c->sfx, c->sfy, c->sfw, c->sfh, 0); 4427 } else 4428 #endif // SAVEFLOATS_PATCH // EXRESIZE_PATCH 4429 resize(c, c->x, c->y, c->w, c->h, 0); 4430 #if SAVEFLOATS_PATCH || EXRESIZE_PATCH 4431 } else { 4432 /* save last known float dimensions */ 4433 c->sfx = c->x; 4434 c->sfy = c->y; 4435 c->sfw = c->w; 4436 c->sfh = c->h; 4437 #if ALWAYSONTOP_PATCH 4438 c->alwaysontop = 0; 4439 #endif // ALWAYSONTOP_PATCH 4440 #elif ALWAYSONTOP_PATCH 4441 } else { 4442 c->alwaysontop = 0; 4443 #endif // SAVEFLOATS_PATCH | EXRESIZE_PATCH | ALWAYSONTOP_PATCH 4444 } 4445 arrange(c->mon); 4446 4447 #if BAR_EWMHTAGS_PATCH 4448 setfloatinghint(c); 4449 #endif // BAR_EWMHTAGS_PATCH 4450 } 4451 4452 void 4453 toggletag(const Arg *arg) 4454 { 4455 unsigned int newtags; 4456 #if SWAPFOCUS_PATCH && PERTAG_PATCH 4457 unsigned int tagmask, tagindex; 4458 #endif // SWAPFOCUS_PATCH 4459 4460 if (!selmon->sel) 4461 return; 4462 newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); 4463 if (newtags) { 4464 selmon->sel->tags = newtags; 4465 arrange(selmon); 4466 focus(NULL); 4467 #if SWAPFOCUS_PATCH && PERTAG_PATCH 4468 for (tagmask = arg->ui & TAGMASK, tagindex = 1; tagmask!=0; tagmask >>= 1, tagindex++) 4469 if (tagmask & 1) 4470 selmon->pertag->prevclient[tagindex] = NULL; 4471 #endif // SWAPFOCUS_PATCH 4472 } 4473 #if BAR_EWMHTAGS_PATCH 4474 updatecurrentdesktop(); 4475 #endif // BAR_EWMHTAGS_PATCH 4476 } 4477 4478 void 4479 toggleview(const Arg *arg) 4480 { 4481 unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);; 4482 #if TAGSYNC_PATCH 4483 Monitor *origselmon = selmon; 4484 for (selmon = mons; selmon; selmon = selmon->next) { 4485 #endif // TAGSYNC_PATCH 4486 #if PERTAG_PATCH 4487 int i; 4488 #endif // PERTAG_PATCH 4489 4490 #if TAGINTOSTACK_ALLMASTER_PATCH 4491 Client *const selected = selmon->sel; 4492 4493 // clients in the master area should be the same after we add a new tag 4494 Client **const masters = calloc(selmon->nmaster, sizeof(Client *)); 4495 if (!masters) { 4496 die("fatal: could not calloc() %u bytes \n", selmon->nmaster * sizeof(Client *)); 4497 } 4498 // collect (from last to first) references to all clients in the master area 4499 Client *c; 4500 size_t j; 4501 for (c = nexttiled(selmon->clients), j = 0; c && j < selmon->nmaster; c = nexttiled(c->next), ++j) 4502 masters[selmon->nmaster - (j + 1)] = c; 4503 // put the master clients at the front of the list 4504 // > go from the 'last' master to the 'first' 4505 for (j = 0; j < selmon->nmaster; ++j) 4506 if (masters[j]) 4507 pop(masters[j]); 4508 free(masters); 4509 4510 // we also want to be sure not to mutate the focus 4511 focus(selected); 4512 #elif TAGINTOSTACK_ONEMASTER_PATCH 4513 // the first visible client should be the same after we add a new tag 4514 // we also want to be sure not to mutate the focus 4515 Client *const c = nexttiled(selmon->clients); 4516 if (c) { 4517 Client * const selected = selmon->sel; 4518 pop(c); 4519 focus(selected); 4520 } 4521 #endif // TAGINTOSTACK_ALLMASTER_PATCH / TAGINTOSTACK_ONEMASTER_PATCH 4522 4523 #if !EMPTYVIEW_PATCH 4524 if (newtagset) { 4525 #endif // EMPTYVIEW_PATCH 4526 #if BAR_TAGPREVIEW_PATCH 4527 tagpreviewswitchtag(); 4528 #endif // BAR_TAGPREVIEW_PATCH 4529 selmon->tagset[selmon->seltags] = newtagset; 4530 4531 #if PERTAG_PATCH 4532 #if SCRATCHPADS_PATCH && !RENAMED_SCRATCHPADS_PATCH 4533 if (newtagset == ~SPTAGMASK) 4534 #else 4535 if (newtagset == ~0) 4536 #endif // SCRATCHPADS_PATCH 4537 { 4538 selmon->pertag->curtag = 0; 4539 } 4540 /* test if the user did not select the same tag */ 4541 if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { 4542 for (i = 0; !(newtagset & 1 << i); i++) ; 4543 selmon->pertag->curtag = i + 1; 4544 } 4545 4546 /* apply settings for this view */ 4547 selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; 4548 selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; 4549 selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; 4550 selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; 4551 selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; 4552 #if PERTAGBAR_PATCH 4553 if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) 4554 togglebar(NULL); 4555 #endif // PERTAGBAR_PATCH 4556 #endif // PERTAG_PATCH 4557 #if !TAGSYNC_PATCH 4558 arrange(selmon); 4559 focus(NULL); 4560 #endif // TAGSYNC_PATCH 4561 #if !EMPTYVIEW_PATCH 4562 } 4563 #endif // EMPTYVIEW_PATCH 4564 #if TAGSYNC_PATCH 4565 } 4566 selmon = origselmon; 4567 #if !EMPTYVIEW_PATCH 4568 if (newtagset) { 4569 #endif // EMPTYVIEW_PATCH 4570 arrange(NULL); 4571 focus(NULL); 4572 #if !EMPTYVIEW_PATCH 4573 } 4574 #endif // EMPTYVIEW_PATCH 4575 #endif // TAGSYNC_PATCH 4576 #if BAR_EWMHTAGS_PATCH 4577 updatecurrentdesktop(); 4578 #endif // BAR_EWMHTAGS_PATCH 4579 } 4580 4581 void 4582 unfocus(Client *c, int setfocus, Client *nextfocus) 4583 { 4584 if (!c) 4585 return; 4586 4587 #if SWAPFOCUS_PATCH && PERTAG_PATCH 4588 selmon->pertag->prevclient[selmon->pertag->curtag] = c; 4589 #endif // SWAPFOCUS_PATCH 4590 #if GAMES_PATCH 4591 if (c->isgame && c->isfullscreen) { 4592 minimize(c); 4593 } 4594 #endif // GAMES_PATCH 4595 #if GAMES_PATCH && LOSEFULLSCREEN_PATCH 4596 else 4597 #endif // GAMES_PATCH | LOSEFULLSCREEN_PATCH 4598 #if LOSEFULLSCREEN_PATCH 4599 if (c->isfullscreen && ISVISIBLE(c) && c->mon == selmon && nextfocus && !nextfocus->isfloating) { 4600 #if RENAMED_SCRATCHPADS_PATCH && RENAMED_SCRATCHPADS_AUTO_HIDE_PATCH 4601 #if FAKEFULLSCREEN_CLIENT_PATCH 4602 if (c->scratchkey != 0 && c->fakefullscreen != 1) 4603 togglescratch(&((Arg) {.v = (const char*[]){ &c->scratchkey, NULL } })); 4604 #else 4605 if (c->scratchkey != 0) 4606 togglescratch(&((Arg) {.v = (const char*[]){ &c->scratchkey, NULL } })); 4607 #endif // FAKEFULLSCREEN_CLIENT_PATCH 4608 else 4609 #endif // RENAMED_SCRATCHPADS_AUTO_HIDE_PATCH 4610 #if FAKEFULLSCREEN_CLIENT_PATCH 4611 if (c->fakefullscreen != 1) 4612 setfullscreen(c, 0); 4613 #else 4614 setfullscreen(c, 0); 4615 #endif // #if FAKEFULLSCREEN_CLIENT_PATCH 4616 } 4617 #endif // LOSEFULLSCREEN_PATCH 4618 grabbuttons(c, 0); 4619 #if !BAR_FLEXWINTITLE_PATCH 4620 #if RENAMED_SCRATCHPADS_PATCH 4621 if (c->scratchkey != 0 && c->isfloating) 4622 XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColFloat].pixel); 4623 else if (c->scratchkey != 0) 4624 XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel); 4625 else if (c->isfloating) 4626 XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColFloat].pixel); 4627 else 4628 XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); 4629 #else 4630 if (c->isfloating) 4631 XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColFloat].pixel); 4632 else 4633 XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); 4634 #endif // RENAMED_SCRATCHPADS_PATCH 4635 #endif // BAR_FLEXWINTITLE_PATCH 4636 if (setfocus) { 4637 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); 4638 XDeleteProperty(dpy, root, netatom[NetActiveWindow]); 4639 } 4640 } 4641 4642 void 4643 unmanage(Client *c, int destroyed) 4644 { 4645 Monitor *m; 4646 #if SWITCHTAG_PATCH 4647 unsigned int switchtag = c->switchtag; 4648 #endif // SWITCHTAG_PATCH 4649 XWindowChanges wc; 4650 #if XKB_PATCH 4651 XkbInfo *xkb; 4652 #endif // XKB_PATCH 4653 4654 #if ZOOMSWAP_PATCH 4655 /* Make sure to clear any previous zoom references to the client being removed. */ 4656 #if PERTAG_PATCH 4657 int i; 4658 for (m = mons; m; m = m->next) { 4659 for (i = 0; i <= NUMTAGS; i++) { 4660 if (m->pertag->prevzooms[i] == c) { 4661 m->pertag->prevzooms[i] = NULL; 4662 } 4663 } 4664 } 4665 #else 4666 if (c == prevzoom) 4667 prevzoom = NULL; 4668 #endif // PERTAG_PATCH 4669 #endif // ZOOMSWAP_PATCH 4670 m = c->mon; 4671 4672 #if SWALLOW_PATCH 4673 if (c->swallowing) { 4674 unswallow(c); 4675 return; 4676 } 4677 4678 Client *s = swallowingclient(c->win); 4679 if (s) { 4680 free(s->swallowing); 4681 s->swallowing = NULL; 4682 arrange(m); 4683 focus(NULL); 4684 return; 4685 } 4686 #endif // SWALLOW_PATCH 4687 4688 detach(c); 4689 detachstack(c); 4690 #if BAR_WINICON_PATCH 4691 freeicon(c); 4692 #endif // BAR_WINICON_PATCH 4693 if (!destroyed) { 4694 wc.border_width = c->oldbw; 4695 XGrabServer(dpy); /* avoid race conditions */ 4696 XSetErrorHandler(xerrordummy); 4697 XSelectInput(dpy, c->win, NoEventMask); 4698 XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ 4699 XUngrabButton(dpy, AnyButton, AnyModifier, c->win); 4700 if (!HIDDEN(c)) 4701 setclientstate(c, WithdrawnState); 4702 XSync(dpy, False); 4703 XSetErrorHandler(xerror); 4704 XUngrabServer(dpy); 4705 } 4706 #if XKB_PATCH 4707 else { 4708 xkb = findxkb(c->win); 4709 if (xkb != NULL) { 4710 if (xkb->prev) 4711 xkb->prev->next = xkb->next; 4712 if (xkb->next) 4713 xkb->next->prev = xkb->prev; 4714 free(xkb); 4715 } 4716 } 4717 #endif // XKB_PATCH 4718 4719 #if SCRATCHPAD_ALT_1_PATCH 4720 if (scratchpad_last_showed == c) 4721 scratchpad_last_showed = NULL; 4722 #endif // SCRATCHPAD_ALT_1_PATCH 4723 4724 free(c); 4725 #if SWALLOW_PATCH 4726 if (s) 4727 return; 4728 #endif // SWALLOW_PATCH 4729 arrange(m); 4730 focus(NULL); 4731 updateclientlist(); 4732 #if SWITCHTAG_PATCH 4733 if (switchtag && ((switchtag & TAGMASK) != selmon->tagset[selmon->seltags])) 4734 view(&((Arg) { .ui = switchtag })); 4735 #endif // SWITCHTAG_PATCH 4736 } 4737 4738 void 4739 unmapnotify(XEvent *e) 4740 { 4741 Client *c; 4742 #if BAR_ANYBAR_PATCH 4743 Monitor *m; 4744 Bar *bar; 4745 #endif // BAR_ANYBAR_PATCH 4746 XUnmapEvent *ev = &e->xunmap; 4747 4748 if ((c = wintoclient(ev->window))) { 4749 if (ev->send_event) 4750 setclientstate(c, WithdrawnState); 4751 else 4752 unmanage(c, 0); 4753 #if BAR_SYSTRAY_PATCH 4754 } else if (showsystray && (c = wintosystrayicon(ev->window))) { 4755 /* KLUDGE! sometimes icons occasionally unmap their windows, but do 4756 * _not_ destroy them. We map those windows back */ 4757 XMapRaised(dpy, c->win); 4758 removesystrayicon(c); 4759 drawbarwin(systray->bar); 4760 #endif // BAR_SYSTRAY_PATCH 4761 } 4762 #if BAR_ANYBAR_PATCH 4763 else { 4764 m = wintomon(ev->window); 4765 for (bar = m->bar; bar; bar = bar->next) { 4766 if (bar->win == ev->window) { 4767 unmanagealtbar(ev->window); 4768 break; 4769 } 4770 } 4771 } 4772 #endif // BAR_ANYBAR_PATCH 4773 } 4774 4775 void 4776 updatebars(void) 4777 { 4778 Bar *bar; 4779 Monitor *m; 4780 XSetWindowAttributes wa = { 4781 .override_redirect = True, 4782 #if BAR_ALPHA_PATCH 4783 .background_pixel = 0, 4784 .border_pixel = 0, 4785 .colormap = cmap, 4786 #else 4787 .background_pixmap = ParentRelative, 4788 #endif // BAR_ALPHA_PATCH 4789 #if BAR_TAGPREVIEW_PATCH 4790 .event_mask = ButtonPressMask|ExposureMask|PointerMotionMask 4791 #else 4792 .event_mask = ButtonPressMask|ExposureMask 4793 #endif // BAR_TAGPREVIEW_PATCH 4794 }; 4795 XClassHint ch = {"dwm", "dwm"}; 4796 for (m = mons; m; m = m->next) { 4797 for (bar = m->bar; bar; bar = bar->next) { 4798 if (bar->external) 4799 continue; 4800 if (!bar->win) { 4801 #if BAR_ALPHA_PATCH 4802 bar->win = XCreateWindow(dpy, root, bar->bx, bar->by, bar->bw, bar->bh, 0, depth, 4803 InputOutput, visual, 4804 CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa); 4805 #else 4806 bar->win = XCreateWindow(dpy, root, bar->bx, bar->by, bar->bw, bar->bh, 0, DefaultDepth(dpy, screen), 4807 CopyFromParent, DefaultVisual(dpy, screen), 4808 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); 4809 #endif // BAR_ALPHA_PATCH 4810 XDefineCursor(dpy, bar->win, cursor[CurNormal]->cursor); 4811 XMapRaised(dpy, bar->win); 4812 XSetClassHint(dpy, bar->win, &ch); 4813 } 4814 } 4815 #if TAB_PATCH 4816 if (!m->tabwin) { 4817 #if BAR_ALPHA_PATCH 4818 m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, depth, 4819 InputOutput, visual, 4820 CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa); 4821 #else 4822 m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen), 4823 CopyFromParent, DefaultVisual(dpy, screen), 4824 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); 4825 #endif // BAR_ALPHA_PATCH 4826 XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor); 4827 XMapRaised(dpy, m->tabwin); 4828 } 4829 #endif // TAB_PATCH 4830 } 4831 } 4832 4833 void 4834 updatebarpos(Monitor *m) 4835 { 4836 #if TAB_PATCH 4837 Client *c; 4838 int nvis = 0; 4839 #endif // TAB_PATCH 4840 4841 m->wx = m->mx; 4842 m->wy = m->my; 4843 m->ww = m->mw; 4844 m->wh = m->mh; 4845 Bar *bar; 4846 int y_pad = 0; 4847 int x_pad = 0; 4848 #if BAR_PADDING_VANITYGAPS_PATCH && VANITYGAPS_PATCH 4849 #if PERTAG_VANITYGAPS_PATCH && PERTAG_PATCH 4850 if (!selmon || selmon->pertag->enablegaps[selmon->pertag->curtag]) 4851 #elif PERMON_VANITYGAPS_PATCH 4852 if (!selmon || selmon->enablegaps) 4853 #else 4854 if (enablegaps) 4855 #endif // PERTAG_VANITYGAPS_PATCH 4856 { 4857 #if BAR_PADDING_SMART_PATCH 4858 unsigned int n; Client *c; 4859 for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); 4860 if (n > 1) { 4861 y_pad = gappoh; 4862 x_pad = gappov; 4863 } 4864 #else 4865 y_pad = gappoh; 4866 x_pad = gappov; 4867 #endif // BAR_PADDING_SMART_PATCH 4868 } 4869 #elif BAR_PADDING_PATCH 4870 #if BAR_PADDING_SMART_PATCH 4871 unsigned int n; Client *c; 4872 for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); 4873 if (n > 1) { 4874 y_pad = vertpad; 4875 x_pad = sidepad; 4876 } 4877 #else 4878 y_pad = vertpad; 4879 x_pad = sidepad; 4880 #endif // BAR_PADDING_SMART_PATCH 4881 #endif // BAR_PADDING_PATCH | BAR_PADDING_VANITYGAPS_PATCH 4882 4883 #if INSETS_PATCH 4884 // Custom insets 4885 Inset inset = m->inset; 4886 m->wx += inset.x; 4887 m->wy += inset.y; 4888 m->ww -= inset.w + inset.x; 4889 m->wh -= inset.h + inset.y; 4890 #endif // INSETS_PATCH 4891 4892 for (bar = m->bar; bar; bar = bar->next) { 4893 bar->bx = m->wx + x_pad; 4894 #if BAR_ANYBAR_PATCH && !BAR_ANYBAR_MANAGE_WIDTH_PATCH 4895 if (bar->external) 4896 continue; 4897 #endif // BAR_ANYBAR_PATCH | BAR_ANYBAR_MANAGE_WIDTH_PATCH 4898 bar->bw = m->ww - 2 * x_pad; 4899 } 4900 4901 for (bar = m->bar; bar; bar = bar->next) 4902 if (!m->showbar || !bar->showbar) 4903 bar->by = -bar->bh - y_pad; 4904 4905 #if TAB_PATCH 4906 for (c = m->clients; c; c = c->next) { 4907 if (ISVISIBLE(c) && !HIDDEN(c)) 4908 ++nvis; 4909 } 4910 4911 if (m->showtab == showtab_always 4912 || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))) { 4913 m->wh -= th; 4914 m->ty = m->toptab ? m->wy : m->wy + m->wh; 4915 if (m->toptab) 4916 m->wy += th; 4917 } else { 4918 m->ty = -th; 4919 } 4920 #endif // TAB_PATCH 4921 4922 if (!m->showbar) 4923 return; 4924 for (bar = m->bar; bar; bar = bar->next) { 4925 if (!bar->showbar) 4926 continue; 4927 #if BAR_HOLDBAR_PATCH 4928 if (m->showbar == 2) { 4929 bar->by = (bar->topbar ? m->wy : m->wy + m->wh - bar->bh); 4930 continue; 4931 } 4932 #endif // BAR_HOLDBAR_PATCH 4933 if (bar->topbar) 4934 m->wy = m->wy + bar->bh + y_pad; 4935 m->wh -= y_pad + bar->bh; 4936 bar->by = (bar->topbar ? m->wy - bar->bh : m->wy + m->wh); 4937 } 4938 } 4939 4940 void 4941 updateclientlist(void) 4942 { 4943 Client *c; 4944 Monitor *m; 4945 4946 XDeleteProperty(dpy, root, netatom[NetClientList]); 4947 for (m = mons; m; m = m->next) 4948 for (c = m->clients; c; c = c->next) 4949 XChangeProperty(dpy, root, netatom[NetClientList], 4950 XA_WINDOW, 32, PropModeAppend, 4951 (unsigned char *) &(c->win), 1); 4952 4953 #if NET_CLIENT_LIST_STACKING_PATCH 4954 XDeleteProperty(dpy, root, netatom[NetClientListStacking]); 4955 for (m = mons; m; m = m->next) 4956 for (c = m->stack; c; c = c->snext) 4957 XChangeProperty(dpy, root, netatom[NetClientListStacking], 4958 XA_WINDOW, 32, PropModeAppend, 4959 (unsigned char *) &(c->win), 1); 4960 #endif // NET_CLIENT_LIST_STACKING_PATCH 4961 } 4962 4963 int 4964 updategeom(void) 4965 { 4966 int dirty = 0; 4967 4968 #ifdef XINERAMA 4969 if (XineramaIsActive(dpy)) { 4970 int i, j, n, nn; 4971 Client *c; 4972 Monitor *m; 4973 XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn); 4974 XineramaScreenInfo *unique = NULL; 4975 4976 for (n = 0, m = mons; m; m = m->next, n++); 4977 /* only consider unique geometries as separate screens */ 4978 unique = ecalloc(nn, sizeof(XineramaScreenInfo)); 4979 for (i = 0, j = 0; i < nn; i++) 4980 if (isuniquegeom(unique, j, &info[i])) 4981 memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo)); 4982 XFree(info); 4983 nn = j; 4984 #if SORTSCREENS_PATCH 4985 sortscreens(unique, nn); 4986 #endif // SORTSCREENS_PATCH 4987 /* new monitors if nn > n */ 4988 for (i = n; i < nn; i++) { 4989 for (m = mons; m && m->next; m = m->next); 4990 if (m) 4991 m->next = createmon(); 4992 else 4993 mons = createmon(); 4994 } 4995 for (i = 0, m = mons; i < nn && m; m = m->next, i++) 4996 if (i >= n 4997 || unique[i].x_org != m->mx || unique[i].y_org != m->my 4998 || unique[i].width != m->mw || unique[i].height != m->mh) 4999 { 5000 dirty = 1; 5001 m->num = i; 5002 m->mx = m->wx = unique[i].x_org; 5003 m->my = m->wy = unique[i].y_org; 5004 m->mw = m->ww = unique[i].width; 5005 m->mh = m->wh = unique[i].height; 5006 updatebarpos(m); 5007 } 5008 /* removed monitors if n > nn */ 5009 for (i = nn; i < n; i++) { 5010 for (m = mons; m && m->next; m = m->next); 5011 while ((c = m->clients)) { 5012 dirty = 1; 5013 m->clients = c->next; 5014 detachstack(c); 5015 c->mon = mons; 5016 attach(c); 5017 attachstack(c); 5018 } 5019 if (m == selmon) 5020 selmon = mons; 5021 cleanupmon(m); 5022 } 5023 free(unique); 5024 } else 5025 #endif /* XINERAMA */ 5026 { /* default monitor setup */ 5027 if (!mons) 5028 mons = createmon(); 5029 if (mons->mw != sw || mons->mh != sh) { 5030 dirty = 1; 5031 mons->mw = mons->ww = sw; 5032 mons->mh = mons->wh = sh; 5033 updatebarpos(mons); 5034 } 5035 } 5036 if (dirty) { 5037 selmon = mons; 5038 selmon = wintomon(root); 5039 } 5040 return dirty; 5041 } 5042 5043 void 5044 updatenumlockmask(void) 5045 { 5046 unsigned int i, j; 5047 XModifierKeymap *modmap; 5048 5049 numlockmask = 0; 5050 modmap = XGetModifierMapping(dpy); 5051 for (i = 0; i < 8; i++) 5052 for (j = 0; j < modmap->max_keypermod; j++) 5053 if (modmap->modifiermap[i * modmap->max_keypermod + j] 5054 == XKeysymToKeycode(dpy, XK_Num_Lock)) 5055 numlockmask = (1 << i); 5056 XFreeModifiermap(modmap); 5057 } 5058 5059 void 5060 updatesizehints(Client *c) 5061 { 5062 long msize; 5063 XSizeHints size; 5064 5065 if (!XGetWMNormalHints(dpy, c->win, &size, &msize)) 5066 /* size is uninitialized, ensure that size.flags aren't used */ 5067 #if SIZEHINTS_PATCH || SIZEHINTS_RULED_PATCH || SIZEHINTS_ISFREESIZE_PATCH 5068 size.flags = 0; 5069 #else 5070 size.flags = PSize; 5071 #endif // SIZEHINTS_PATCH | SIZEHINTS_RULED_PATCH | SIZEHINTS_ISFREESIZE_PATCH 5072 if (size.flags & PBaseSize) { 5073 c->basew = size.base_width; 5074 c->baseh = size.base_height; 5075 } else if (size.flags & PMinSize) { 5076 c->basew = size.min_width; 5077 c->baseh = size.min_height; 5078 } else 5079 c->basew = c->baseh = 0; 5080 if (size.flags & PResizeInc) { 5081 c->incw = size.width_inc; 5082 c->inch = size.height_inc; 5083 } else 5084 c->incw = c->inch = 0; 5085 if (size.flags & PMaxSize) { 5086 c->maxw = size.max_width; 5087 c->maxh = size.max_height; 5088 } else 5089 c->maxw = c->maxh = 0; 5090 if (size.flags & PMinSize) { 5091 c->minw = size.min_width; 5092 c->minh = size.min_height; 5093 } else if (size.flags & PBaseSize) { 5094 c->minw = size.base_width; 5095 c->minh = size.base_height; 5096 } else 5097 c->minw = c->minh = 0; 5098 if (size.flags & PAspect) { 5099 c->mina = (float)size.min_aspect.y / size.min_aspect.x; 5100 c->maxa = (float)size.max_aspect.x / size.max_aspect.y; 5101 } else 5102 c->maxa = c->mina = 0.0; 5103 #if SIZEHINTS_PATCH || SIZEHINTS_RULED_PATCH || SIZEHINTS_ISFREESIZE_PATCH 5104 #if SIZEHINTS_ISFREESIZE_PATCH 5105 if ((size.flags & PSize) && c->isfreesize) 5106 #else 5107 if (size.flags & PSize) 5108 #endif // SIZEHINTS_ISFREESIZE_PATCH 5109 { 5110 c->basew = size.base_width; 5111 c->baseh = size.base_height; 5112 c->isfloating = 1; 5113 } 5114 #if SIZEHINTS_RULED_PATCH 5115 checkfloatingrules(c); 5116 #endif // SIZEHINTS_RULED_PATCH 5117 #endif // SIZEHINTS_PATCH 5118 c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); 5119 c->hintsvalid = 1; 5120 } 5121 5122 void 5123 updatestatus(void) 5124 { 5125 Monitor *m; 5126 #if BAR_EXTRASTATUS_PATCH 5127 if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) { 5128 strcpy(stext, "dwm-"VERSION); 5129 estext[0] = '\0'; 5130 } else { 5131 char *e = strchr(rawstext, statussep); 5132 if (e) { 5133 *e = '\0'; e++; 5134 #if BAR_STATUSCMD_PATCH 5135 strncpy(rawestext, e, sizeof(estext) - 1); 5136 copyvalidchars(estext, rawestext); 5137 #else 5138 strncpy(estext, e, sizeof(estext) - 1); 5139 #endif // BAR_STATUSCMD_PATCH 5140 } else { 5141 estext[0] = '\0'; 5142 } 5143 #if BAR_STATUSCMD_PATCH 5144 copyvalidchars(stext, rawstext); 5145 #else 5146 strncpy(stext, rawstext, sizeof(stext) - 1); 5147 #endif // BAR_STATUSCMD_PATCH 5148 } 5149 #elif BAR_STATUSCMD_PATCH 5150 if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) 5151 strcpy(stext, "dwm-"VERSION); 5152 else 5153 copyvalidchars(stext, rawstext); 5154 #else 5155 if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) 5156 strcpy(stext, "dwm-"VERSION); 5157 #endif // BAR_EXTRASTATUS_PATCH | BAR_STATUSCMD_PATCH 5158 for (m = mons; m; m = m->next) 5159 drawbar(m); 5160 } 5161 5162 void 5163 updatetitle(Client *c) 5164 { 5165 #if IPC_PATCH 5166 char oldname[sizeof(c->name)]; 5167 strcpy(oldname, c->name); 5168 #endif // IPC_PATCH 5169 5170 if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) 5171 gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); 5172 if (c->name[0] == '\0') /* hack to mark broken clients */ 5173 strcpy(c->name, broken); 5174 5175 #if IPC_PATCH 5176 for (Monitor *m = mons; m; m = m->next) { 5177 if (m->sel == c && strcmp(oldname, c->name) != 0) 5178 ipc_focused_title_change_event(m->num, c->win, oldname, c->name); 5179 } 5180 #endif // IPC_PATCH 5181 } 5182 5183 void 5184 updatewmhints(Client *c) 5185 { 5186 XWMHints *wmh; 5187 5188 if ((wmh = XGetWMHints(dpy, c->win))) { 5189 if (c == selmon->sel && wmh->flags & XUrgencyHint) { 5190 wmh->flags &= ~XUrgencyHint; 5191 XSetWMHints(dpy, c->win, wmh); 5192 } else 5193 c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0; 5194 if (c->isurgent) { 5195 if (c->isfloating) 5196 XSetWindowBorder(dpy, c->win, scheme[SchemeUrg][ColFloat].pixel); 5197 else 5198 XSetWindowBorder(dpy, c->win, scheme[SchemeUrg][ColBorder].pixel); 5199 } 5200 if (wmh->flags & InputHint) 5201 c->neverfocus = !wmh->input; 5202 else 5203 c->neverfocus = 0; 5204 XFree(wmh); 5205 } 5206 } 5207 5208 void 5209 view(const Arg *arg) 5210 { 5211 #if TAGSYNC_PATCH 5212 Monitor *origselmon = selmon; 5213 for (selmon = mons; selmon; selmon = selmon->next) { 5214 #endif // TAGSYNC_PATCH 5215 #if EMPTYVIEW_PATCH 5216 if (arg->ui && (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) 5217 #else 5218 if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) 5219 #endif // EMPTYVIEW_PATCH 5220 { 5221 #if TOGGLETAG_PATCH 5222 view(&((Arg) { .ui = 0 })); 5223 #endif // TOGGLETAG_PATCH 5224 return; 5225 } 5226 #if BAR_TAGPREVIEW_PATCH 5227 tagpreviewswitchtag(); 5228 #endif // BAR_TAGPREVIEW_PATCH 5229 #if VIEW_HISTORY_PATCH 5230 if (!arg->ui) { 5231 selmon->seltags += 1; 5232 if (selmon->seltags == LENGTH(selmon->tagset)) 5233 selmon->seltags = 0; 5234 } else { 5235 if (selmon->seltags == 0) 5236 selmon->seltags = LENGTH(selmon->tagset) - 1; 5237 else 5238 selmon->seltags -= 1; 5239 } 5240 #else 5241 selmon->seltags ^= 1; /* toggle sel tagset */ 5242 #endif // VIEW_HISTORY_PATCH 5243 if (arg->ui & TAGMASK) 5244 selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; 5245 #if PERTAG_PATCH 5246 pertagview(arg); 5247 #endif // PERTAG_PATCH 5248 #if TAGSYNC_PATCH 5249 } 5250 selmon = origselmon; 5251 #endif // TAGSYNC_PATCH 5252 #if TAGSYNC_PATCH 5253 arrange(NULL); 5254 #else 5255 arrange(selmon); 5256 #endif // TAGSYNC_PATCH 5257 focus(NULL); 5258 #if BAR_EWMHTAGS_PATCH 5259 updatecurrentdesktop(); 5260 #endif // BAR_EWMHTAGS_PATCH 5261 } 5262 5263 Client * 5264 wintoclient(Window w) 5265 { 5266 Client *c; 5267 Monitor *m; 5268 5269 for (m = mons; m; m = m->next) 5270 for (c = m->clients; c; c = c->next) 5271 if (c->win == w) 5272 return c; 5273 return NULL; 5274 } 5275 5276 Monitor * 5277 wintomon(Window w) 5278 { 5279 int x, y; 5280 Client *c; 5281 Monitor *m; 5282 Bar *bar; 5283 5284 if (w == root && getrootptr(&x, &y)) 5285 return recttomon(x, y, 1, 1); 5286 for (m = mons; m; m = m->next) 5287 for (bar = m->bar; bar; bar = bar->next) 5288 if (w == bar->win) 5289 return m; 5290 if ((c = wintoclient(w))) 5291 return c->mon; 5292 return selmon; 5293 } 5294 5295 /* There's no way to check accesses to destroyed windows, thus those cases are 5296 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs 5297 * default error handler, which may call exit. */ 5298 int 5299 xerror(Display *dpy, XErrorEvent *ee) 5300 { 5301 if (ee->error_code == BadWindow 5302 || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) 5303 || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) 5304 || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable) 5305 || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) 5306 || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) 5307 || (ee->request_code == X_GrabButton && ee->error_code == BadAccess) 5308 || (ee->request_code == X_GrabKey && ee->error_code == BadAccess) 5309 || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) 5310 return 0; 5311 fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", 5312 ee->request_code, ee->error_code); 5313 return xerrorxlib(dpy, ee); /* may call exit */ 5314 } 5315 5316 int 5317 xerrordummy(Display *dpy, XErrorEvent *ee) 5318 { 5319 return 0; 5320 } 5321 5322 /* Startup Error handler to check if another window manager 5323 * is already running. */ 5324 int 5325 xerrorstart(Display *dpy, XErrorEvent *ee) 5326 { 5327 die("dwm: another window manager is already running"); 5328 return -1; 5329 } 5330 5331 void 5332 zoom(const Arg *arg) 5333 { 5334 Client *c = selmon->sel; 5335 #if FOCUSMASTER_RETURN_PATCH && ZOOMSWAP_PATCH 5336 int i; 5337 #endif // FOCUSMASTER_RETURN_PATCH 5338 if (arg && arg->v) 5339 c = (Client*)arg->v; 5340 if (!c) 5341 return; 5342 #if ZOOMSWAP_PATCH 5343 Client *at = NULL, *cold, *cprevious = NULL, *p; 5344 #endif // ZOOMSWAP_PATCH 5345 5346 #if ZOOMFLOATING_PATCH 5347 if (c && c->isfloating) 5348 togglefloating(&((Arg) { .v = c })); 5349 #endif // ZOOMFLOATING_PATCH 5350 5351 #if SWAPFOCUS_PATCH && PERTAG_PATCH 5352 c->mon->pertag->prevclient[c->mon->pertag->curtag] = nexttiled(c->mon->clients); 5353 #endif // SWAPFOCUS_PATCH 5354 5355 if (!c->mon->lt[c->mon->sellt]->arrange || !c || c->isfloating) 5356 return; 5357 5358 #if ZOOMSWAP_PATCH 5359 if (c == nexttiled(c->mon->clients)) { 5360 #if PERTAG_PATCH 5361 p = c->mon->pertag->prevzooms[c->mon->pertag->curtag]; 5362 #else 5363 p = prevzoom; 5364 #endif // PERTAG_PATCH 5365 at = findbefore(p); 5366 if (at) 5367 cprevious = nexttiled(at->next); 5368 if (!cprevious || cprevious != p) { 5369 #if PERTAG_PATCH 5370 c->mon->pertag->prevzooms[c->mon->pertag->curtag] = NULL; 5371 #else 5372 prevzoom = NULL; 5373 #endif // PERTAG_PATCH 5374 #if SWAPFOCUS_PATCH && PERTAG_PATCH 5375 if (!c || !(c = c->mon->pertag->prevclient[c->mon->pertag->curtag] = nexttiled(c->next))) 5376 #else 5377 if (!c || !(c = nexttiled(c->next))) 5378 #endif // SWAPFOCUS_PATCH 5379 return; 5380 } else 5381 #if SWAPFOCUS_PATCH && PERTAG_PATCH 5382 c = c->mon->pertag->prevclient[c->mon->pertag->curtag] = cprevious; 5383 #else 5384 c = cprevious; 5385 #endif // SWAPFOCUS_PATCH 5386 } 5387 5388 cold = nexttiled(c->mon->clients); 5389 if (c != cold && !at) 5390 at = findbefore(c); 5391 #if FOCUSMASTER_RETURN_PATCH 5392 for (i = 0; !(selmon->tagset[selmon->seltags] & 1 << i); i++); 5393 i++; 5394 5395 c->mon->tagmarked[i] = cold; 5396 #endif // FOCUSMASTER_RETURN_PATCH 5397 detach(c); 5398 attach(c); 5399 /* swap windows instead of pushing the previous one down */ 5400 if (c != cold && at) { 5401 #if PERTAG_PATCH 5402 c->mon->pertag->prevzooms[c->mon->pertag->curtag] = cold; 5403 #else 5404 prevzoom = cold; 5405 #endif // PERTAG_PATCH 5406 if (cold && at != cold) { 5407 detach(cold); 5408 cold->next = at->next; 5409 at->next = cold; 5410 } 5411 } 5412 focus(c); 5413 arrange(c->mon); 5414 #elif SWAPFOCUS_PATCH && PERTAG_PATCH 5415 if (c == nexttiled(c->mon->clients) && !(c = c->mon->pertag->prevclient[c->mon->pertag->curtag] = nexttiled(c->next))) 5416 return; 5417 pop(c); 5418 #else 5419 if (c == nexttiled(selmon->clients) && !(c = nexttiled(c->next))) 5420 return; 5421 pop(c); 5422 #endif // ZOOMSWAP_PATCH 5423 } 5424 5425 int 5426 main(int argc, char *argv[]) 5427 { 5428 #if CMDCUSTOMIZE_PATCH 5429 for (int i=1;i<argc;i+=1) 5430 if (!strcmp("-v", argv[i])) 5431 die("dwm-"VERSION); 5432 else if (!strcmp("-h", argv[i]) || !strcmp("--help", argv[i])) 5433 die(help()); 5434 else if (!strcmp("-fn", argv[i])) /* font set */ 5435 #if BAR_PANGO_PATCH 5436 strcpy(font, argv[++i]); 5437 #else 5438 fonts[0] = argv[++i]; 5439 #endif // BAR_PANGO_PATCH 5440 #if !BAR_VTCOLORS_PATCH 5441 else if (!strcmp("-nb", argv[i])) /* normal background color */ 5442 colors[SchemeNorm][1] = argv[++i]; 5443 else if (!strcmp("-nf", argv[i])) /* normal foreground color */ 5444 colors[SchemeNorm][0] = argv[++i]; 5445 else if (!strcmp("-sb", argv[i])) /* selected background color */ 5446 colors[SchemeSel][1] = argv[++i]; 5447 else if (!strcmp("-sf", argv[i])) /* selected foreground color */ 5448 colors[SchemeSel][0] = argv[++i]; 5449 #endif // !BAR_VTCOLORS_PATCH 5450 #if NODMENU_PATCH 5451 else if (!strcmp("-df", argv[i])) /* dmenu font */ 5452 dmenucmd[2] = argv[++i]; 5453 else if (!strcmp("-dnb", argv[i])) /* dmenu normal background color */ 5454 dmenucmd[4] = argv[++i]; 5455 else if (!strcmp("-dnf", argv[i])) /* dmenu normal foreground color */ 5456 dmenucmd[6] = argv[++i]; 5457 else if (!strcmp("-dsb", argv[i])) /* dmenu selected background color */ 5458 dmenucmd[8] = argv[++i]; 5459 else if (!strcmp("-dsf", argv[i])) /* dmenu selected foreground color */ 5460 dmenucmd[10] = argv[++i]; 5461 #else 5462 else if (!strcmp("-df", argv[i])) /* dmenu font */ 5463 dmenucmd[4] = argv[++i]; 5464 else if (!strcmp("-dnb", argv[i])) /* dmenu normal background color */ 5465 dmenucmd[6] = argv[++i]; 5466 else if (!strcmp("-dnf", argv[i])) /* dmenu normal foreground color */ 5467 dmenucmd[8] = argv[++i]; 5468 else if (!strcmp("-dsb", argv[i])) /* dmenu selected background color */ 5469 dmenucmd[10] = argv[++i]; 5470 else if (!strcmp("-dsf", argv[i])) /* dmenu selected foreground color */ 5471 dmenucmd[12] = argv[++i]; 5472 #endif // NODMENU_PATCH 5473 else die(help()); 5474 #else 5475 if (argc == 2 && !strcmp("-v", argv[1])) 5476 die("dwm-"VERSION); 5477 else if (argc != 1) 5478 die("usage: dwm [-v]"); 5479 #endif // CMDCUSTOMIZE_PATCH 5480 if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) 5481 fputs("warning: no locale support\n", stderr); 5482 if (!(dpy = XOpenDisplay(NULL))) 5483 die("dwm: cannot open display"); 5484 #if SWALLOW_PATCH 5485 if (!(xcon = XGetXCBConnection(dpy))) 5486 die("dwm: cannot get xcb connection\n"); 5487 #endif // SWALLOW_PATCH 5488 checkotherwm(); 5489 #if XRESOURCES_PATCH || XRDB_PATCH 5490 XrmInitialize(); 5491 load_xresources(); 5492 #endif // XRESOURCES_PATCH | XRDB_PATCH 5493 #if COOL_AUTOSTART_PATCH 5494 autostart_exec(); 5495 #endif // COOL_AUTOSTART_PATCH 5496 setup(); 5497 #ifdef __OpenBSD__ 5498 #if SWALLOW_PATCH 5499 if (pledge("stdio rpath proc exec ps", NULL) == -1) 5500 #else 5501 if (pledge("stdio rpath proc exec", NULL) == -1) 5502 #endif // SWALLOW_PATCH 5503 die("pledge"); 5504 #endif /* __OpenBSD__ */ 5505 scan(); 5506 #if AUTOSTART_PATCH 5507 runautostart(); 5508 #endif 5509 run(); 5510 cleanup(); 5511 XCloseDisplay(dpy); 5512 #if RESTARTSIG_PATCH 5513 if (restart) 5514 execvp(argv[0], argv); 5515 #endif // RESTARTSIG_PATCH 5516 return EXIT_SUCCESS; 5517 } 5518