dwm-single_tagset-6.0.diff (14417B)
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 diff -r ec4baab78314 dwm.c 19 --- a/dwm.c Mon Dec 19 15:38:30 2011 +0100 20 +++ b/dwm.c Fri Apr 06 08:23:13 2012 +0200 21 @@ -45,7 +45,7 @@ 22 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) 23 #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ 24 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) 25 -#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) 26 +#define ISVISIBLE(C, M) ((C->tags & M->tagset[M->seltags])) 27 #define LENGTH(X) (sizeof X / sizeof X[0]) 28 #define MAX(A, B) ((A) > (B) ? (A) : (B)) 29 #define MIN(A, B) ((A) < (B) ? (A) : (B)) 30 @@ -124,6 +124,7 @@ 31 void (*arrange)(Monitor *); 32 } Layout; 33 34 +typedef struct Clientlist Clientlist; 35 struct Monitor { 36 char ltsymbol[16]; 37 float mfact; 38 @@ -137,9 +138,8 @@ 39 unsigned int tagset[2]; 40 Bool showbar; 41 Bool topbar; 42 - Client *clients; 43 + Clientlist *cl; 44 Client *sel; 45 - Client *stack; 46 Monitor *next; 47 Window barwin; 48 const Layout *lt[2]; 49 @@ -154,12 +154,18 @@ 50 int monitor; 51 } Rule; 52 53 +struct Clientlist { 54 + Client *clients; 55 + Client *stack; 56 +}; 57 + 58 /* function declarations */ 59 static void applyrules(Client *c); 60 static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact); 61 static void arrange(Monitor *m); 62 static void arrangemon(Monitor *m); 63 static void attach(Client *c); 64 +static void attachclients(Monitor *m); 65 static void attachstack(Client *c); 66 static void buttonpress(XEvent *e); 67 static void checkotherwm(void); 68 @@ -202,7 +208,7 @@ 69 static void monocle(Monitor *m); 70 static void motionnotify(XEvent *e); 71 static void movemouse(const Arg *arg); 72 -static Client *nexttiled(Client *c); 73 +static Client *nexttiled(Client *c, Monitor *m); 74 static void pop(Client *); 75 static void propertynotify(XEvent *e); 76 static void quit(const Arg *arg); 77 @@ -283,6 +289,7 @@ 78 static DC dc; 79 static Monitor *mons = NULL, *selmon = NULL; 80 static Window root; 81 +static Clientlist *cl; 82 83 /* configuration, allows nested code to access above variables */ 84 #include "config.h" 85 @@ -313,7 +320,7 @@ 86 { 87 c->isfloating = r->isfloating; 88 c->tags |= r->tags; 89 - for(m = mons; m && m->num != r->monitor; m = m->next); 90 + for(m = mons; m && (m->tagset[m->seltags] & c->tags) == 0; m = m->next) ; 91 if(m) 92 c->mon = m; 93 } 94 @@ -394,9 +401,9 @@ 95 void 96 arrange(Monitor *m) { 97 if(m) 98 - showhide(m->stack); 99 + showhide(m->cl->stack); 100 else for(m = mons; m; m = m->next) 101 - showhide(m->stack); 102 + showhide(m->cl->stack); 103 if(m) 104 arrangemon(m); 105 else for(m = mons; m; m = m->next) 106 @@ -413,14 +420,47 @@ 107 108 void 109 attach(Client *c) { 110 - c->next = c->mon->clients; 111 - c->mon->clients = c; 112 + c->next = c->mon->cl->clients; 113 + c->mon->cl->clients = c; 114 +} 115 + 116 +void 117 +attachclients(Monitor *m) { 118 + /* attach clients to the specified monitor */ 119 + Monitor *tm; 120 + Client *c; 121 + unsigned int utags = 0; 122 + Bool rmons = False; 123 + if(!m) 124 + return; 125 + 126 + /* collect information about the tags in use */ 127 + for(tm = mons; tm; tm = tm->next) 128 + if(tm != m) 129 + utags |= m->tagset[m->seltags]; 130 + 131 + for(c = m->cl->clients; c; c = c->next) 132 + if(ISVISIBLE(c, m)) { 133 + /* if client is also visible on other tags that are displayed on 134 + * other monitors, remove these tags */ 135 + if(c->tags & utags) { 136 + c->tags = c->tags & m->tagset[m->seltags]; 137 + rmons = True; 138 + } 139 + unfocus(c, True); 140 + c->mon = m; 141 + } 142 + 143 + if(rmons) 144 + for(tm = mons; tm; tm = tm->next) 145 + if(tm != m) 146 + arrange(tm); 147 } 148 149 void 150 attachstack(Client *c) { 151 - c->snext = c->mon->stack; 152 - c->mon->stack = c; 153 + c->snext = c->mon->cl->stack; 154 + c->mon->cl->stack = c; 155 } 156 157 void 158 @@ -483,8 +523,8 @@ 159 view(&a); 160 selmon->lt[selmon->sellt] = &foo; 161 for(m = mons; m; m = m->next) 162 - while(m->stack) 163 - unmanage(m->stack, False); 164 + while(m->cl->stack) 165 + unmanage(m->cl->stack, False); 166 if(dc.font.set) 167 XFreeFontSet(dpy, dc.font.set); 168 else 169 @@ -541,7 +581,7 @@ 170 || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); 171 } 172 else if(cme->message_type == netatom[NetActiveWindow]) { 173 - if(!ISVISIBLE(c)) { 174 + if(!ISVISIBLE(c, c->mon)) { 175 c->mon->seltags ^= 1; 176 c->mon->tagset[c->mon->seltags] = c->tags; 177 } 178 @@ -624,7 +664,7 @@ 179 c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */ 180 if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) 181 configure(c); 182 - if(ISVISIBLE(c)) 183 + if(ISVISIBLE(c, m)) 184 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); 185 } 186 else 187 @@ -645,11 +685,18 @@ 188 189 Monitor * 190 createmon(void) { 191 - Monitor *m; 192 + Monitor *m, *tm; 193 + unsigned int i; 194 195 if(!(m = (Monitor *)calloc(1, sizeof(Monitor)))) 196 die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); 197 - m->tagset[0] = m->tagset[1] = 1; 198 + m->cl = cl; 199 + /* reassing tags when creating a new monitor */ 200 + for(i=1, tm = mons; tm; tm = tm->next, i++) { 201 + tm->seltags ^= 1; 202 + tm->tagset[tm->seltags] = i; 203 + } 204 + m->tagset[0] = m->tagset[1] = i; 205 m->mfact = mfact; 206 m->nmaster = nmaster; 207 m->showbar = showbar; 208 @@ -673,7 +720,7 @@ 209 detach(Client *c) { 210 Client **tc; 211 212 - for(tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next); 213 + for(tc = &c->mon->cl->clients; *tc && *tc != c; tc = &(*tc)->next); 214 *tc = c->next; 215 } 216 217 @@ -681,11 +728,11 @@ 218 detachstack(Client *c) { 219 Client **tc, *t; 220 221 - for(tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext); 222 + for(tc = &c->mon->cl->stack; *tc && *tc != c; tc = &(*tc)->snext); 223 *tc = c->snext; 224 225 if(c == c->mon->sel) { 226 - for(t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext); 227 + for(t = c->mon->cl->stack; t && !ISVISIBLE(t, c->mon); t = t->snext); 228 c->mon->sel = t; 229 } 230 } 231 @@ -722,7 +769,7 @@ 232 unsigned long *col; 233 Client *c; 234 235 - for(c = m->clients; c; c = c->next) { 236 + for(c = m->cl->clients; c; c = c->next) { 237 occ |= c->tags; 238 if(c->isurgent) 239 urg |= c->tags; 240 @@ -842,8 +889,8 @@ 241 242 void 243 focus(Client *c) { 244 - if(!c || !ISVISIBLE(c)) 245 - for(c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); 246 + if(!c || !ISVISIBLE(c, selmon)) 247 + for(c = selmon->cl->stack; c && !ISVISIBLE(c, selmon); c = c->snext); 248 /* was if(selmon->sel) */ 249 if(selmon->sel && selmon->sel != c) 250 unfocus(selmon->sel, False); 251 @@ -892,17 +939,17 @@ 252 if(!selmon->sel) 253 return; 254 if(arg->i > 0) { 255 - for(c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); 256 + for(c = selmon->sel->next; c && !ISVISIBLE(c, selmon); c = c->next); 257 if(!c) 258 - for(c = selmon->clients; c && !ISVISIBLE(c); c = c->next); 259 + for(c = selmon->cl->clients; c && !ISVISIBLE(c, selmon); c = c->next); 260 } 261 else { 262 - for(i = selmon->clients; i != selmon->sel; i = i->next) 263 - if(ISVISIBLE(i)) 264 + for(i = selmon->cl->clients; i != selmon->sel; i = i->next) 265 + if(ISVISIBLE(i, selmon)) 266 c = i; 267 if(!c) 268 for(; i; i = i->next) 269 - if(ISVISIBLE(i)) 270 + if(ISVISIBLE(i, selmon)) 271 c = i; 272 } 273 if(c) { 274 @@ -1194,12 +1241,12 @@ 275 unsigned int n = 0; 276 Client *c; 277 278 - for(c = m->clients; c; c = c->next) 279 - if(ISVISIBLE(c)) 280 + for(c = m->cl->clients; c; c = c->next) 281 + if(ISVISIBLE(c, m)) 282 n++; 283 if(n > 0) /* override layout symbol */ 284 snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); 285 - for(c = nexttiled(m->clients); c; c = nexttiled(c->next)) 286 + for(c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m)) 287 resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False); 288 } 289 290 @@ -1274,8 +1321,8 @@ 291 } 292 293 Client * 294 -nexttiled(Client *c) { 295 - for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); 296 +nexttiled(Client *c, Monitor *m) { 297 + for(; c && (c->isfloating || !ISVISIBLE(c, m)); c = c->next); 298 return c; 299 } 300 301 @@ -1425,8 +1472,8 @@ 302 if(m->lt[m->sellt]->arrange) { 303 wc.stack_mode = Below; 304 wc.sibling = m->barwin; 305 - for(c = m->stack; c; c = c->snext) 306 - if(!c->isfloating && ISVISIBLE(c)) { 307 + for(c = m->cl->stack; c; c = c->snext) 308 + if(!c->isfloating && ISVISIBLE(c, m)) { 309 XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); 310 wc.sibling = c->win; 311 } 312 @@ -1476,11 +1523,9 @@ 313 if(c->mon == m) 314 return; 315 unfocus(c, True); 316 - detach(c); 317 detachstack(c); 318 c->mon = m; 319 c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ 320 - attach(c); 321 attachstack(c); 322 focus(NULL); 323 arrange(NULL); 324 @@ -1594,6 +1639,8 @@ 325 sw = DisplayWidth(dpy, screen); 326 sh = DisplayHeight(dpy, screen); 327 bh = dc.h = dc.font.height + 2; 328 + if(!(cl = (Clientlist *)calloc(1, sizeof(Clientlist)))) 329 + die("fatal: could not malloc() %u bytes\n", sizeof(Clientlist)); 330 updategeom(); 331 /* init atoms */ 332 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); 333 @@ -1642,7 +1689,7 @@ 334 showhide(Client *c) { 335 if(!c) 336 return; 337 - if(ISVISIBLE(c)) { /* show clients top down */ 338 + if(ISVISIBLE(c, c->mon)) { /* show clients top down */ 339 XMoveWindow(dpy, c->win, c->x, c->y); 340 if((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) 341 resize(c, c->x, c->y, c->w, c->h, False); 342 @@ -1676,7 +1723,22 @@ 343 344 void 345 tag(const Arg *arg) { 346 + Monitor *m; 347 + unsigned int newtags; 348 if(selmon->sel && arg->ui & TAGMASK) { 349 + newtags = arg->ui & TAGMASK; 350 + for(m = mons; m; m = m->next) 351 + /* if tag is visible on another monitor, move client to the new monitor */ 352 + if(m != selmon && m->tagset[m->seltags] & newtags) { 353 + /* prevent moving client to all tags (MODKEY-Shift-0) when multiple monitors are connected */ 354 + if(newtags & selmon->tagset[selmon->seltags]) 355 + return; 356 + selmon->sel->tags = newtags; 357 + selmon->sel->mon = m; 358 + arrange(m); 359 + break; 360 + } 361 + /* workaround in case just one monitor is connected */ 362 selmon->sel->tags = arg->ui & TAGMASK; 363 focus(NULL); 364 arrange(selmon); 365 @@ -1706,7 +1768,7 @@ 366 unsigned int i, n, h, mw, my, ty; 367 Client *c; 368 369 - for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); 370 + for(n = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), n++); 371 if(n == 0) 372 return; 373 374 @@ -1714,7 +1776,7 @@ 375 mw = m->nmaster ? m->ww * m->mfact : 0; 376 else 377 mw = m->ww; 378 - for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) 379 + for(i = my = ty = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), i++) 380 if(i < m->nmaster) { 381 h = (m->wh - my) / (MIN(n, m->nmaster) - i); 382 resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False); 383 @@ -1748,12 +1810,17 @@ 384 385 void 386 toggletag(const Arg *arg) { 387 + Monitor *m; 388 unsigned int newtags; 389 390 if(!selmon->sel) 391 return; 392 newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); 393 if(newtags) { 394 + /* prevent adding tags that are in use on other monitors */ 395 + for(m = mons; m; m = m->next) 396 + if(m != selmon && newtags & m->tagset[m->seltags]) 397 + return; 398 selmon->sel->tags = newtags; 399 focus(NULL); 400 arrange(selmon); 401 @@ -1762,10 +1829,16 @@ 402 403 void 404 toggleview(const Arg *arg) { 405 + Monitor *m; 406 unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); 407 408 if(newtagset) { 409 + /* prevent displaying the same tags on multiple monitors */ 410 + for(m = mons; m; m = m->next) 411 + if(m != selmon && newtagset & m->tagset[m->seltags]) 412 + return; 413 selmon->tagset[selmon->seltags] = newtagset; 414 + attachclients(selmon); 415 focus(NULL); 416 arrange(selmon); 417 } 418 @@ -1872,8 +1945,10 @@ 419 if(n <= nn) { 420 for(i = 0; i < (nn - n); i++) { /* new monitors available */ 421 for(m = mons; m && m->next; m = m->next); 422 - if(m) 423 + if(m) { 424 m->next = createmon(); 425 + attachclients(m->next); 426 + } 427 else 428 mons = createmon(); 429 } 430 @@ -1894,17 +1969,13 @@ 431 else { /* less monitors available nn < n */ 432 for(i = nn; i < n; i++) { 433 for(m = mons; m && m->next; m = m->next); 434 - while(m->clients) { 435 - dirty = True; 436 - c = m->clients; 437 - m->clients = c->next; 438 - detachstack(c); 439 - c->mon = mons; 440 - attach(c); 441 - attachstack(c); 442 - } 443 if(m == selmon) 444 selmon = mons; 445 + for(c = m->cl->clients; c; c = c->next) { 446 + dirty = True; 447 + if(c->mon == m) 448 + c->mon = selmon; 449 + } 450 cleanupmon(m); 451 } 452 } 453 @@ -2043,11 +2114,31 @@ 454 455 void 456 view(const Arg *arg) { 457 + Monitor *m; 458 + unsigned int newtagset = selmon->tagset[selmon->seltags ^ 1]; 459 if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) 460 return; 461 + 462 + /* swap tags when trying to display a tag from another monitor */ 463 + if(arg->ui & TAGMASK) 464 + newtagset = arg->ui & TAGMASK; 465 + for(m = mons; m; m = m->next) 466 + if(m != selmon && newtagset & m->tagset[m->seltags]) { 467 + /* prevent displaying all tags (MODKEY-0) when multiple monitors 468 + * are connected */ 469 + if(newtagset & selmon->tagset[selmon->seltags]) 470 + return; 471 + m->seltags ^= 1; 472 + m->tagset[m->seltags] = selmon->tagset[selmon->seltags]; 473 + attachclients(m); 474 + arrange(m); 475 + break; 476 + } 477 + 478 selmon->seltags ^= 1; /* toggle sel tagset */ 479 if(arg->ui & TAGMASK) 480 selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; 481 + attachclients(selmon); 482 focus(NULL); 483 arrange(selmon); 484 } 485 @@ -2058,7 +2149,7 @@ 486 Monitor *m; 487 488 for(m = mons; m; m = m->next) 489 - for(c = m->clients; c; c = c->next) 490 + for(c = m->cl->clients; c; c = c->next) 491 if(c->win == w) 492 return c; 493 return NULL; 494 @@ -2120,8 +2211,8 @@ 495 if(!selmon->lt[selmon->sellt]->arrange 496 || (selmon->sel && selmon->sel->isfloating)) 497 return; 498 - if(c == nexttiled(selmon->clients)) 499 - if(!c || !(c = nexttiled(c->next))) 500 + if(c == nexttiled(selmon->cl->clients, selmon)) 501 + if(!c || !(c = nexttiled(c->next, selmon))) 502 return; 503 pop(c); 504 }