dwm-6.1-single_tagset.diff (16634B)
1 Author: Jan Christoph Ebersbach <jceb@e-jc.de> 2 URL: http://dwm.suckless.org/patches/single_tagset 3 This patch addresses the multi-monitor setup. Instead of having separate tags 4 for every monitor there is just one list of tags for all monitors. Instead of 5 moving windows from one monitor to the other, the desired tag from the 6 other monitor can just be selected and all windows will be drawn on the 7 current monitor. 8 9 Several deep changes needed to be made: 10 1. Macro ISVISIBLE expects a second parameter, the monitor 11 2. Monitor->clients and Monitor->stack were moved to the global variable 12 Clientlist cl. All monitors refer to this one list. 13 3. A new method attachclients was added. When changing between tags this 14 function ensures that all clients are pointing to the right monitor. 15 16 Please be aware that this patch probably breaks any other patch! 17 18 Index: dwm/dwm.c 19 =================================================================== 20 --- dwm/dwm.c.orig 2014-02-09 15:24:26.156117354 +0100 21 +++ dwm/dwm.c 2014-02-09 15:24:26.148117354 +0100 22 @@ -48,7 +48,7 @@ 23 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) 24 #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ 25 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) 26 -#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) 27 +#define ISVISIBLE(C, M) ((C->tags & M->tagset[M->seltags])) 28 #define LENGTH(X) (sizeof X / sizeof X[0]) 29 #define MOUSEMASK (BUTTONMASK|PointerMotionMask) 30 #define WIDTH(X) ((X)->w + 2 * (X)->bw) 31 @@ -110,6 +110,7 @@ 32 void (*arrange)(Monitor *); 33 } Layout; 34 35 +typedef struct Clientlist Clientlist; 36 struct Monitor { 37 char ltsymbol[16]; 38 float mfact; 39 @@ -123,9 +124,8 @@ 40 unsigned int tagset[2]; 41 Bool showbar; 42 Bool topbar; 43 - Client *clients; 44 + Clientlist *cl; 45 Client *sel; 46 - Client *stack; 47 Monitor *next; 48 Window barwin; 49 const Layout *lt[2]; 50 @@ -140,12 +140,18 @@ 51 int monitor; 52 } Rule; 53 54 +struct Clientlist { 55 + Client *clients; 56 + Client *stack; 57 +}; 58 + 59 /* function declarations */ 60 static void applyrules(Client *c); 61 static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact); 62 static void arrange(Monitor *m); 63 static void arrangemon(Monitor *m); 64 static void attach(Client *c); 65 +static void attachclients(Monitor *m); 66 static void attachstack(Client *c); 67 static void buttonpress(XEvent *e); 68 static void checkotherwm(void); 69 @@ -183,7 +189,7 @@ 70 static void monocle(Monitor *m); 71 static void motionnotify(XEvent *e); 72 static void movemouse(const Arg *arg); 73 -static Client *nexttiled(Client *c); 74 +static Client *nexttiled(Client *c, Monitor *m); 75 static void pop(Client *); 76 static void propertynotify(XEvent *e); 77 static void quit(const Arg *arg); 78 @@ -266,6 +272,7 @@ 79 static Fnt *fnt; 80 static Monitor *mons, *selmon; 81 static Window root; 82 +static Clientlist *cl; 83 84 /* configuration, allows nested code to access above variables */ 85 #include "config.h" 86 @@ -296,7 +303,7 @@ 87 { 88 c->isfloating = r->isfloating; 89 c->tags |= r->tags; 90 - for(m = mons; m && m->num != r->monitor; m = m->next); 91 + for(m = mons; m && (m->tagset[m->seltags] & c->tags) == 0; m = m->next) ; 92 if(m) 93 c->mon = m; 94 } 95 @@ -377,9 +384,9 @@ 96 void 97 arrange(Monitor *m) { 98 if(m) 99 - showhide(m->stack); 100 + showhide(m->cl->stack); 101 else for(m = mons; m; m = m->next) 102 - showhide(m->stack); 103 + showhide(m->cl->stack); 104 if(m) { 105 arrangemon(m); 106 restack(m); 107 @@ -396,14 +403,47 @@ 108 109 void 110 attach(Client *c) { 111 - c->next = c->mon->clients; 112 - c->mon->clients = c; 113 + c->next = c->mon->cl->clients; 114 + c->mon->cl->clients = c; 115 +} 116 + 117 +void 118 +attachclients(Monitor *m) { 119 + /* attach clients to the specified monitor */ 120 + Monitor *tm; 121 + Client *c; 122 + unsigned int utags = 0; 123 + Bool rmons = False; 124 + if(!m) 125 + return; 126 + 127 + /* collect information about the tags in use */ 128 + for(tm = mons; tm; tm = tm->next) 129 + if(tm != m) 130 + utags |= m->tagset[m->seltags]; 131 + 132 + for(c = m->cl->clients; c; c = c->next) 133 + if(ISVISIBLE(c, m)) { 134 + /* if client is also visible on other tags that are displayed on 135 + * other monitors, remove these tags */ 136 + if(c->tags & utags) { 137 + c->tags = c->tags & m->tagset[m->seltags]; 138 + rmons = True; 139 + } 140 + unfocus(c, True); 141 + c->mon = m; 142 + } 143 + 144 + if(rmons) 145 + for(tm = mons; tm; tm = tm->next) 146 + if(tm != m) 147 + arrange(tm); 148 } 149 150 void 151 attachstack(Client *c) { 152 - c->snext = c->mon->stack; 153 - c->mon->stack = c; 154 + c->snext = c->mon->cl->stack; 155 + c->mon->cl->stack = c; 156 } 157 158 void 159 @@ -466,8 +506,8 @@ 160 view(&a); 161 selmon->lt[selmon->sellt] = &foo; 162 for(m = mons; m; m = m->next) 163 - while(m->stack) 164 - unmanage(m->stack, False); 165 + while(m->cl->stack) 166 + unmanage(m->cl->stack, False); 167 XUngrabKey(dpy, AnyKey, AnyModifier, root); 168 while(mons) 169 cleanupmon(mons); 170 @@ -527,7 +567,7 @@ 171 || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); 172 } 173 else if(cme->message_type == netatom[NetActiveWindow]) { 174 - if(!ISVISIBLE(c)) { 175 + if(!ISVISIBLE(c, c->mon)) { 176 c->mon->seltags ^= 1; 177 c->mon->tagset[c->mon->seltags] = c->tags; 178 } 179 @@ -609,7 +649,7 @@ 180 c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */ 181 if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) 182 configure(c); 183 - if(ISVISIBLE(c)) 184 + if(ISVISIBLE(c, m)) 185 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); 186 } 187 else 188 @@ -630,11 +670,18 @@ 189 190 Monitor * 191 createmon(void) { 192 - Monitor *m; 193 + Monitor *m, *tm; 194 + int i; 195 196 if(!(m = (Monitor *)calloc(1, sizeof(Monitor)))) 197 die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); 198 - m->tagset[0] = m->tagset[1] = 1; 199 + m->cl = cl; 200 + /* reassing tags when creating a new monitor */ 201 + for(i=1, tm = mons; tm; tm = tm->next, i++) { 202 + tm->seltags ^= 1; 203 + tm->tagset[tm->seltags] = i; 204 + } 205 + m->tagset[0] = m->tagset[1] = i; 206 m->mfact = mfact; 207 m->nmaster = nmaster; 208 m->showbar = showbar; 209 @@ -658,7 +705,7 @@ 210 detach(Client *c) { 211 Client **tc; 212 213 - for(tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next); 214 + for(tc = &c->mon->cl->clients; *tc && *tc != c; tc = &(*tc)->next); 215 *tc = c->next; 216 } 217 218 @@ -666,11 +713,11 @@ 219 detachstack(Client *c) { 220 Client **tc, *t; 221 222 - for(tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext); 223 + for(tc = &c->mon->cl->stack; *tc && *tc != c; tc = &(*tc)->snext); 224 *tc = c->snext; 225 226 if(c == c->mon->sel) { 227 - for(t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext); 228 + for(t = c->mon->cl->stack; t && !ISVISIBLE(t, c->mon); t = t->snext); 229 c->mon->sel = t; 230 } 231 } 232 @@ -696,7 +743,7 @@ 233 unsigned int i, occ = 0, urg = 0; 234 Client *c; 235 236 - for(c = m->clients; c; c = c->next) { 237 + for(c = m->cl->clients; c; c = c->next) { 238 occ |= c->tags; 239 if(c->isurgent) 240 urg |= c->tags; 241 @@ -779,8 +826,8 @@ 242 243 void 244 focus(Client *c) { 245 - if(!c || !ISVISIBLE(c)) 246 - for(c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); 247 + if(!c || !ISVISIBLE(c, selmon)) 248 + for(c = selmon->cl->stack; c && !ISVISIBLE(c, selmon); c = c->snext); 249 /* was if(selmon->sel) */ 250 if(selmon->sel && selmon->sel != c) 251 unfocus(selmon->sel, False); 252 @@ -832,17 +879,17 @@ 253 if(!selmon->sel) 254 return; 255 if(arg->i > 0) { 256 - for(c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); 257 + for(c = selmon->sel->next; c && !ISVISIBLE(c, selmon); c = c->next); 258 if(!c) 259 - for(c = selmon->clients; c && !ISVISIBLE(c); c = c->next); 260 + for(c = selmon->cl->clients; c && !ISVISIBLE(c, selmon); c = c->next); 261 } 262 else { 263 - for(i = selmon->clients; i != selmon->sel; i = i->next) 264 - if(ISVISIBLE(i)) 265 + for(i = selmon->cl->clients; i != selmon->sel; i = i->next) 266 + if(ISVISIBLE(i, selmon)) 267 c = i; 268 if(!c) 269 for(; i; i = i->next) 270 - if(ISVISIBLE(i)) 271 + if(ISVISIBLE(i, selmon)) 272 c = i; 273 } 274 if(c) { 275 @@ -1092,12 +1139,12 @@ 276 unsigned int n = 0; 277 Client *c; 278 279 - for(c = m->clients; c; c = c->next) 280 - if(ISVISIBLE(c)) 281 + for(c = m->cl->clients; c; c = c->next) 282 + if(ISVISIBLE(c, m)) 283 n++; 284 if(n > 0) /* override layout symbol */ 285 snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); 286 - for(c = nexttiled(m->clients); c; c = nexttiled(c->next)) 287 + for(c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m)) 288 resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False); 289 } 290 291 @@ -1175,8 +1222,8 @@ 292 } 293 294 Client * 295 -nexttiled(Client *c) { 296 - for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); 297 +nexttiled(Client *c, Monitor *m) { 298 + for(; c && (c->isfloating || !ISVISIBLE(c, m)); c = c->next); 299 return c; 300 } 301 302 @@ -1328,8 +1375,8 @@ 303 if(m->lt[m->sellt]->arrange) { 304 wc.stack_mode = Below; 305 wc.sibling = m->barwin; 306 - for(c = m->stack; c; c = c->snext) 307 - if(!c->isfloating && ISVISIBLE(c)) { 308 + for(c = m->cl->stack; c; c = c->snext) 309 + if(!c->isfloating && ISVISIBLE(c, m)) { 310 XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); 311 wc.sibling = c->win; 312 } 313 @@ -1379,7 +1426,6 @@ 314 if(c->mon == m) 315 return; 316 unfocus(c, True); 317 - detach(c); 318 detachstack(c); 319 c->mon = m; 320 c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ 321 @@ -1501,6 +1547,8 @@ 322 sw = DisplayWidth(dpy, screen); 323 sh = DisplayHeight(dpy, screen); 324 bh = fnt->h + 2; 325 + if(!(cl = (Clientlist *)calloc(1, sizeof(Clientlist)))) 326 + die("fatal: could not malloc() %u bytes\n", sizeof(Clientlist)); 327 drw = drw_create(dpy, screen, root, sw, sh); 328 drw_setfont(drw, fnt); 329 updategeom(); 330 @@ -1549,9 +1597,11 @@ 331 showhide(Client *c) { 332 if(!c) 333 return; 334 - if(ISVISIBLE(c)) { /* show clients top down */ 335 + if(ISVISIBLE(c, c->mon)) { /* show clients top down */ 336 XMoveWindow(dpy, c->win, c->x, c->y); 337 if((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) 338 + if(c->isfloating) 339 + keepfloatingposition(c); 340 resize(c, c->x, c->y, c->w, c->h, False); 341 showhide(c->snext); 342 } 343 @@ -1585,7 +1635,22 @@ 344 345 void 346 tag(const Arg *arg) { 347 + Monitor *m; 348 + unsigned int newtags; 349 if(selmon->sel && arg->ui & TAGMASK) { 350 + newtags = arg->ui & TAGMASK; 351 + for(m = mons; m; m = m->next) 352 + /* if tag is visible on another monitor, move client to the new monitor */ 353 + if(m != selmon && m->tagset[m->seltags] & newtags) { 354 + /* prevent moving client to all tags (MODKEY-Shift-0) when multiple monitors are connected */ 355 + if(newtags & selmon->tagset[selmon->seltags]) 356 + return; 357 + selmon->sel->tags = newtags; 358 + selmon->sel->mon = m; 359 + arrange(m); 360 + break; 361 + } 362 + /* workaround in case just one monitor is connected */ 363 selmon->sel->tags = arg->ui & TAGMASK; 364 focus(NULL); 365 arrange(selmon); 366 @@ -1604,7 +1669,7 @@ 367 unsigned int i, n, h, mw, my, ty; 368 Client *c; 369 370 - for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); 371 + for(n = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), n++); 372 if(n == 0) 373 return; 374 375 @@ -1612,7 +1677,7 @@ 376 mw = m->nmaster ? m->ww * m->mfact : 0; 377 else 378 mw = m->ww; 379 - for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) 380 + for(i = my = ty = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), i++) 381 if(i < m->nmaster) { 382 h = (m->wh - my) / (MIN(n, m->nmaster) - i); 383 resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False); 384 @@ -1648,12 +1713,17 @@ 385 386 void 387 toggletag(const Arg *arg) { 388 + Monitor *m; 389 unsigned int newtags; 390 391 if(!selmon->sel) 392 return; 393 newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); 394 if(newtags) { 395 + /* prevent adding tags that are in use on other monitors */ 396 + for(m = mons; m; m = m->next) 397 + if(m != selmon && newtags & m->tagset[m->seltags]) 398 + return; 399 selmon->sel->tags = newtags; 400 focus(NULL); 401 arrange(selmon); 402 @@ -1662,9 +1732,14 @@ 403 404 void 405 toggleview(const Arg *arg) { 406 + Monitor *m; 407 unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); 408 409 if(newtagset) { 410 + /* prevent displaying the same tags on multiple monitors */ 411 + for(m = mons; m; m = m->next) 412 + if(m != selmon && newtagset & m->tagset[m->seltags]) 413 + return; 414 selmon->tagset[selmon->seltags] = newtagset; 415 focus(NULL); 416 arrange(selmon); 417 @@ -1703,6 +1778,7 @@ 418 XUngrabServer(dpy); 419 } 420 free(c); 421 + attachclients(selmon); 422 focus(NULL); 423 updateclientlist(); 424 arrange(m); 425 @@ -1760,7 +1836,7 @@ 426 427 XDeleteProperty(dpy, root, netatom[NetClientList]); 428 for(m = mons; m; m = m->next) 429 - for(c = m->clients; c; c = c->next) 430 + for(c = m->cl->clients; c; c = c->next) 431 XChangeProperty(dpy, root, netatom[NetClientList], 432 XA_WINDOW, 32, PropModeAppend, 433 (unsigned char *) &(c->win), 1); 434 @@ -1790,8 +1866,10 @@ 435 if(n <= nn) { 436 for(i = 0; i < (nn - n); i++) { /* new monitors available */ 437 for(m = mons; m && m->next; m = m->next); 438 - if(m) 439 + if(m) { 440 m->next = createmon(); 441 + attachclients(m->next); 442 + } 443 else 444 mons = createmon(); 445 } 446 @@ -1812,17 +1890,13 @@ 447 else { /* less monitors available nn < n */ 448 for(i = nn; i < n; i++) { 449 for(m = mons; m && m->next; m = m->next); 450 - while(m->clients) { 451 - dirty = True; 452 - c = m->clients; 453 - m->clients = c->next; 454 - detachstack(c); 455 - c->mon = mons; 456 - attach(c); 457 - attachstack(c); 458 - } 459 if(m == selmon) 460 selmon = mons; 461 + for(c = m->cl->clients; c; c = c->next) { 462 + dirty = True; 463 + if(c->mon == m) 464 + c->mon = selmon; 465 + } 466 cleanupmon(m); 467 } 468 } 469 @@ -1960,11 +2034,31 @@ 470 471 void 472 view(const Arg *arg) { 473 + Monitor *m; 474 + unsigned int newtagset = selmon->tagset[selmon->seltags ^ 1]; 475 if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) 476 return; 477 + 478 + /* swap tags when trying to display a tag from another monitor */ 479 + if(arg->ui & TAGMASK) 480 + newtagset = arg->ui & TAGMASK; 481 + for(m = mons; m; m = m->next) 482 + if(m != selmon && newtagset & m->tagset[m->seltags]) { 483 + /* prevent displaying all tags (MODKEY-0) when multiple monitors 484 + * are connected */ 485 + if(newtagset & selmon->tagset[selmon->seltags]) 486 + return; 487 + m->seltags ^= 1; 488 + m->tagset[m->seltags] = selmon->tagset[selmon->seltags]; 489 + attachclients(m); 490 + arrange(m); 491 + break; 492 + } 493 + 494 selmon->seltags ^= 1; /* toggle sel tagset */ 495 if(arg->ui & TAGMASK) 496 selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; 497 + attachclients(selmon); 498 focus(NULL); 499 arrange(selmon); 500 } 501 @@ -1975,7 +2069,7 @@ 502 Monitor *m; 503 504 for(m = mons; m; m = m->next) 505 - for(c = m->clients; c; c = c->next) 506 + for(c = m->cl->clients; c; c = c->next) 507 if(c->win == w) 508 return c; 509 return NULL; 510 @@ -2037,8 +2131,8 @@ 511 if(!selmon->lt[selmon->sellt]->arrange 512 || (selmon->sel && selmon->sel->isfloating)) 513 return; 514 - if(c == nexttiled(selmon->clients)) 515 - if(!c || !(c = nexttiled(c->next))) 516 + if(c == nexttiled(selmon->cl->clients, selmon)) 517 + if(!c || !(c = nexttiled(c->next, selmon))) 518 return; 519 pop(c); 520 } 521 Index: dwm/config.def.h 522 =================================================================== 523 --- dwm/config.def.h.orig 2014-02-09 15:24:26.156117354 +0100 524 +++ dwm/config.def.h 2014-02-09 15:24:26.148117354 +0100 525 @@ -54,6 +54,7 @@ 526 static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL }; 527 static const char *termcmd[] = { "st", NULL }; 528 529 +#include "keepfloatingposition.c" 530 static Key keys[] = { 531 /* modifier key function argument */ 532 { MODKEY, XK_p, spawn, {.v = dmenucmd } }, 533 Index: dwm/keepfloatingposition.c 534 =================================================================== 535 --- /dev/null 1970-01-01 00:00:00.000000000 +0000 536 +++ dwm/keepfloatingposition.c 2014-02-09 15:24:26.148117354 +0100 537 @@ -0,0 +1,30 @@ 538 +static void 539 +keepfloatingposition(Client *c) { 540 + Monitor *m; 541 + int cmmx = c->mon->mx; 542 + int cmmy = c->mon->my; 543 + int cmmw = c->mon->mw; 544 + int cmmh = c->mon->mh; 545 + int mmx, mmy; 546 + if(!(cmmx <= c->x && 547 + cmmx + cmmw - 1 >= c->x && 548 + cmmy <= c->y && 549 + cmmy + cmmh - 1 >= c->y)) 550 + for(m = mons; m; m = m->next) { 551 + mmx = m->mx; 552 + mmy = m->my; 553 + if(mmx <= c->x && 554 + mmx + m->mw - 1 >= c->x && 555 + mmy <= c->y && 556 + mmy + m->mh - 1 >= c->y) { 557 + c->x = c->x - mmx + cmmx; 558 + c->y = c->y - mmy + cmmy; 559 + if(c->x + c->w + 2 * c->bw > cmmx + cmmw - 1) 560 + c->x -= c->x + c->w + 2 * c->bw - cmmx - cmmw; 561 + if(c->y + c->h + 2 * c->bw > cmmy + cmmh - 1) 562 + c->y -= c->y + c->h + 2 * c->bw - cmmy - cmmh; 563 + resizeclient(c, c->x, c->y, c->w, c->h); 564 + break; 565 + } 566 + } 567 +}