dwm-awesomebar-statuscmd-6.2.diff (12122B)
1 diff --git a/config.def.h b/config.def.h 2 index 1c0b587..0b92823 100644 3 --- a/config.def.h 4 +++ b/config.def.h 5 @@ -16,6 +16,7 @@ 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 + [SchemeHid] = { col_cyan, col_gray1, col_cyan }, 10 }; 11 12 /* tagging */ 13 @@ -59,6 +60,10 @@ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() 14 static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; 15 static const char *termcmd[] = { "st", NULL }; 16 17 +/* commands spawned when clicking statusbar, the mouse button pressed is exported as BUTTON */ 18 +static char *statuscmds[] = { "notify-send Mouse$BUTTON" }; 19 +static char *statuscmd[] = { "/bin/sh", "-c", NULL, NULL }; 20 + 21 static Key keys[] = { 22 /* modifier key function argument */ 23 { MODKEY, XK_p, spawn, {.v = dmenucmd } }, 24 @@ -102,8 +107,11 @@ static Button buttons[] = { 25 /* click event mask button function argument */ 26 { ClkLtSymbol, 0, Button1, setlayout, {0} }, 27 { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, 28 + { ClkWinTitle, 0, Button1, togglewin, {0} }, 29 { ClkWinTitle, 0, Button2, zoom, {0} }, 30 - { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, 31 + { ClkStatusText, 0, Button1, spawn, {.v = statuscmd } }, 32 + { ClkStatusText, 0, Button2, spawn, {.v = statuscmd } }, 33 + { ClkStatusText, 0, Button3, spawn, {.v = statuscmd } }, 34 { ClkClientWin, MODKEY, Button1, movemouse, {0} }, 35 { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, 36 { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, 37 diff --git a/dwm.c b/dwm.c 38 index 4465af1..d841477 100644 39 --- a/dwm.c 40 +++ b/dwm.c 41 @@ -50,6 +50,7 @@ 42 #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ 43 * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) 44 #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) 45 +#define HIDDEN(C) ((getstate(C->win) == IconicState)) 46 #define LENGTH(X) (sizeof X / sizeof X[0]) 47 #define MOUSEMASK (BUTTONMASK|PointerMotionMask) 48 #define WIDTH(X) ((X)->w + 2 * (X)->bw) 49 @@ -59,7 +60,7 @@ 50 51 /* enums */ 52 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ 53 -enum { SchemeNorm, SchemeSel }; /* color schemes */ 54 +enum { SchemeNorm, SchemeSel, SchemeHid }; /* color schemes */ 55 enum { NetSupported, NetWMName, NetWMState, NetWMCheck, 56 NetWMFullscreen, NetActiveWindow, NetWMWindowType, 57 NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ 58 @@ -117,6 +118,8 @@ struct Monitor { 59 int nmaster; 60 int num; 61 int by; /* bar geometry */ 62 + int btw; /* width of tasks portion of bar */ 63 + int bt; /* number of tasks */ 64 int mx, my, mw, mh; /* screen size */ 65 int wx, wy, ww, wh; /* window area */ 66 unsigned int seltags; 67 @@ -156,6 +159,7 @@ static void clientmessage(XEvent *e); 68 static void configure(Client *c); 69 static void configurenotify(XEvent *e); 70 static void configurerequest(XEvent *e); 71 +static void copyvalidchars(char *text, char *rawtext); 72 static Monitor *createmon(void); 73 static void destroynotify(XEvent *e); 74 static void detach(Client *c); 75 @@ -174,6 +178,7 @@ static long getstate(Window w); 76 static int gettextprop(Window w, Atom atom, char *text, unsigned int size); 77 static void grabbuttons(Client *c, int focused); 78 static void grabkeys(void); 79 +static void hide(Client *c); 80 static void incnmaster(const Arg *arg); 81 static void keypress(XEvent *e); 82 static void killclient(const Arg *arg); 83 @@ -203,6 +208,7 @@ static void setlayout(const Arg *arg); 84 static void setmfact(const Arg *arg); 85 static void setup(void); 86 static void seturgent(Client *c, int urg); 87 +static void show(Client *c); 88 static void showhide(Client *c); 89 static void sigchld(int unused); 90 static void spawn(const Arg *arg); 91 @@ -213,6 +219,7 @@ static void togglebar(const Arg *arg); 92 static void togglefloating(const Arg *arg); 93 static void toggletag(const Arg *arg); 94 static void toggleview(const Arg *arg); 95 +static void togglewin(const Arg *arg); 96 static void unfocus(Client *c, int setfocus); 97 static void unmanage(Client *c, int destroyed); 98 static void unmapnotify(XEvent *e); 99 @@ -237,6 +244,9 @@ static void zoom(const Arg *arg); 100 /* variables */ 101 static const char broken[] = "broken"; 102 static char stext[256]; 103 +static char rawstext[256]; 104 +static int statuscmdn; 105 +static char lastbutton[] = "-"; 106 static int screen; 107 static int sw, sh; /* X display screen geometry width, height */ 108 static int bh, blw = 0; /* bar geometry */ 109 @@ -421,6 +431,7 @@ buttonpress(XEvent *e) 110 Client *c; 111 Monitor *m; 112 XButtonPressedEvent *ev = &e->xbutton; 113 + *lastbutton = '0' + ev->button; 114 115 click = ClkRootWin; 116 /* focus monitor if necessary */ 117 @@ -439,10 +450,43 @@ buttonpress(XEvent *e) 118 arg.ui = 1 << i; 119 } else if (ev->x < x + blw) 120 click = ClkLtSymbol; 121 - else if (ev->x > selmon->ww - TEXTW(stext)) 122 + /* 2px right padding */ 123 + else if (ev->x > (selmon->ww - TEXTW(stext) + lrpad) - 2) { 124 + x = selmon->ww - TEXTW(stext) + lrpad - 2; 125 click = ClkStatusText; 126 - else 127 - click = ClkWinTitle; 128 + 129 + char *text = rawstext; 130 + int i = -1; 131 + char ch; 132 + statuscmdn = 0; 133 + while (text[++i]) { 134 + if ((unsigned char)text[i] < ' ') { 135 + ch = text[i]; 136 + text[i] = '\0'; 137 + x += TEXTW(text) - lrpad; 138 + text[i] = ch; 139 + text += i+1; 140 + i = -1; 141 + if (x >= ev->x) break; 142 + if (ch <= LENGTH(statuscmds)) statuscmdn = ch - 1; 143 + } 144 + } 145 + } else { 146 + x += blw; 147 + c = m->clients; 148 + 149 + if (c) { 150 + do { 151 + if (!ISVISIBLE(c)) 152 + continue; 153 + else 154 + x += (1.0 / (double)m->bt) * m->btw; 155 + } while (ev->x > x && (c = c->next)); 156 + 157 + click = ClkWinTitle; 158 + arg.v = c; 159 + } 160 + } 161 } else if ((c = wintoclient(ev->window))) { 162 focus(c); 163 restack(selmon); 164 @@ -452,7 +496,7 @@ buttonpress(XEvent *e) 165 for (i = 0; i < LENGTH(buttons); i++) 166 if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button 167 && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) 168 - buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); 169 + buttons[i].func((click == ClkTagBar || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); 170 } 171 172 void 173 @@ -627,6 +671,19 @@ configurerequest(XEvent *e) 174 XSync(dpy, False); 175 } 176 177 +void 178 +copyvalidchars(char *text, char *rawtext) 179 +{ 180 + int i = -1, j = 0; 181 + 182 + while(rawtext[++i]) { 183 + if ((unsigned char)rawtext[i] >= ' ') { 184 + text[j++] = rawtext[i]; 185 + } 186 + } 187 + text[j] = '\0'; 188 +} 189 + 190 Monitor * 191 createmon(void) 192 { 193 @@ -695,7 +752,7 @@ dirtomon(int dir) 194 void 195 drawbar(Monitor *m) 196 { 197 - int x, w, sw = 0; 198 + int x, w, sw = 0, n = 0, scm; 199 int boxs = drw->fonts->h / 9; 200 int boxw = drw->fonts->h / 6 + 2; 201 unsigned int i, occ = 0, urg = 0; 202 @@ -709,6 +766,8 @@ drawbar(Monitor *m) 203 } 204 205 for (c = m->clients; c; c = c->next) { 206 + if (ISVISIBLE(c)) 207 + n++; 208 occ |= c->tags; 209 if (c->isurgent) 210 urg |= c->tags; 211 @@ -729,16 +788,37 @@ drawbar(Monitor *m) 212 x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); 213 214 if ((w = m->ww - sw - x) > bh) { 215 - if (m->sel) { 216 - drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); 217 - drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); 218 - if (m->sel->isfloating) 219 - drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); 220 + if (n > 0) { 221 + int remainder = w % n; 222 + int tabw = (1.0 / (double)n) * w + 1; 223 + for (c = m->clients; c; c = c->next) { 224 + if (!ISVISIBLE(c)) 225 + continue; 226 + if (m->sel == c) 227 + scm = SchemeSel; 228 + else if (HIDDEN(c)) 229 + scm = SchemeHid; 230 + else 231 + scm = SchemeNorm; 232 + drw_setscheme(drw, scheme[scm]); 233 + 234 + if (remainder >= 0) { 235 + if (remainder == 0) { 236 + tabw--; 237 + } 238 + remainder--; 239 + } 240 + drw_text(drw, x, 0, tabw, bh, lrpad / 2, c->name, 0); 241 + x += tabw; 242 + } 243 } else { 244 drw_setscheme(drw, scheme[SchemeNorm]); 245 drw_rect(drw, x, 0, w, bh, 1, 1); 246 } 247 } 248 + 249 + m->bt = n; 250 + m->btw = w; 251 drw_map(drw, m->barwin, 0, 0, m->ww, bh); 252 } 253 254 @@ -783,8 +863,8 @@ expose(XEvent *e) 255 void 256 focus(Client *c) 257 { 258 - if (!c || !ISVISIBLE(c)) 259 - for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); 260 + if (!c || !ISVISIBLE(c) || HIDDEN(c)) 261 + for (c = selmon->stack; c && (!ISVISIBLE(c) || HIDDEN(c)); c = c->snext); 262 if (selmon->sel && selmon->sel != c) 263 unfocus(selmon->sel, 0); 264 if (c) { 265 @@ -963,6 +1043,31 @@ grabkeys(void) 266 } 267 } 268 269 +void 270 +hide(Client *c) { 271 + if (!c || HIDDEN(c)) 272 + return; 273 + 274 + Window w = c->win; 275 + static XWindowAttributes ra, ca; 276 + 277 + // more or less taken directly from blackbox's hide() function 278 + XGrabServer(dpy); 279 + XGetWindowAttributes(dpy, root, &ra); 280 + XGetWindowAttributes(dpy, w, &ca); 281 + // prevent UnmapNotify events 282 + XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask); 283 + XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask); 284 + XUnmapWindow(dpy, w); 285 + setclientstate(c, IconicState); 286 + XSelectInput(dpy, root, ra.your_event_mask); 287 + XSelectInput(dpy, w, ca.your_event_mask); 288 + XUngrabServer(dpy); 289 + 290 + focus(c->snext); 291 + arrange(c->mon); 292 +} 293 + 294 void 295 incnmaster(const Arg *arg) 296 { 297 @@ -1067,12 +1172,14 @@ manage(Window w, XWindowAttributes *wa) 298 XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, 299 (unsigned char *) &(c->win), 1); 300 XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ 301 - setclientstate(c, NormalState); 302 + if (!HIDDEN(c)) 303 + setclientstate(c, NormalState); 304 if (c->mon == selmon) 305 unfocus(selmon->sel, 0); 306 c->mon->sel = c; 307 arrange(c->mon); 308 - XMapWindow(dpy, c->win); 309 + if (!HIDDEN(c)) 310 + XMapWindow(dpy, c->win); 311 focus(NULL); 312 } 313 314 @@ -1195,7 +1302,7 @@ movemouse(const Arg *arg) 315 Client * 316 nexttiled(Client *c) 317 { 318 - for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); 319 + for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next); 320 return c; 321 } 322 323 @@ -1248,6 +1355,16 @@ propertynotify(XEvent *e) 324 void 325 quit(const Arg *arg) 326 { 327 + // fix: reloading dwm keeps all the hidden clients hidden 328 + Monitor *m; 329 + Client *c; 330 + for (m = mons; m; m = m->next) { 331 + if (m) { 332 + for (c = m->stack; c; c = c->next) 333 + if (c && HIDDEN(c)) show(c); 334 + } 335 + } 336 + 337 running = 0; 338 } 339 340 @@ -1610,6 +1727,17 @@ seturgent(Client *c, int urg) 341 XFree(wmh); 342 } 343 344 +void 345 +show(Client *c) 346 +{ 347 + if (!c || !HIDDEN(c)) 348 + return; 349 + 350 + XMapWindow(dpy, c->win); 351 + setclientstate(c, NormalState); 352 + arrange(c->mon); 353 +} 354 + 355 void 356 showhide(Client *c) 357 { 358 @@ -1641,6 +1769,10 @@ spawn(const Arg *arg) 359 { 360 if (arg->v == dmenucmd) 361 dmenumon[0] = '0' + selmon->num; 362 + else if (arg->v == statuscmd) { 363 + statuscmd[2] = statuscmds[statuscmdn]; 364 + setenv("BUTTON", lastbutton, 1); 365 + } 366 if (fork() == 0) { 367 if (dpy) 368 close(ConnectionNumber(dpy)); 369 @@ -1746,6 +1878,20 @@ toggleview(const Arg *arg) 370 } 371 } 372 373 +void 374 +togglewin(const Arg *arg) 375 +{ 376 + Client *c = (Client*)arg->v; 377 + if (c == selmon->sel) 378 + hide(c); 379 + else { 380 + if (HIDDEN(c)) 381 + show(c); 382 + focus(c); 383 + restack(selmon); 384 + } 385 +} 386 + 387 void 388 unfocus(Client *c, int setfocus) 389 { 390 @@ -1987,8 +2133,10 @@ updatesizehints(Client *c) 391 void 392 updatestatus(void) 393 { 394 - if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) 395 + if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) 396 strcpy(stext, "dwm-"VERSION); 397 + else 398 + copyvalidchars(stext, rawstext); 399 drawbar(selmon); 400 } 401