dwm-anybar-polybar-tray-fix-20200721-bb2e722.diff (12360B)
1 From 62286f56a59ebd0ef7ee1308dd957d09c1ad0b11 Mon Sep 17 00:00:00 2001 2 From: mihirlad55 <mihirlad55@gmail.com> 3 Date: Tue, 21 Jul 2020 01:32:06 +0000 4 Subject: [PATCH] Add support for managing external status bars 5 6 This patch allows dwm to manage other status bars such as 7 polybar/lemonbar without them needing to set override-redirect. For 8 all intents and purposes, DWM treats this bar as if it were its own 9 and as a result helps the status bar and DWM live in harmony. 10 11 This has a few advantages 12 * The bar does not block fullscreen windows 13 * DWM makes room for the status bar, so windows do not overlap the bar 14 * The bar can be hidden/killed and DWM will not keep an unsightly gap 15 where the bar was 16 * DWM receives EnterNotify events when your cursor enters the bar 17 18 To use another status bar, set usealtbar to 1 in your config.h and set 19 altbarclass to the class name (can be found using xprop) to the class 20 name of your status bar. Also make sure that if your status bar will 21 be displayed on top, topbar is set to 1 in your config, and if it will 22 be displayed on bottom, topbar is set to 0. This patch does not 23 support bars that are not docked at the top or at the bottom of your 24 monitor. 25 26 This verison of the patch fixes handling of polybar's tray. 27 28 The patch is developed at https://github.com/mihirlad55/dwm-anybar 29 --- 30 config.def.h | 3 + 31 dwm.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++----- 32 2 files changed, 171 insertions(+), 15 deletions(-) 33 34 diff --git a/config.def.h b/config.def.h 35 index 1c0b587..6dc83bd 100644 36 --- a/config.def.h 37 +++ b/config.def.h 38 @@ -5,6 +5,9 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ 39 static const unsigned int snap = 32; /* snap pixel */ 40 static const int showbar = 1; /* 0 means no bar */ 41 static const int topbar = 1; /* 0 means bottom bar */ 42 +static const int usealtbar = 1; /* 1 means use non-dwm status bar */ 43 +static const char *altbarclass = "Polybar"; /* Alternate bar class name */ 44 +static const char *alttrayname = "tray"; /* Polybar tray instance name */ 45 static const char *fonts[] = { "monospace:size=10" }; 46 static const char dmenufont[] = "monospace:size=10"; 47 static const char col_gray1[] = "#222222"; 48 diff --git a/dwm.c b/dwm.c 49 index 9fd0286..c8fd4b2 100644 50 --- a/dwm.c 51 +++ b/dwm.c 52 @@ -47,8 +47,8 @@ 53 /* macros */ 54 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) 55 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) 56 -#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ 57 - * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) 58 +#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->mx+(m)->mw) - MAX((x),(m)->mx)) \ 59 + * MAX(0, MIN((y)+(h),(m)->my+(m)->mh) - MAX((y),(m)->my))) 60 #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) 61 #define LENGTH(X) (sizeof X / sizeof X[0]) 62 #define MOUSEMASK (BUTTONMASK|PointerMotionMask) 63 @@ -116,7 +116,8 @@ struct Monitor { 64 float mfact; 65 int nmaster; 66 int num; 67 - int by; /* bar geometry */ 68 + int by, bh; /* bar geometry */ 69 + int tx, tw; /* bar tray geometry */ 70 int mx, my, mw, mh; /* screen size */ 71 int wx, wy, ww, wh; /* window area */ 72 unsigned int seltags; 73 @@ -129,6 +130,7 @@ struct Monitor { 74 Client *stack; 75 Monitor *next; 76 Window barwin; 77 + Window traywin; 78 const Layout *lt[2]; 79 }; 80 81 @@ -179,6 +181,8 @@ static void incnmaster(const Arg *arg); 82 static void keypress(XEvent *e); 83 static void killclient(const Arg *arg); 84 static void manage(Window w, XWindowAttributes *wa); 85 +static void managealtbar(Window win, XWindowAttributes *wa); 86 +static void managetray(Window win, XWindowAttributes *wa); 87 static void mappingnotify(XEvent *e); 88 static void maprequest(XEvent *e); 89 static void monocle(Monitor *m); 90 @@ -195,6 +199,7 @@ static void resizemouse(const Arg *arg); 91 static void restack(Monitor *m); 92 static void run(void); 93 static void scan(void); 94 +static void scantray(void); 95 static int sendevent(Client *c, Atom proto); 96 static void sendmon(Client *c, Monitor *m); 97 static void setclientstate(Client *c, long state); 98 @@ -216,6 +221,8 @@ static void toggletag(const Arg *arg); 99 static void toggleview(const Arg *arg); 100 static void unfocus(Client *c, int setfocus); 101 static void unmanage(Client *c, int destroyed); 102 +static void unmanagealtbar(Window w); 103 +static void unmanagetray(Window w); 104 static void unmapnotify(XEvent *e); 105 static void updatebarpos(Monitor *m); 106 static void updatebars(void); 107 @@ -230,6 +237,7 @@ static void updatewmhints(Client *c); 108 static void view(const Arg *arg); 109 static Client *wintoclient(Window w); 110 static Monitor *wintomon(Window w); 111 +static int wmclasscontains(Window win, const char *class, const char *name); 112 static int xerror(Display *dpy, XErrorEvent *ee); 113 static int xerrordummy(Display *dpy, XErrorEvent *ee); 114 static int xerrorstart(Display *dpy, XErrorEvent *ee); 115 @@ -505,8 +513,10 @@ cleanupmon(Monitor *mon) 116 for (m = mons; m && m->next != mon; m = m->next); 117 m->next = mon->next; 118 } 119 - XUnmapWindow(dpy, mon->barwin); 120 - XDestroyWindow(dpy, mon->barwin); 121 + if (!usealtbar) { 122 + XUnmapWindow(dpy, mon->barwin); 123 + XDestroyWindow(dpy, mon->barwin); 124 + } 125 free(mon); 126 } 127 128 @@ -568,7 +578,7 @@ configurenotify(XEvent *e) 129 for (c = m->clients; c; c = c->next) 130 if (c->isfullscreen) 131 resizeclient(c, m->mx, m->my, m->mw, m->mh); 132 - XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); 133 + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, m->bh); 134 } 135 focus(NULL); 136 arrange(NULL); 137 @@ -639,6 +649,7 @@ createmon(void) 138 m->nmaster = nmaster; 139 m->showbar = showbar; 140 m->topbar = topbar; 141 + m->bh = bh; 142 m->lt[0] = &layouts[0]; 143 m->lt[1] = &layouts[1 % LENGTH(layouts)]; 144 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); 145 @@ -649,10 +660,15 @@ void 146 destroynotify(XEvent *e) 147 { 148 Client *c; 149 + Monitor *m; 150 XDestroyWindowEvent *ev = &e->xdestroywindow; 151 152 if ((c = wintoclient(ev->window))) 153 unmanage(c, 1); 154 + else if ((m = wintomon(ev->window)) && m->barwin == ev->window) 155 + unmanagealtbar(ev->window); 156 + else if (m->traywin == ev->window) 157 + unmanagetray(ev->window); 158 } 159 160 void 161 @@ -696,6 +712,9 @@ dirtomon(int dir) 162 void 163 drawbar(Monitor *m) 164 { 165 + if (usealtbar) 166 + return; 167 + 168 int x, w, tw = 0; 169 int boxs = drw->fonts->h / 9; 170 int boxw = drw->fonts->h / 6 + 2; 171 @@ -1077,6 +1096,45 @@ manage(Window w, XWindowAttributes *wa) 172 focus(NULL); 173 } 174 175 +void 176 +managealtbar(Window win, XWindowAttributes *wa) 177 +{ 178 + Monitor *m; 179 + if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height))) 180 + return; 181 + 182 + m->barwin = win; 183 + m->by = wa->y; 184 + bh = m->bh = wa->height; 185 + updatebarpos(m); 186 + arrange(m); 187 + XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); 188 + XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height); 189 + XMapWindow(dpy, win); 190 + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, 191 + (unsigned char *) &win, 1); 192 +} 193 + 194 +void 195 +managetray(Window win, XWindowAttributes *wa) 196 +{ 197 + Monitor *m; 198 + if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height))) 199 + return; 200 + 201 + m->traywin = win; 202 + m->tx = wa->x; 203 + m->tw = wa->width; 204 + updatebarpos(m); 205 + arrange(m); 206 + XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); 207 + XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height); 208 + XMapWindow(dpy, win); 209 + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, 210 + (unsigned char *) &win, 1); 211 +} 212 + 213 + 214 void 215 mappingnotify(XEvent *e) 216 { 217 @@ -1097,7 +1155,9 @@ maprequest(XEvent *e) 218 return; 219 if (wa.override_redirect) 220 return; 221 - if (!wintoclient(ev->window)) 222 + if (wmclasscontains(ev->window, altbarclass, "")) 223 + managealtbar(ev->window, &wa); 224 + else if (!wintoclient(ev->window)) 225 manage(ev->window, &wa); 226 } 227 228 @@ -1393,7 +1453,9 @@ scan(void) 229 if (!XGetWindowAttributes(dpy, wins[i], &wa) 230 || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) 231 continue; 232 - if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) 233 + if (wmclasscontains(wins[i], altbarclass, "")) 234 + managealtbar(wins[i], &wa); 235 + else if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) 236 manage(wins[i], &wa); 237 } 238 for (i = 0; i < num; i++) { /* now the transients */ 239 @@ -1408,6 +1470,29 @@ scan(void) 240 } 241 } 242 243 +void 244 +scantray(void) 245 +{ 246 + unsigned int num; 247 + Window d1, d2, *wins = NULL; 248 + XWindowAttributes wa; 249 + 250 + if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { 251 + for (unsigned int i = 0; i < num; i++) { 252 + if (wmclasscontains(wins[i], altbarclass, alttrayname)) { 253 + if (!XGetWindowAttributes(dpy, wins[i], &wa)) 254 + break; 255 + managetray(wins[i], &wa); 256 + } 257 + } 258 + } 259 + 260 + if (wins) 261 + XFree(wins); 262 +} 263 + 264 + 265 + 266 void 267 sendmon(Client *c, Monitor *m) 268 { 269 @@ -1546,7 +1631,7 @@ setup(void) 270 if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) 271 die("no fonts could be loaded."); 272 lrpad = drw->fonts->h; 273 - bh = drw->fonts->h + 2; 274 + bh = usealtbar ? 0 : drw->fonts->h + 2; 275 updategeom(); 276 /* init atoms */ 277 utf8string = XInternAtom(dpy, "UTF8_STRING", False); 278 @@ -1702,9 +1787,18 @@ tile(Monitor *m) 279 void 280 togglebar(const Arg *arg) 281 { 282 + /** 283 + * Polybar tray does not raise maprequest event. It must be manually scanned 284 + * for. Scanning it too early while the tray is being populated would give 285 + * wrong dimensions. 286 + */ 287 + if (!selmon->traywin) 288 + scantray(); 289 + 290 selmon->showbar = !selmon->showbar; 291 updatebarpos(selmon); 292 - XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); 293 + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, selmon->bh); 294 + XMoveResizeWindow(dpy, selmon->traywin, selmon->tx, selmon->by, selmon->tw, selmon->bh); 295 arrange(selmon); 296 } 297 298 @@ -1787,10 +1881,41 @@ unmanage(Client *c, int destroyed) 299 arrange(m); 300 } 301 302 +void 303 +unmanagealtbar(Window w) 304 +{ 305 + Monitor *m = wintomon(w); 306 + 307 + if (!m) 308 + return; 309 + 310 + m->barwin = 0; 311 + m->by = 0; 312 + m->bh = 0; 313 + updatebarpos(m); 314 + arrange(m); 315 +} 316 + 317 +void 318 +unmanagetray(Window w) 319 +{ 320 + Monitor *m = wintomon(w); 321 + 322 + if (!m) 323 + return; 324 + 325 + m->traywin = 0; 326 + m->tx = 0; 327 + m->tw = 0; 328 + updatebarpos(m); 329 + arrange(m); 330 +} 331 + 332 void 333 unmapnotify(XEvent *e) 334 { 335 Client *c; 336 + Monitor *m; 337 XUnmapEvent *ev = &e->xunmap; 338 339 if ((c = wintoclient(ev->window))) { 340 @@ -1798,12 +1923,18 @@ unmapnotify(XEvent *e) 341 setclientstate(c, WithdrawnState); 342 else 343 unmanage(c, 0); 344 - } 345 + } else if ((m = wintomon(ev->window)) && m->barwin == ev->window) 346 + unmanagealtbar(ev->window); 347 + else if (m->traywin == ev->window) 348 + unmanagetray(ev->window); 349 } 350 351 void 352 updatebars(void) 353 { 354 + if (usealtbar) 355 + return; 356 + 357 Monitor *m; 358 XSetWindowAttributes wa = { 359 .override_redirect = True, 360 @@ -1829,11 +1960,11 @@ updatebarpos(Monitor *m) 361 m->wy = m->my; 362 m->wh = m->mh; 363 if (m->showbar) { 364 - m->wh -= bh; 365 + m->wh -= m->bh; 366 m->by = m->topbar ? m->wy : m->wy + m->wh; 367 - m->wy = m->topbar ? m->wy + bh : m->wy; 368 + m->wy = m->topbar ? m->wy + m->bh : m->wy; 369 } else 370 - m->by = -bh; 371 + m->by = -m->bh; 372 } 373 374 void 375 @@ -2070,13 +2201,35 @@ wintomon(Window w) 376 if (w == root && getrootptr(&x, &y)) 377 return recttomon(x, y, 1, 1); 378 for (m = mons; m; m = m->next) 379 - if (w == m->barwin) 380 + if (w == m->barwin || w == m->traywin) 381 return m; 382 if ((c = wintoclient(w))) 383 return c->mon; 384 return selmon; 385 } 386 387 +int 388 +wmclasscontains(Window win, const char *class, const char *name) 389 +{ 390 + XClassHint ch = { NULL, NULL }; 391 + int res = 1; 392 + 393 + if (XGetClassHint(dpy, win, &ch)) { 394 + if (ch.res_name && strstr(ch.res_name, name) == NULL) 395 + res = 0; 396 + if (ch.res_class && strstr(ch.res_class, class) == NULL) 397 + res = 0; 398 + } else 399 + res = 0; 400 + 401 + if (ch.res_class) 402 + XFree(ch.res_class); 403 + if (ch.res_name) 404 + XFree(ch.res_name); 405 + 406 + return res; 407 +} 408 + 409 /* There's no way to check accesses to destroyed windows, thus those cases are 410 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs 411 * default error handler, which may call exit. */ 412 -- 413 2.27.0 414