dwm-awesomebarwithhover-20230431-6.4.diff (15829B)
1 diff --git a/config.def.h b/config.def.h 2 index 061ad66..82a3ed2 100644 3 --- a/config.def.h 4 +++ b/config.def.h 5 @@ -16,6 +16,8 @@ static const char *colors[][3] = { 6 /* fg bg border */ 7 [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, 8 [SchemeSel] = { col_gray4, col_cyan, col_cyan }, 9 + [SchemeHov] = { col_gray4, col_cyan, col_cyan }, 10 + [SchemeHid] = { col_cyan, col_gray1, col_cyan }, 11 }; 12 13 /* tagging */ 14 @@ -64,8 +66,10 @@ static const Key keys[] = { 15 { MODKEY, XK_p, spawn, {.v = dmenucmd } }, 16 { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, 17 { MODKEY, XK_b, togglebar, {0} }, 18 - { MODKEY, XK_j, focusstack, {.i = +1 } }, 19 - { MODKEY, XK_k, focusstack, {.i = -1 } }, 20 + { MODKEY, XK_j, focusstackvis, {.i = +1 } }, 21 + { MODKEY, XK_k, focusstackvis, {.i = -1 } }, 22 + { MODKEY|ShiftMask, XK_j, focusstackhid, {.i = +1 } }, 23 + { MODKEY|ShiftMask, XK_k, focusstackhid, {.i = -1 } }, 24 { MODKEY, XK_i, incnmaster, {.i = +1 } }, 25 { MODKEY, XK_d, incnmaster, {.i = -1 } }, 26 { MODKEY, XK_h, setmfact, {.f = -0.05} }, 27 @@ -84,6 +88,9 @@ static const Key keys[] = { 28 { MODKEY, XK_period, focusmon, {.i = +1 } }, 29 { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, 30 { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, 31 + { MODKEY, XK_s, show, {0} }, 32 + { MODKEY|ShiftMask, XK_s, showall, {0} }, 33 + { MODKEY, XK_h, hide, {0} }, 34 TAGKEYS( XK_1, 0) 35 TAGKEYS( XK_2, 1) 36 TAGKEYS( XK_3, 2) 37 @@ -102,6 +109,7 @@ static const Button buttons[] = { 38 /* click event mask button function argument */ 39 { ClkLtSymbol, 0, Button1, setlayout, {0} }, 40 { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, 41 + { ClkWinTitle, 0, Button1, togglewin, {0} }, 42 { ClkWinTitle, 0, Button2, zoom, {0} }, 43 { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, 44 { ClkClientWin, MODKEY, Button1, movemouse, {0} }, 45 diff --git a/dwm.c b/dwm.c 46 index e5efb6a..8cb5171 100644 47 --- a/dwm.c 48 +++ b/dwm.c 49 @@ -50,6 +50,7 @@ 50 #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ 51 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) 52 #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) 53 +#define HIDDEN(C) ((getstate(C->win) == IconicState)) 54 #define LENGTH(X) (sizeof X / sizeof X[0]) 55 #define MOUSEMASK (BUTTONMASK|PointerMotionMask) 56 #define WIDTH(X) ((X)->w + 2 * (X)->bw) 57 @@ -59,7 +60,7 @@ 58 59 /* enums */ 60 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ 61 -enum { SchemeNorm, SchemeSel }; /* color schemes */ 62 +enum { SchemeNorm, SchemeSel, SchemeHov, SchemeHid }; /* color schemes */ 63 enum { NetSupported, NetWMName, NetWMState, NetWMCheck, 64 NetWMFullscreen, NetActiveWindow, NetWMWindowType, 65 NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ 66 @@ -117,6 +118,8 @@ struct Monitor { 67 int nmaster; 68 int num; 69 int by; /* bar geometry */ 70 + int btw; /* width of tasks portion of bar */ 71 + int bt; /* number of tasks */ 72 int mx, my, mw, mh; /* screen size */ 73 int wx, wy, ww, wh; /* window area */ 74 unsigned int seltags; 75 @@ -124,8 +127,10 @@ struct Monitor { 76 unsigned int tagset[2]; 77 int showbar; 78 int topbar; 79 + int hidsel; 80 Client *clients; 81 Client *sel; 82 + Client *hov; 83 Client *stack; 84 Monitor *next; 85 Window barwin; 86 @@ -168,13 +173,17 @@ static void expose(XEvent *e); 87 static void focus(Client *c); 88 static void focusin(XEvent *e); 89 static void focusmon(const Arg *arg); 90 -static void focusstack(const Arg *arg); 91 +static void focusstackvis(const Arg *arg); 92 +static void focusstackhid(const Arg *arg); 93 +static void focusstack(int inc, int vis); 94 static Atom getatomprop(Client *c, Atom prop); 95 static int getrootptr(int *x, int *y); 96 static long getstate(Window w); 97 static int gettextprop(Window w, Atom atom, char *text, unsigned int size); 98 static void grabbuttons(Client *c, int focused); 99 static void grabkeys(void); 100 +static void hide(const Arg *arg); 101 +static void hidewin(Client *c); 102 static void incnmaster(const Arg *arg); 103 static void keypress(XEvent *e); 104 static void killclient(const Arg *arg); 105 @@ -204,6 +213,9 @@ static void setlayout(const Arg *arg); 106 static void setmfact(const Arg *arg); 107 static void setup(void); 108 static void seturgent(Client *c, int urg); 109 +static void show(const Arg *arg); 110 +static void showall(const Arg *arg); 111 +static void showwin(Client *c); 112 static void showhide(Client *c); 113 static void sigchld(int unused); 114 static void spawn(const Arg *arg); 115 @@ -214,6 +226,7 @@ static void togglebar(const Arg *arg); 116 static void togglefloating(const Arg *arg); 117 static void toggletag(const Arg *arg); 118 static void toggleview(const Arg *arg); 119 +static void togglewin(const Arg *arg); 120 static void unfocus(Client *c, int setfocus); 121 static void unmanage(Client *c, int destroyed); 122 static void unmapnotify(XEvent *e); 123 @@ -442,10 +455,25 @@ buttonpress(XEvent *e) 124 arg.ui = 1 << i; 125 } else if (ev->x < x + TEXTW(selmon->ltsymbol)) 126 click = ClkLtSymbol; 127 - else if (ev->x > selmon->ww - (int)TEXTW(stext)) 128 + /* 2px right padding */ 129 + else if (ev->x > selmon->ww - TEXTW(stext) + lrpad - 2) 130 click = ClkStatusText; 131 - else 132 - click = ClkWinTitle; 133 + else { 134 + x += TEXTW(selmon->ltsymbol); 135 + c = m->clients; 136 + 137 + if (c) { 138 + do { 139 + if (!ISVISIBLE(c)) 140 + continue; 141 + else 142 + x +=(1.0 / (double)m->bt) * m->btw; 143 + } while (ev->x > x && (c = c->next)); 144 + 145 + click = ClkWinTitle; 146 + arg.v = c; 147 + } 148 + } 149 } else if ((c = wintoclient(ev->window))) { 150 focus(c); 151 restack(selmon); 152 @@ -455,7 +483,7 @@ buttonpress(XEvent *e) 153 for (i = 0; i < LENGTH(buttons); i++) 154 if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button 155 && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) 156 - buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); 157 + buttons[i].func((click == ClkTagBar || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); 158 } 159 160 void 161 @@ -699,7 +727,7 @@ dirtomon(int dir) 162 void 163 drawbar(Monitor *m) 164 { 165 - int x, w, tw = 0; 166 + int x, w, tw = 0, n = 0, scm; 167 int boxs = drw->fonts->h / 9; 168 int boxw = drw->fonts->h / 6 + 2; 169 unsigned int i, occ = 0, urg = 0; 170 @@ -716,6 +744,8 @@ drawbar(Monitor *m) 171 } 172 173 for (c = m->clients; c; c = c->next) { 174 + if (ISVISIBLE(c)) 175 + n++; 176 occ |= c->tags; 177 if (c->isurgent) 178 urg |= c->tags; 179 @@ -736,16 +766,38 @@ drawbar(Monitor *m) 180 x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); 181 182 if ((w = m->ww - tw - x) > bh) { 183 - if (m->sel) { 184 - drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); 185 - drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); 186 - if (m->sel->isfloating) 187 - drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); 188 + if (n > 0) { 189 + int remainder = w % n; 190 + int tabw = (1.0 / (double)n) * w + 1; 191 + for (c = m->clients; c; c = c->next) { 192 + if (!ISVISIBLE(c)) 193 + continue; 194 + if (m->hov == c) 195 + scm = SchemeHov; 196 + else if (m->sel == c) 197 + scm = SchemeSel; 198 + else if (HIDDEN(c)) 199 + scm = SchemeHid; 200 + else 201 + scm = SchemeNorm; 202 + drw_setscheme(drw, scheme[scm]); 203 + 204 + if (remainder >= 0) { 205 + if (remainder == 0) { 206 + tabw--; 207 + } 208 + remainder--; 209 + } 210 + drw_text(drw, x, 0, tabw, bh, lrpad / 2, c->name, 0); 211 + x += tabw; 212 + } 213 } else { 214 drw_setscheme(drw, scheme[SchemeNorm]); 215 drw_rect(drw, x, 0, w, bh, 1, 1); 216 } 217 } 218 + m->bt = n; 219 + m->btw = w; 220 drw_map(drw, m->barwin, 0, 0, m->ww, bh); 221 } 222 223 @@ -791,9 +843,17 @@ void 224 focus(Client *c) 225 { 226 if (!c || !ISVISIBLE(c)) 227 - for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); 228 - if (selmon->sel && selmon->sel != c) 229 + for (c = selmon->stack; c && (!ISVISIBLE(c) || HIDDEN(c)); c = c->snext); 230 + if (selmon->sel && selmon->sel != c) { 231 unfocus(selmon->sel, 0); 232 + 233 + if (selmon->hidsel) { 234 + hidewin(selmon->sel); 235 + if (c) 236 + arrange(c->mon); 237 + selmon->hidsel = 0; 238 + } 239 + } 240 if (c) { 241 if (c->mon != selmon) 242 selmon = c->mon; 243 @@ -837,28 +897,52 @@ focusmon(const Arg *arg) 244 } 245 246 void 247 -focusstack(const Arg *arg) 248 +focusstackvis(const Arg *arg) { 249 + focusstack(arg->i, 0); 250 +} 251 + 252 +void 253 +focusstackhid(const Arg *arg) { 254 + focusstack(arg->i, 1); 255 +} 256 + 257 +void 258 +focusstack(int inc, int hid) 259 { 260 Client *c = NULL, *i; 261 - 262 - if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen)) 263 + // if no client selected AND exclude hidden client; if client selected but fullscreened 264 + if ((!selmon->sel && !hid) || (selmon->sel && selmon->sel->isfullscreen && lockfullscreen)) 265 + return; 266 + if (!selmon->clients) 267 return; 268 - if (arg->i > 0) { 269 - for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); 270 + if (inc > 0) { 271 + if (selmon->sel) 272 + for (c = selmon->sel->next; 273 + c && (!ISVISIBLE(c) || (!hid && HIDDEN(c))); 274 + c = c->next); 275 if (!c) 276 - for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); 277 + for (c = selmon->clients; 278 + c && (!ISVISIBLE(c) || (!hid && HIDDEN(c))); 279 + c = c->next); 280 } else { 281 - for (i = selmon->clients; i != selmon->sel; i = i->next) 282 - if (ISVISIBLE(i)) 283 - c = i; 284 + if (selmon->sel) { 285 + for (i = selmon->clients; i != selmon->sel; i = i->next) 286 + if (ISVISIBLE(i) && !(!hid && HIDDEN(i))) 287 + c = i; 288 + } else 289 + c = selmon->clients; 290 if (!c) 291 for (; i; i = i->next) 292 - if (ISVISIBLE(i)) 293 + if (ISVISIBLE(i) && !(!hid && HIDDEN(i))) 294 c = i; 295 } 296 if (c) { 297 focus(c); 298 restack(selmon); 299 + if (HIDDEN(c)) { 300 + showwin(c); 301 + c->mon->hidsel = 1; 302 + } 303 } 304 } 305 306 @@ -968,6 +1052,36 @@ grabkeys(void) 307 } 308 } 309 310 +void 311 +hide(const Arg *arg) 312 +{ 313 + hidewin(selmon->sel); 314 + focus(NULL); 315 + arrange(selmon); 316 +} 317 + 318 +void 319 +hidewin(Client *c) { 320 + if (!c || HIDDEN(c)) 321 + return; 322 + 323 + Window w = c->win; 324 + static XWindowAttributes ra, ca; 325 + 326 + // more or less taken directly from blackbox's hide() function 327 + XGrabServer(dpy); 328 + XGetWindowAttributes(dpy, root, &ra); 329 + XGetWindowAttributes(dpy, w, &ca); 330 + // prevent UnmapNotify events 331 + XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask); 332 + XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask); 333 + XUnmapWindow(dpy, w); 334 + setclientstate(c, IconicState); 335 + XSelectInput(dpy, root, ra.your_event_mask); 336 + XSelectInput(dpy, w, ca.your_event_mask); 337 + XUngrabServer(dpy); 338 +} 339 + 340 void 341 incnmaster(const Arg *arg) 342 { 343 @@ -1070,12 +1184,14 @@ manage(Window w, XWindowAttributes *wa) 344 XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, 345 (unsigned char *) &(c->win), 1); 346 XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ 347 - setclientstate(c, NormalState); 348 + if (!HIDDEN(c)) 349 + setclientstate(c, NormalState); 350 if (c->mon == selmon) 351 unfocus(selmon->sel, 0); 352 c->mon->sel = c; 353 arrange(c->mon); 354 - XMapWindow(dpy, c->win); 355 + if (!HIDDEN(c)) 356 + XMapWindow(dpy, c->win); 357 focus(NULL); 358 } 359 360 @@ -1119,18 +1235,76 @@ monocle(Monitor *m) 361 void 362 motionnotify(XEvent *e) 363 { 364 + int x, i; 365 static Monitor *mon = NULL; 366 + Client *c; 367 Monitor *m; 368 XMotionEvent *ev = &e->xmotion; 369 370 - if (ev->window != root) 371 + if (ev->window != selmon->barwin) { 372 + if (selmon->hov) { 373 + if (selmon->hov != selmon->sel) 374 + XSetWindowBorder(dpy, selmon->hov->win, scheme[SchemeNorm][ColBorder].pixel); 375 + else 376 + XSetWindowBorder(dpy, selmon->hov->win, scheme[SchemeSel][ColBorder].pixel); 377 + 378 + selmon->hov = NULL; 379 + c = wintoclient(ev->window); 380 + m = c ? c->mon : wintomon(ev->window); 381 + drawbar(m); 382 + } 383 + 384 + if (ev->window == root) { 385 + if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { 386 + unfocus(selmon->sel, 1); 387 + selmon = m; 388 + focus(NULL); 389 + } 390 + mon = m; 391 + } 392 + 393 return; 394 - if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { 395 - unfocus(selmon->sel, 1); 396 - selmon = m; 397 - focus(NULL); 398 } 399 - mon = m; 400 + 401 + c = wintoclient(ev->window); 402 + m = c ? c->mon : wintomon(ev->window); 403 + c = m->clients; 404 + 405 + x = 0, i = 0; 406 + do 407 + x += TEXTW(tags[i]); 408 + while (ev->x >= x && ++i < LENGTH(tags)); 409 + if (i < LENGTH(tags) || ev->x < x + TEXTW(selmon->ltsymbol) || ev->x > selmon->ww - TEXTW(stext) + lrpad - 2) { 410 + if (selmon->hov) { 411 + if (selmon->hov != selmon->sel) 412 + XSetWindowBorder(dpy, selmon->hov->win, scheme[SchemeNorm][ColBorder].pixel); 413 + else 414 + XSetWindowBorder(dpy, selmon->hov->win, scheme[SchemeSel][ColBorder].pixel); 415 + selmon->hov = NULL; 416 + drawbar(m); 417 + } 418 + } else { 419 + x += TEXTW(selmon->ltsymbol); 420 + if (c) { 421 + do { 422 + if (!ISVISIBLE(c)) 423 + continue; 424 + else 425 + x +=(1.0 / (double)m->bt) * m->btw; 426 + } while (ev->x > x && (c = c->next)); 427 + if (c) { 428 + if (selmon->hov) { 429 + if (selmon->hov != selmon->sel) 430 + XSetWindowBorder(dpy, selmon->hov->win, scheme[SchemeNorm][ColBorder].pixel); 431 + else 432 + XSetWindowBorder(dpy, selmon->hov->win, scheme[SchemeSel][ColBorder].pixel); 433 + } 434 + selmon->hov = c; 435 + XSetWindowBorder(dpy, c->win, scheme[SchemeHov][ColBorder].pixel); 436 + } 437 + } 438 + drawbar(m); 439 + } 440 } 441 442 void 443 @@ -1196,7 +1370,7 @@ movemouse(const Arg *arg) 444 Client * 445 nexttiled(Client *c) 446 { 447 - for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); 448 + for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next); 449 return c; 450 } 451 452 @@ -1249,6 +1423,16 @@ propertynotify(XEvent *e) 453 void 454 quit(const Arg *arg) 455 { 456 + // fix: reloading dwm keeps all the hidden clients hidden 457 + Monitor *m; 458 + Client *c; 459 + for (m = mons; m; m = m->next) { 460 + if (m) { 461 + for (c = m->stack; c; c = c->next) 462 + if (c && HIDDEN(c)) showwin(c); 463 + } 464 + } 465 + 466 running = 0; 467 } 468 469 @@ -1610,6 +1794,42 @@ seturgent(Client *c, int urg) 470 XFree(wmh); 471 } 472 473 +void 474 +show(const Arg *arg) 475 +{ 476 + if (selmon->hidsel) 477 + selmon->hidsel = 0; 478 + showwin(selmon->sel); 479 +} 480 + 481 +void 482 +showall(const Arg *arg) 483 +{ 484 + Client *c = NULL; 485 + selmon->hidsel = 0; 486 + for (c = selmon->clients; c; c = c->next) { 487 + if (ISVISIBLE(c)) 488 + showwin(c); 489 + } 490 + if (!selmon->sel) { 491 + for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); 492 + if (c) 493 + focus(c); 494 + } 495 + restack(selmon); 496 +} 497 + 498 +void 499 +showwin(Client *c) 500 +{ 501 + if (!c || !HIDDEN(c)) 502 + return; 503 + 504 + XMapWindow(dpy, c->win); 505 + setclientstate(c, NormalState); 506 + arrange(c->mon); 507 +} 508 + 509 void 510 showhide(Client *c) 511 { 512 @@ -1744,6 +1964,23 @@ toggleview(const Arg *arg) 513 } 514 } 515 516 +void 517 +togglewin(const Arg *arg) 518 +{ 519 + Client *c = (Client*)arg->v; 520 + 521 + if (c == selmon->sel) { 522 + hidewin(c); 523 + focus(NULL); 524 + arrange(c->mon); 525 + } else { 526 + if (HIDDEN(c)) 527 + showwin(c); 528 + focus(c); 529 + restack(selmon); 530 + } 531 +} 532 + 533 void 534 unfocus(Client *c, int setfocus) 535 { 536 @@ -1815,6 +2052,7 @@ updatebars(void) 537 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); 538 XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); 539 XMapRaised(dpy, m->barwin); 540 + XSelectInput(dpy, m->barwin, ButtonPressMask|PointerMotionMask); 541 XSetClassHint(dpy, m->barwin, &ch); 542 } 543 }