dwm-anybar-polybar-tray-fix-20200810-bb2e722.diff - sites - public wiki contents of suckless.org
 (HTM) git clone git://git.suckless.org/sites
 (DIR) Log
 (DIR) Files
 (DIR) 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