dwm-single_tagset-20211015-a786211.diff (15736B)
1 From 671cd00f679247378af4ec1813e071985f2bab72 Mon Sep 17 00:00:00 2001 2 From: mzeinali <mzeinali@protonmail.com> 3 Date: Fri, 15 Oct 2021 02:41:50 +0330 4 Subject: [PATCH] single tagset for dwm source a786211 20211015 5 6 --- 7 dwm.c | 226 ++++++++++++++++++++++++++++++++++++++++++++-------------- 8 1 file changed, 171 insertions(+), 55 deletions(-) 9 10 diff --git a/dwm.c b/dwm.c 11 index 5e4d494..5eb3d5f 100644 12 --- a/dwm.c 13 +++ b/dwm.c 14 @@ -49,7 +49,7 @@ 15 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) 16 #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ 17 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) 18 -#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) 19 +#define ISVISIBLE(C, M) ((C->tags & M->tagset[M->seltags])) 20 #define LENGTH(X) (sizeof X / sizeof X[0]) 21 #define MOUSEMASK (BUTTONMASK|PointerMotionMask) 22 #define WIDTH(X) ((X)->w + 2 * (X)->bw) 23 @@ -82,6 +82,7 @@ typedef struct { 24 const Arg arg; 25 } Button; 26 27 +typedef struct Clientlist Clientlist; 28 typedef struct Monitor Monitor; 29 typedef struct Client Client; 30 struct Client { 31 @@ -124,9 +125,8 @@ struct Monitor { 32 unsigned int tagset[2]; 33 int showbar; 34 int topbar; 35 - Client *clients; 36 + Clientlist *cl; 37 Client *sel; 38 - Client *stack; 39 Monitor *next; 40 Window barwin; 41 const Layout *lt[2]; 42 @@ -141,12 +141,18 @@ typedef struct { 43 int monitor; 44 } Rule; 45 46 +struct Clientlist { 47 + Client *clients; 48 + Client *stack; 49 +}; 50 + 51 /* function declarations */ 52 static void applyrules(Client *c); 53 static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); 54 static void arrange(Monitor *m); 55 static void arrangemon(Monitor *m); 56 static void attach(Client *c); 57 +static void attachclients(Monitor *m); 58 static void attachstack(Client *c); 59 static void buttonpress(XEvent *e); 60 static void checkotherwm(void); 61 @@ -184,7 +190,7 @@ static void maprequest(XEvent *e); 62 static void monocle(Monitor *m); 63 static void motionnotify(XEvent *e); 64 static void movemouse(const Arg *arg); 65 -static Client *nexttiled(Client *c); 66 +static Client *nexttiled(Client *c, Monitor *m); 67 static void pop(Client *); 68 static void propertynotify(XEvent *e); 69 static void quit(const Arg *arg); 70 @@ -268,6 +274,7 @@ static Display *dpy; 71 static Drw *drw; 72 static Monitor *mons, *selmon; 73 static Window root, wmcheckwin; 74 +static Clientlist *cl; 75 76 /* configuration, allows nested code to access above variables */ 77 #include "config.h" 78 @@ -300,7 +307,7 @@ applyrules(Client *c) 79 { 80 c->isfloating = r->isfloating; 81 c->tags |= r->tags; 82 - for (m = mons; m && m->num != r->monitor; m = m->next); 83 + for (m = mons; m && (m->tagset[m->seltags] & c->tags) == 0; m = m->next); 84 if (m) 85 c->mon = m; 86 } 87 @@ -382,9 +389,9 @@ void 88 arrange(Monitor *m) 89 { 90 if (m) 91 - showhide(m->stack); 92 + showhide(m->cl->stack); 93 else for (m = mons; m; m = m->next) 94 - showhide(m->stack); 95 + showhide(m->cl->stack); 96 if (m) { 97 arrangemon(m); 98 restack(m); 99 @@ -403,15 +410,49 @@ arrangemon(Monitor *m) 100 void 101 attach(Client *c) 102 { 103 - c->next = c->mon->clients; 104 - c->mon->clients = c; 105 + c->next = c->mon->cl->clients; 106 + c->mon->cl->clients = c; 107 +} 108 + 109 +void 110 +attachclients(Monitor *m) { 111 + /* attach clients to the specified monitor */ 112 + Monitor *tm; 113 + Client *c; 114 + unsigned int utags = 0; 115 + Bool rmons = False; 116 + if(!m) 117 + return; 118 + 119 + /* collect information about the tags in use */ 120 + for (tm = mons; tm; tm = tm->next) 121 + if(tm != m) 122 + utags |= tm->tagset[tm->seltags]; 123 + 124 + for (c = m->cl->clients; c; c = c->next) 125 + if(ISVISIBLE(c, m)) { 126 + /* if client is also visible on other tags that are displayed on 127 + * other monitors, remove these tags */ 128 + if(c->tags & utags) { 129 + c->tags = c->tags & m->tagset[m->seltags]; 130 + rmons = True; 131 + } 132 + unfocus(c, True); 133 + c->mon = m; 134 + } 135 + 136 + if (rmons) 137 + for (tm = mons; tm; tm = tm->next) 138 + if(tm != m) 139 + arrange(tm); 140 + 141 } 142 143 void 144 attachstack(Client *c) 145 { 146 - c->snext = c->mon->stack; 147 - c->mon->stack = c; 148 + c->snext = c->mon->cl->stack; 149 + c->mon->cl->stack = c; 150 } 151 152 void 153 @@ -478,8 +519,8 @@ cleanup(void) 154 view(&a); 155 selmon->lt[selmon->sellt] = &foo; 156 for (m = mons; m; m = m->next) 157 - while (m->stack) 158 - unmanage(m->stack, 0); 159 + while (m->cl->stack) 160 + unmanage(m->cl->stack, 0); 161 XUngrabKey(dpy, AnyKey, AnyModifier, root); 162 while (mons) 163 cleanupmon(mons); 164 @@ -565,7 +606,7 @@ configurenotify(XEvent *e) 165 drw_resize(drw, sw, bh); 166 updatebars(); 167 for (m = mons; m; m = m->next) { 168 - for (c = m->clients; c; c = c->next) 169 + for (c = m->cl->clients; c; c = c->next) 170 if (c->isfullscreen) 171 resizeclient(c, m->mx, m->my, m->mw, m->mh); 172 XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); 173 @@ -611,7 +652,7 @@ configurerequest(XEvent *e) 174 c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */ 175 if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) 176 configure(c); 177 - if (ISVISIBLE(c)) 178 + if (ISVISIBLE(c, m)) 179 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); 180 } else 181 configure(c); 182 @@ -631,10 +672,31 @@ configurerequest(XEvent *e) 183 Monitor * 184 createmon(void) 185 { 186 - Monitor *m; 187 + Monitor *m, *tm; 188 + int i; 189 190 + /* bail out if the number of monitors exceeds the number of tags */ 191 + for (i=1, tm=mons; tm; i++, tm=tm->next); 192 + if (i > LENGTH(tags)) { 193 + fprintf(stderr, "dwm: failed to add monitor, number of tags exceeded\n"); 194 + return NULL; 195 + } 196 + /* find the first tag that isn't in use */ 197 + for (i=0; i < LENGTH(tags); i++) { 198 + for (tm=mons; tm && !(tm->tagset[tm->seltags] & (1<<i)); tm=tm->next); 199 + if (!tm) 200 + break; 201 + } 202 + /* reassign all tags to monitors since there's currently no free tag for the 203 + * new monitor */ 204 + if (i >= LENGTH(tags)) 205 + for (i=0, tm=mons; tm; tm=tm->next, i++) { 206 + tm->seltags ^= 1; 207 + tm->tagset[tm->seltags] = (1<<i) & TAGMASK; 208 + } 209 m = ecalloc(1, sizeof(Monitor)); 210 - m->tagset[0] = m->tagset[1] = 1; 211 + m->cl = cl; 212 + m->tagset[0] = m->tagset[1] = (1<<i) & TAGMASK; 213 m->mfact = mfact; 214 m->nmaster = nmaster; 215 m->showbar = showbar; 216 @@ -660,7 +722,7 @@ detach(Client *c) 217 { 218 Client **tc; 219 220 - for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next); 221 + for (tc = &c->mon->cl->clients; *tc && *tc != c; tc = &(*tc)->next); 222 *tc = c->next; 223 } 224 225 @@ -669,11 +731,11 @@ detachstack(Client *c) 226 { 227 Client **tc, *t; 228 229 - for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext); 230 + for (tc = &c->mon->cl->stack; *tc && *tc != c; tc = &(*tc)->snext); 231 *tc = c->snext; 232 233 if (c == c->mon->sel) { 234 - for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext); 235 + for (t = c->mon->cl->stack; t && !ISVISIBLE(t, c->mon); t = t->snext); 236 c->mon->sel = t; 237 } 238 } 239 @@ -709,7 +771,7 @@ drawbar(Monitor *m) 240 drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); 241 } 242 243 - for (c = m->clients; c; c = c->next) { 244 + for (c = m->cl->clients; c; c = c->next) { 245 occ |= c->tags; 246 if (c->isurgent) 247 urg |= c->tags; 248 @@ -784,8 +846,8 @@ expose(XEvent *e) 249 void 250 focus(Client *c) 251 { 252 - if (!c || !ISVISIBLE(c)) 253 - for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); 254 + if (!c || !ISVISIBLE(c, selmon)) 255 + for (c = selmon->cl->stack; c && !ISVISIBLE(c, selmon); c = c->snext); 256 if (selmon->sel && selmon->sel != c) 257 unfocus(selmon->sel, 0); 258 if (c) { 259 @@ -838,16 +900,16 @@ focusstack(const Arg *arg) 260 if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen)) 261 return; 262 if (arg->i > 0) { 263 - for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); 264 + for (c = selmon->sel->next; c && !ISVISIBLE(c, selmon); c = c->next); 265 if (!c) 266 - for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); 267 + for (c = selmon->cl->clients; c && !ISVISIBLE(c, selmon); c = c->next); 268 } else { 269 - for (i = selmon->clients; i != selmon->sel; i = i->next) 270 - if (ISVISIBLE(i)) 271 + for (i = selmon->cl->clients; i != selmon->sel; i = i->next) 272 + if (ISVISIBLE(i, selmon)) 273 c = i; 274 if (!c) 275 for (; i; i = i->next) 276 - if (ISVISIBLE(i)) 277 + if (ISVISIBLE(i, selmon)) 278 c = i; 279 } 280 if (c) { 281 @@ -1107,12 +1169,12 @@ monocle(Monitor *m) 282 unsigned int n = 0; 283 Client *c; 284 285 - for (c = m->clients; c; c = c->next) 286 - if (ISVISIBLE(c)) 287 + for (c = m->cl->clients; c; c = c->next) 288 + if (ISVISIBLE(c, m)) 289 n++; 290 if (n > 0) /* override layout symbol */ 291 snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); 292 - for (c = nexttiled(m->clients); c; c = nexttiled(c->next)) 293 + for (c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m)) 294 resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); 295 } 296 297 @@ -1194,9 +1256,9 @@ movemouse(const Arg *arg) 298 } 299 300 Client * 301 -nexttiled(Client *c) 302 +nexttiled(Client *c, Monitor *m) 303 { 304 - for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); 305 + for (; c && (c->isfloating || !ISVISIBLE(c, m)); c = c->next); 306 return c; 307 } 308 309 @@ -1360,8 +1422,8 @@ restack(Monitor *m) 310 if (m->lt[m->sellt]->arrange) { 311 wc.stack_mode = Below; 312 wc.sibling = m->barwin; 313 - for (c = m->stack; c; c = c->snext) 314 - if (!c->isfloating && ISVISIBLE(c)) { 315 + for (c = m->cl->stack; c; c = c->snext) 316 + if (!c->isfloating && ISVISIBLE(c, m)) { 317 XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); 318 wc.sibling = c->win; 319 } 320 @@ -1414,11 +1476,9 @@ sendmon(Client *c, Monitor *m) 321 if (c->mon == m) 322 return; 323 unfocus(c, 1); 324 - detach(c); 325 detachstack(c); 326 c->mon = m; 327 c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ 328 - attach(c); 329 attachstack(c); 330 focus(NULL); 331 arrange(NULL); 332 @@ -1541,6 +1601,8 @@ setup(void) 333 screen = DefaultScreen(dpy); 334 sw = DisplayWidth(dpy, screen); 335 sh = DisplayHeight(dpy, screen); 336 + if(!(cl = (Clientlist *)calloc(1, sizeof(Clientlist)))) 337 + die("fatal: could not malloc() %u bytes\n", sizeof(Clientlist)); 338 root = RootWindow(dpy, screen); 339 drw = drw_create(dpy, screen, root, sw, sh); 340 if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) 341 @@ -1616,7 +1678,7 @@ showhide(Client *c) 342 { 343 if (!c) 344 return; 345 - if (ISVISIBLE(c)) { 346 + if (ISVISIBLE(c, c->mon)) { 347 /* show clients top down */ 348 XMoveWindow(dpy, c->win, c->x, c->y); 349 if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) 350 @@ -1656,7 +1718,23 @@ spawn(const Arg *arg) 351 void 352 tag(const Arg *arg) 353 { 354 + Monitor *m; 355 + unsigned int newtags; 356 if (selmon->sel && arg->ui & TAGMASK) { 357 + newtags = arg->ui & TAGMASK; 358 + for (m = mons; m; m = m->next) 359 + /* if tag is visible on another monitor, move client to the new monitor */ 360 + if (m != selmon && m->tagset[m->seltags] & newtags) { 361 + /* prevent moving client to all tags (MODKEY-Shift-0) when multiple monitors are connected */ 362 + if(newtags & selmon->tagset[selmon->seltags]) 363 + return; 364 + selmon->sel->tags = newtags; 365 + selmon->sel->mon = m; 366 + arrange(m); 367 + break; 368 + } 369 + /* workaround in case just one monitor is connected */ 370 + 371 selmon->sel->tags = arg->ui & TAGMASK; 372 focus(NULL); 373 arrange(selmon); 374 @@ -1677,7 +1755,7 @@ tile(Monitor *m) 375 unsigned int i, n, h, mw, my, ty; 376 Client *c; 377 378 - for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); 379 + for (n = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), n++); 380 if (n == 0) 381 return; 382 383 @@ -1685,7 +1763,7 @@ tile(Monitor *m) 384 mw = m->nmaster ? m->ww * m->mfact : 0; 385 else 386 mw = m->ww; 387 - for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) 388 + for (i = my = ty = 0, c = nexttiled(m->cl->clients, m); c; c = nexttiled(c->next, m), i++) 389 if (i < m->nmaster) { 390 h = (m->wh - my) / (MIN(n, m->nmaster) - i); 391 resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); 392 @@ -1725,12 +1803,17 @@ togglefloating(const Arg *arg) 393 void 394 toggletag(const Arg *arg) 395 { 396 + Monitor *m; 397 unsigned int newtags; 398 399 if (!selmon->sel) 400 return; 401 newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); 402 if (newtags) { 403 + /* prevent adding tags that are in use on other monitors */ 404 + for (m = mons; m; m = m->next) 405 + if (m != selmon && newtags & m->tagset[m->seltags]) 406 + return; 407 selmon->sel->tags = newtags; 408 focus(NULL); 409 arrange(selmon); 410 @@ -1740,12 +1823,27 @@ toggletag(const Arg *arg) 411 void 412 toggleview(const Arg *arg) 413 { 414 + Monitor *m; 415 unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); 416 417 if (newtagset) { 418 + /* prevent displaying the same tags on multiple monitors */ 419 + for(m = mons; m; m = m->next) 420 + if(m != selmon && newtagset & m->tagset[m->seltags]) 421 + return; 422 selmon->tagset[selmon->seltags] = newtagset; 423 - focus(NULL); 424 + attachclients(selmon); 425 arrange(selmon); 426 + focus(NULL); 427 + 428 + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); 429 + 430 + if (newtagset) { 431 + selmon->tagset[selmon->seltags] = newtagset; 432 + attachclients(selmon); 433 + arrange(selmon); 434 + focus(NULL); 435 + } 436 } 437 } 438 439 @@ -1844,7 +1942,7 @@ updateclientlist() 440 441 XDeleteProperty(dpy, root, netatom[NetClientList]); 442 for (m = mons; m; m = m->next) 443 - for (c = m->clients; c; c = c->next) 444 + for (c = m->cl->clients; c; c = c->next) 445 XChangeProperty(dpy, root, netatom[NetClientList], 446 XA_WINDOW, 32, PropModeAppend, 447 (unsigned char *) &(c->win), 1); 448 @@ -1874,8 +1972,10 @@ updategeom(void) 449 if (n <= nn) { /* new monitors available */ 450 for (i = 0; i < (nn - n); i++) { 451 for (m = mons; m && m->next; m = m->next); 452 - if (m) 453 + if (m) { 454 m->next = createmon(); 455 + attachclients(m->next); 456 + } 457 else 458 mons = createmon(); 459 } 460 @@ -1895,16 +1995,13 @@ updategeom(void) 461 } else { /* less monitors available nn < n */ 462 for (i = nn; i < n; i++) { 463 for (m = mons; m && m->next; m = m->next); 464 - while ((c = m->clients)) { 465 - dirty = 1; 466 - m->clients = c->next; 467 - detachstack(c); 468 - c->mon = mons; 469 - attach(c); 470 - attachstack(c); 471 - } 472 if (m == selmon) 473 selmon = mons; 474 + for (c = m->cl->clients; c; c = c->next) { 475 + dirty = True; 476 + if (c->mon == m) 477 + c->mon = selmon; 478 + } 479 cleanupmon(m); 480 } 481 } 482 @@ -2038,13 +2135,32 @@ updatewmhints(Client *c) 483 void 484 view(const Arg *arg) 485 { 486 + Monitor *m; 487 + unsigned int newtagset = selmon->tagset[selmon->seltags ^ 1]; 488 if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) 489 return; 490 + /* swap tags when trying to display a tag from another monitor */ 491 + if (arg->ui & TAGMASK) 492 + newtagset = arg->ui & TAGMASK; 493 + for (m = mons; m; m = m->next) 494 + if (m != selmon && newtagset & m->tagset[m->seltags]) { 495 + /* prevent displaying all tags (MODKEY-0) when multiple monitors 496 + * are connected */ 497 + if (newtagset & selmon->tagset[selmon->seltags]) 498 + return; 499 + m->sel = selmon->sel; 500 + m->seltags ^= 1; 501 + m->tagset[m->seltags] = selmon->tagset[selmon->seltags]; 502 + attachclients(m); 503 + arrange(m); 504 + break; 505 + } 506 selmon->seltags ^= 1; /* toggle sel tagset */ 507 if (arg->ui & TAGMASK) 508 selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; 509 - focus(NULL); 510 + attachclients(selmon); 511 arrange(selmon); 512 + focus(NULL); 513 } 514 515 Client * 516 @@ -2054,7 +2170,7 @@ wintoclient(Window w) 517 Monitor *m; 518 519 for (m = mons; m; m = m->next) 520 - for (c = m->clients; c; c = c->next) 521 + for (c = m->cl->clients; c; c = c->next) 522 if (c->win == w) 523 return c; 524 return NULL; 525 @@ -2121,8 +2237,8 @@ zoom(const Arg *arg) 526 if (!selmon->lt[selmon->sellt]->arrange 527 || (selmon->sel && selmon->sel->isfloating)) 528 return; 529 - if (c == nexttiled(selmon->clients)) 530 - if (!c || !(c = nexttiled(c->next))) 531 + if (c == nexttiled(selmon->cl->clients, selmon)) 532 + if (!c || !(c = nexttiled(c->next, selmon))) 533 return; 534 pop(c); 535 } 536 -- 537 2.33.0 538