sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

dwm-anybar-polybar-tray-fix-20200810-bb2e722.diff (13021B)


      1 From 9b5719969ce85c3ecc0238d49c0255c5c2cc79f0 Mon Sep 17 00:00:00 2001
      2 From: mihirlad55 <mihirlad55@gmail.com>
      3 Date: Mon, 10 Aug 2020 01:39:28 +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 |   4 ++
     31  dwm.c        | 192 +++++++++++++++++++++++++++++++++++++++++++++++----
     32  2 files changed, 181 insertions(+), 15 deletions(-)
     33 
     34 diff --git a/config.def.h b/config.def.h
     35 index 1c0b587..f45211b 100644
     36 --- a/config.def.h
     37 +++ b/config.def.h
     38 @@ -5,6 +5,10 @@ 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 *altbarcmd        = "$HOME/bar.sh"; /* Alternate bar launch command */
     46  static const char *fonts[]          = { "monospace:size=10" };
     47  static const char dmenufont[]       = "monospace:size=10";
     48  static const char col_gray1[]       = "#222222";
     49 diff --git a/dwm.c b/dwm.c
     50 index 9fd0286..c1d8ce0 100644
     51 --- a/dwm.c
     52 +++ b/dwm.c
     53 @@ -47,8 +47,8 @@
     54  /* macros */
     55  #define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask)
     56  #define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
     57 -#define INTERSECT(x,y,w,h,m)    (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
     58 -                               * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
     59 +#define INTERSECT(x,y,w,h,m)    (MAX(0, MIN((x)+(w),(m)->mx+(m)->mw) - MAX((x),(m)->mx)) \
     60 +                               * MAX(0, MIN((y)+(h),(m)->my+(m)->mh) - MAX((y),(m)->my)))
     61  #define ISVISIBLE(C)            ((C->tags & C->mon->tagset[C->mon->seltags]))
     62  #define LENGTH(X)               (sizeof X / sizeof X[0])
     63  #define MOUSEMASK               (BUTTONMASK|PointerMotionMask)
     64 @@ -116,7 +116,8 @@ struct Monitor {
     65  	float mfact;
     66  	int nmaster;
     67  	int num;
     68 -	int by;               /* bar geometry */
     69 +	int by, bh;           /* bar geometry */
     70 +	int tx, tw;           /* bar tray geometry */
     71  	int mx, my, mw, mh;   /* screen size */
     72  	int wx, wy, ww, wh;   /* window area  */
     73  	unsigned int seltags;
     74 @@ -129,6 +130,7 @@ struct Monitor {
     75  	Client *stack;
     76  	Monitor *next;
     77  	Window barwin;
     78 +	Window traywin;
     79  	const Layout *lt[2];
     80  };
     81  
     82 @@ -179,6 +181,8 @@ static void incnmaster(const Arg *arg);
     83  static void keypress(XEvent *e);
     84  static void killclient(const Arg *arg);
     85  static void manage(Window w, XWindowAttributes *wa);
     86 +static void managealtbar(Window win, XWindowAttributes *wa);
     87 +static void managetray(Window win, XWindowAttributes *wa);
     88  static void mappingnotify(XEvent *e);
     89  static void maprequest(XEvent *e);
     90  static void monocle(Monitor *m);
     91 @@ -195,6 +199,7 @@ static void resizemouse(const Arg *arg);
     92  static void restack(Monitor *m);
     93  static void run(void);
     94  static void scan(void);
     95 +static void scantray(void);
     96  static int sendevent(Client *c, Atom proto);
     97  static void sendmon(Client *c, Monitor *m);
     98  static void setclientstate(Client *c, long state);
     99 @@ -207,6 +212,7 @@ static void seturgent(Client *c, int urg);
    100  static void showhide(Client *c);
    101  static void sigchld(int unused);
    102  static void spawn(const Arg *arg);
    103 +static void spawnbar();
    104  static void tag(const Arg *arg);
    105  static void tagmon(const Arg *arg);
    106  static void tile(Monitor *);
    107 @@ -216,6 +222,8 @@ static void toggletag(const Arg *arg);
    108  static void toggleview(const Arg *arg);
    109  static void unfocus(Client *c, int setfocus);
    110  static void unmanage(Client *c, int destroyed);
    111 +static void unmanagealtbar(Window w);
    112 +static void unmanagetray(Window w);
    113  static void unmapnotify(XEvent *e);
    114  static void updatebarpos(Monitor *m);
    115  static void updatebars(void);
    116 @@ -230,6 +238,7 @@ static void updatewmhints(Client *c);
    117  static void view(const Arg *arg);
    118  static Client *wintoclient(Window w);
    119  static Monitor *wintomon(Window w);
    120 +static int wmclasscontains(Window win, const char *class, const char *name);
    121  static int xerror(Display *dpy, XErrorEvent *ee);
    122  static int xerrordummy(Display *dpy, XErrorEvent *ee);
    123  static int xerrorstart(Display *dpy, XErrorEvent *ee);
    124 @@ -505,8 +514,10 @@ cleanupmon(Monitor *mon)
    125  		for (m = mons; m && m->next != mon; m = m->next);
    126  		m->next = mon->next;
    127  	}
    128 -	XUnmapWindow(dpy, mon->barwin);
    129 -	XDestroyWindow(dpy, mon->barwin);
    130 +	if (!usealtbar) {
    131 +		XUnmapWindow(dpy, mon->barwin);
    132 +		XDestroyWindow(dpy, mon->barwin);
    133 +	}
    134  	free(mon);
    135  }
    136  
    137 @@ -568,7 +579,7 @@ configurenotify(XEvent *e)
    138  				for (c = m->clients; c; c = c->next)
    139  					if (c->isfullscreen)
    140  						resizeclient(c, m->mx, m->my, m->mw, m->mh);
    141 -				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
    142 +				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, m->bh);
    143  			}
    144  			focus(NULL);
    145  			arrange(NULL);
    146 @@ -639,6 +650,7 @@ createmon(void)
    147  	m->nmaster = nmaster;
    148  	m->showbar = showbar;
    149  	m->topbar = topbar;
    150 +	m->bh = bh;
    151  	m->lt[0] = &layouts[0];
    152  	m->lt[1] = &layouts[1 % LENGTH(layouts)];
    153  	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
    154 @@ -649,10 +661,15 @@ void
    155  destroynotify(XEvent *e)
    156  {
    157  	Client *c;
    158 +	Monitor *m;
    159  	XDestroyWindowEvent *ev = &e->xdestroywindow;
    160  
    161  	if ((c = wintoclient(ev->window)))
    162  		unmanage(c, 1);
    163 +	else if ((m = wintomon(ev->window)) && m->barwin == ev->window)
    164 +		unmanagealtbar(ev->window);
    165 +	else if (m->traywin == ev->window)
    166 +		unmanagetray(ev->window);
    167  }
    168  
    169  void
    170 @@ -696,6 +713,9 @@ dirtomon(int dir)
    171  void
    172  drawbar(Monitor *m)
    173  {
    174 +	if (usealtbar)
    175 +		return;
    176 +
    177  	int x, w, tw = 0;
    178  	int boxs = drw->fonts->h / 9;
    179  	int boxw = drw->fonts->h / 6 + 2;
    180 @@ -1077,6 +1097,45 @@ manage(Window w, XWindowAttributes *wa)
    181  	focus(NULL);
    182  }
    183  
    184 +void
    185 +managealtbar(Window win, XWindowAttributes *wa)
    186 +{
    187 +	Monitor *m;
    188 +	if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height)))
    189 +		return;
    190 +
    191 +	m->barwin = win;
    192 +	m->by = wa->y;
    193 +	bh = m->bh = wa->height;
    194 +	updatebarpos(m);
    195 +	arrange(m);
    196 +	XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
    197 +	XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height);
    198 +	XMapWindow(dpy, win);
    199 +	XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
    200 +		(unsigned char *) &win, 1);
    201 +}
    202 +
    203 +void
    204 +managetray(Window win, XWindowAttributes *wa)
    205 +{
    206 +	Monitor *m;
    207 +	if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height)))
    208 +		return;
    209 +
    210 +	m->traywin = win;
    211 +	m->tx = wa->x;
    212 +	m->tw = wa->width;
    213 +	updatebarpos(m);
    214 +	arrange(m);
    215 +	XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
    216 +	XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height);
    217 +	XMapWindow(dpy, win);
    218 +	XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
    219 +			(unsigned char *) &win, 1);
    220 +}
    221 +
    222 +
    223  void
    224  mappingnotify(XEvent *e)
    225  {
    226 @@ -1097,7 +1156,9 @@ maprequest(XEvent *e)
    227  		return;
    228  	if (wa.override_redirect)
    229  		return;
    230 -	if (!wintoclient(ev->window))
    231 +	if (wmclasscontains(ev->window, altbarclass, ""))
    232 +		managealtbar(ev->window, &wa);
    233 +	else if (!wintoclient(ev->window))
    234  		manage(ev->window, &wa);
    235  }
    236  
    237 @@ -1393,7 +1454,9 @@ scan(void)
    238  			if (!XGetWindowAttributes(dpy, wins[i], &wa)
    239  			|| wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
    240  				continue;
    241 -			if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
    242 +			if (wmclasscontains(wins[i], altbarclass, ""))
    243 +				managealtbar(wins[i], &wa);
    244 +			else if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
    245  				manage(wins[i], &wa);
    246  		}
    247  		for (i = 0; i < num; i++) { /* now the transients */
    248 @@ -1408,6 +1471,29 @@ scan(void)
    249  	}
    250  }
    251  
    252 +void
    253 +scantray(void)
    254 +{
    255 +	unsigned int num;
    256 +	Window d1, d2, *wins = NULL;
    257 +	XWindowAttributes wa;
    258 +
    259 +	if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
    260 +		for (unsigned int i = 0; i < num; i++) {
    261 +			if (wmclasscontains(wins[i], altbarclass, alttrayname)) {
    262 +				if (!XGetWindowAttributes(dpy, wins[i], &wa))
    263 +					break;
    264 +				managetray(wins[i], &wa);
    265 +			}
    266 +		}
    267 +	}
    268 +
    269 +	if (wins)
    270 +		XFree(wins);
    271 +}
    272 +
    273 +
    274 +
    275  void
    276  sendmon(Client *c, Monitor *m)
    277  {
    278 @@ -1546,7 +1632,7 @@ setup(void)
    279  	if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
    280  		die("no fonts could be loaded.");
    281  	lrpad = drw->fonts->h;
    282 -	bh = drw->fonts->h + 2;
    283 +	bh = usealtbar ? 0 : drw->fonts->h + 2;
    284  	updategeom();
    285  	/* init atoms */
    286  	utf8string = XInternAtom(dpy, "UTF8_STRING", False);
    287 @@ -1595,6 +1681,7 @@ setup(void)
    288  	XSelectInput(dpy, root, wa.event_mask);
    289  	grabkeys();
    290  	focus(NULL);
    291 +	spawnbar();
    292  }
    293  
    294  
    295 @@ -1653,6 +1740,13 @@ spawn(const Arg *arg)
    296  	}
    297  }
    298  
    299 +void
    300 +spawnbar()
    301 +{
    302 +	if (*altbarcmd)
    303 +		system(altbarcmd);
    304 +}
    305 +
    306  void
    307  tag(const Arg *arg)
    308  {
    309 @@ -1702,9 +1796,18 @@ tile(Monitor *m)
    310  void
    311  togglebar(const Arg *arg)
    312  {
    313 +	/**
    314 +     * Polybar tray does not raise maprequest event. It must be manually scanned
    315 +	 * for. Scanning it too early while the tray is being populated would give
    316 +	 * wrong dimensions.
    317 +     */
    318 +	if (!selmon->traywin)
    319 +		scantray();
    320 +
    321  	selmon->showbar = !selmon->showbar;
    322  	updatebarpos(selmon);
    323 -	XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
    324 +	XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, selmon->bh);
    325 +	XMoveResizeWindow(dpy, selmon->traywin, selmon->tx, selmon->by, selmon->tw, selmon->bh);
    326  	arrange(selmon);
    327  }
    328  
    329 @@ -1787,10 +1890,41 @@ unmanage(Client *c, int destroyed)
    330  	arrange(m);
    331  }
    332  
    333 +void
    334 +unmanagealtbar(Window w)
    335 +{
    336 +    Monitor *m = wintomon(w);
    337 +
    338 +    if (!m)
    339 +        return;
    340 +
    341 +    m->barwin = 0;
    342 +    m->by = 0;
    343 +    m->bh = 0;
    344 +    updatebarpos(m);
    345 +    arrange(m);
    346 +}
    347 +
    348 +void
    349 +unmanagetray(Window w)
    350 +{
    351 +	Monitor *m = wintomon(w);
    352 +
    353 +	if (!m)
    354 +		return;
    355 +
    356 +	m->traywin = 0;
    357 +	m->tx = 0;
    358 +	m->tw = 0;
    359 +	updatebarpos(m);
    360 +	arrange(m);
    361 +}
    362 +
    363  void
    364  unmapnotify(XEvent *e)
    365  {
    366  	Client *c;
    367 +	Monitor *m;
    368  	XUnmapEvent *ev = &e->xunmap;
    369  
    370  	if ((c = wintoclient(ev->window))) {
    371 @@ -1798,12 +1932,18 @@ unmapnotify(XEvent *e)
    372  			setclientstate(c, WithdrawnState);
    373  		else
    374  			unmanage(c, 0);
    375 -	}
    376 +	} else if ((m = wintomon(ev->window)) && m->barwin == ev->window)
    377 +		unmanagealtbar(ev->window);
    378 +	else if (m->traywin == ev->window)
    379 +		unmanagetray(ev->window);
    380  }
    381  
    382  void
    383  updatebars(void)
    384  {
    385 +	if (usealtbar)
    386 +		return;
    387 +
    388  	Monitor *m;
    389  	XSetWindowAttributes wa = {
    390  		.override_redirect = True,
    391 @@ -1829,11 +1969,11 @@ updatebarpos(Monitor *m)
    392  	m->wy = m->my;
    393  	m->wh = m->mh;
    394  	if (m->showbar) {
    395 -		m->wh -= bh;
    396 +		m->wh -= m->bh;
    397  		m->by = m->topbar ? m->wy : m->wy + m->wh;
    398 -		m->wy = m->topbar ? m->wy + bh : m->wy;
    399 +		m->wy = m->topbar ? m->wy + m->bh : m->wy;
    400  	} else
    401 -		m->by = -bh;
    402 +		m->by = -m->bh;
    403  }
    404  
    405  void
    406 @@ -2070,13 +2210,35 @@ wintomon(Window w)
    407  	if (w == root && getrootptr(&x, &y))
    408  		return recttomon(x, y, 1, 1);
    409  	for (m = mons; m; m = m->next)
    410 -		if (w == m->barwin)
    411 +		if (w == m->barwin || w == m->traywin)
    412  			return m;
    413  	if ((c = wintoclient(w)))
    414  		return c->mon;
    415  	return selmon;
    416  }
    417  
    418 +int
    419 +wmclasscontains(Window win, const char *class, const char *name)
    420 +{
    421 +	XClassHint ch = { NULL, NULL };
    422 +	int res = 1;
    423 +
    424 +	if (XGetClassHint(dpy, win, &ch)) {
    425 +		if (ch.res_name && strstr(ch.res_name, name) == NULL)
    426 +			res = 0;
    427 +		if (ch.res_class && strstr(ch.res_class, class) == NULL)
    428 +			res = 0;
    429 +	} else
    430 +		res = 0;
    431 +
    432 +	if (ch.res_class)
    433 +		XFree(ch.res_class);
    434 +	if (ch.res_name)
    435 +		XFree(ch.res_name);
    436 +
    437 +	return res;
    438 +}
    439 +
    440  /* There's no way to check accesses to destroyed windows, thus those cases are
    441   * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
    442   * default error handler, which may call exit. */
    443 -- 
    444 2.28.0
    445