sites

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

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