diff --git a/config.def.h b/config.def.h index 5d720dc..36d689d 100644 --- a/config.def.h +++ b/config.def.h @@ -19,6 +19,11 @@ static const char *colors[][3] = { [SchemeSel] = { col_text, col_base, col_iris }, }; +// anybar config +static const int usealtbar = 1; /* 1 means use non-dwm status bar */ +static const char *altbarclass = "Polybar"; /* Alternate bar class name */ +static const char *altbarcmd = "$HOME/bar.sh"; /* Alternate bar launch command */ + /* tagging */ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; diff --git a/dwm.c b/dwm.c index 672a3d1..6a6fb1c 100644 --- a/dwm.c +++ b/dwm.c @@ -47,8 +47,8 @@ /* macros */ #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) -#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ - * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) +#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->mx+(m)->mw) - MAX((x),(m)->mx)) \ + * MAX(0, MIN((y)+(h),(m)->my+(m)->mh) - MAX((y),(m)->my))) #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define WIDTH(X) ((X)->w + 2 * (X)->bw) @@ -117,7 +117,7 @@ struct Monitor { float mfact; int nmaster; int num; - int by; /* bar geometry */ + int by, bh; /* bar geometry */ int mx, my, mw, mh; /* screen size */ int wx, wy, ww, wh; /* window area */ unsigned int seltags; @@ -181,6 +181,7 @@ static void incnmaster(const Arg *arg); static void keypress(XEvent *e); static void killclient(const Arg *arg); static void manage(Window w, XWindowAttributes *wa); +static void managealtbar(Window win, XWindowAttributes *wa); static void mappingnotify(XEvent *e); static void maprequest(XEvent *e); static void monocle(Monitor *m); @@ -209,6 +210,7 @@ static void setup(void); static void seturgent(Client *c, int urg); static void showhide(Client *c); static void spawn(const Arg *arg); +static void spawnbar(void); static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *m); @@ -218,6 +220,7 @@ static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unfocus(Client *c, int setfocus); static void unmanage(Client *c, int destroyed); +static void unmanagealtbar(Window w); static void unmapnotify(XEvent *e); static void updatebarpos(Monitor *m); static void updatebars(void); @@ -232,6 +235,7 @@ static void updatewmhints(Client *c); static void view(const Arg *arg); static Client *wintoclient(Window w); static Monitor *wintomon(Window w); +static int wmclasscontains(Window win, const char *class, const char *name); static int xerror(Display *dpy, XErrorEvent *ee); static int xerrordummy(Display *dpy, XErrorEvent *ee); static int xerrorstart(Display *dpy, XErrorEvent *ee); @@ -519,8 +523,10 @@ cleanupmon(Monitor *mon) for (m = mons; m && m->next != mon; m = m->next); m->next = mon->next; } - XUnmapWindow(dpy, mon->barwin); - XDestroyWindow(dpy, mon->barwin); + if (!usealtbar) { + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); + } free(mon); } @@ -582,7 +588,7 @@ configurenotify(XEvent *e) for (c = m->clients; c; c = c->next) if (c->isfullscreen) resizeclient(c, m->mx, m->my, m->mw, m->mh); - XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, m->bh); } focus(NULL); arrange(NULL); @@ -654,6 +660,7 @@ createmon(void) m->nmaster = nmaster; m->showbar = showbar; m->topbar = topbar; + m->bh = bh; m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); @@ -678,10 +685,13 @@ void destroynotify(XEvent *e) { Client *c; + Monitor *m; XDestroyWindowEvent *ev = &e->xdestroywindow; if ((c = wintoclient(ev->window))) unmanage(c, 1); + else if ((m = wintomon(ev->window)) && m->barwin == ev->window) + unmanagealtbar(ev->window); } void @@ -725,6 +735,9 @@ dirtomon(int dir) void drawbar(Monitor *m) { + if (usealtbar) + return; + int x, w, tw = 0; int boxs = drw->fonts->h / 9; int boxw = drw->fonts->h / 6 + 2; @@ -1135,6 +1148,25 @@ manage(Window w, XWindowAttributes *wa) focus(NULL); } +void +managealtbar(Window win, XWindowAttributes *wa) +{ + Monitor *m; + if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height))) + return; + + m->barwin = win; + m->by = wa->y; + bh = m->bh = wa->height; + updatebarpos(m); + arrange(m); + XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); + XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height); + XMapWindow(dpy, win); + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &win, 1); +} + void mappingnotify(XEvent *e) { @@ -1149,11 +1181,13 @@ void maprequest(XEvent *e) { static XWindowAttributes wa; - XMapRequestEvent *ev = &e->xmaprequest; + XMapRequestEvent *ev = &e->xaprequest; if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect) return; - if (!wintoclient(ev->window)) + if (wmclasscontains(ev->window, altbarclass, "")) + managealtbar(ev->window, &wa); + else if (!wintoclient(ev->window)) manage(ev->window, &wa); } @@ -1449,7 +1483,9 @@ scan(void) if (!XGetWindowAttributes(dpy, wins[i], &wa) || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) continue; - if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) + if (wmclasscontains(wins[i], altbarclass, "")) + managealtbar(wins[i], &wa); + else if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) manage(wins[i], &wa); } for (i = 0; i < num; i++) { /* now the transients */ @@ -1610,7 +1646,7 @@ setup(void) if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) die("no fonts could be loaded."); lrpad = drw->fonts->h; - bh = drw->fonts->h + 2; + bh = usealtbar ? 0 : drw->fonts->h + 2; updategeom(); /* init atoms */ utf8string = XInternAtom(dpy, "UTF8_STRING", False); @@ -1664,6 +1700,7 @@ setup(void) XSelectInput(dpy, root, wa.event_mask); grabkeys(); focus(NULL); + spawnbar(); } void @@ -1719,6 +1756,13 @@ spawn(const Arg *arg) } } +void +spawnbar() +{ + if (*altbarcmd) + system(altbarcmd); +} + void setclienttagprop(Client *c) { @@ -1781,7 +1825,7 @@ togglebar(const Arg *arg) { selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; updatebarpos(selmon); - XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, selmon->bh); arrange(selmon); } @@ -1890,10 +1934,26 @@ unmanage(Client *c, int destroyed) arrange(m); } +void +unmanagealtbar(Window w) +{ + Monitor *m = wintomon(w); + + if (!m) + return; + + m->barwin = 0; + m->by = 0; + m->bh = 0; + updatebarpos(m); + arrange(m); +} + void unmapnotify(XEvent *e) { Client *c; + Monitor *m; XUnmapEvent *ev = &e->xunmap; if ((c = wintoclient(ev->window))) { @@ -1901,12 +1961,16 @@ unmapnotify(XEvent *e) setclientstate(c, WithdrawnState); else unmanage(c, 0); - } + } else if ((m = wintomon(ev->window)) && m->barwin == ev->window) + unmanagealtbar(ev->window); } void updatebars(void) { + if (usealtbar) + return; + Monitor *m; XSetWindowAttributes wa = { .override_redirect = True, @@ -1932,11 +1996,11 @@ updatebarpos(Monitor *m) m->wy = m->my; m->wh = m->mh; if (m->showbar) { - m->wh -= bh; + m->wh -= m->bh; m->by = m->topbar ? m->wy : m->wy + m->wh; - m->wy = m->topbar ? m->wy + bh : m->wy; + m->wy = m->topbar ? m->wy + m->bh : m->wy; } else - m->by = -bh; + m->by = -m->bh; } void @@ -2207,6 +2271,28 @@ wintomon(Window w) return selmon; } +int +wmclasscontains(Window win, const char *class, const char *name) +{ + XClassHint ch = { NULL, NULL }; + int res = 1; + + if (XGetClassHint(dpy, win, &ch)) { + if (ch.res_name && strstr(ch.res_name, name) == NULL) + res = 0; + if (ch.res_class && strstr(ch.res_class, class) == NULL) + res = 0; + } else + res = 0; + + if (ch.res_class) + XFree(ch.res_class); + if (ch.res_name) + XFree(ch.res_name); + + return res; +} + /* There's no way to check accesses to destroyed windows, thus those cases are * ignored (especially on UnmapNotify's). Other types of errors call Xlibs * default error handler, which may call exit. */ diff --git a/patches/anybar.diff b/patches/anybar.diff new file mode 100644 index 0000000..00fe940 --- /dev/null +++ b/patches/anybar.diff @@ -0,0 +1,335 @@ +From 782f63d8f858b1c14df38aaf623438d7ea2f75e1 Mon Sep 17 00:00:00 2001 +From: mihirlad55 +Date: Mon, 10 Aug 2020 01:39:35 +0000 +Subject: [PATCH] Add support for managing external status bars + +This patch allows dwm to manage other status bars such as +polybar/lemonbar without them needing to set override-redirect. For +all intents and purposes, DWM treats this bar as if it were its own +and as a result helps the status bar and DWM live in harmony. + +This has a few advantages +* The bar does not block fullscreen windows +* DWM makes room for the status bar, so windows do not overlap the bar +* The bar can be hidden/killed and DWM will not keep an unsightly gap + where the bar was +* DWM receives EnterNotify events when your cursor enters the bar + +To use another status bar, set usealtbar to 1 in your config.h and set +altbarclass to the class name (can be found using xprop) to the class +name of your status bar. Also make sure that if your status bar will +be displayed on top, topbar is set to 1 in your config, and if it will +be displayed on bottom, topbar is set to 0. This patch does not +support bars that are not docked at the top or at the bottom of your +monitor. + +The patch is developed at https://github.com/mihirlad55/dwm-anybar +--- + config.def.h | 3 ++ + dwm.c | 114 ++++++++++++++++++++++++++++++++++++++++++++------- + 2 files changed, 103 insertions(+), 14 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..d0d60aa 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -5,6 +5,9 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ ++static const int usealtbar = 1; /* 1 means use non-dwm status bar */ ++static const char *altbarclass = "Polybar"; /* Alternate bar class name */ ++static const char *altbarcmd = "$HOME/bar.sh"; /* Alternate bar launch command */ + static const char *fonts[] = { "monospace:size=10" }; + static const char dmenufont[] = "monospace:size=10"; + static const char col_gray1[] = "#222222"; +diff --git a/dwm.c b/dwm.c +index 9fd0286..f149ab4 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -47,8 +47,8 @@ + /* macros */ + #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) + #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) +-#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ +- * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) ++#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->mx+(m)->mw) - MAX((x),(m)->mx)) \ ++ * MAX(0, MIN((y)+(h),(m)->my+(m)->mh) - MAX((y),(m)->my))) + #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) + #define LENGTH(X) (sizeof X / sizeof X[0]) + #define MOUSEMASK (BUTTONMASK|PointerMotionMask) +@@ -116,7 +116,7 @@ struct Monitor { + float mfact; + int nmaster; + int num; +- int by; /* bar geometry */ ++ int by, bh; /* bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + unsigned int seltags; +@@ -179,6 +179,7 @@ static void incnmaster(const Arg *arg); + static void keypress(XEvent *e); + static void killclient(const Arg *arg); + static void manage(Window w, XWindowAttributes *wa); ++static void managealtbar(Window win, XWindowAttributes *wa); + static void mappingnotify(XEvent *e); + static void maprequest(XEvent *e); + static void monocle(Monitor *m); +@@ -207,6 +208,7 @@ static void seturgent(Client *c, int urg); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static void spawnbar(); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); +@@ -216,6 +218,7 @@ static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unfocus(Client *c, int setfocus); + static void unmanage(Client *c, int destroyed); ++static void unmanagealtbar(Window w); + static void unmapnotify(XEvent *e); + static void updatebarpos(Monitor *m); + static void updatebars(void); +@@ -230,6 +233,7 @@ static void updatewmhints(Client *c); + static void view(const Arg *arg); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); ++static int wmclasscontains(Window win, const char *class, const char *name); + static int xerror(Display *dpy, XErrorEvent *ee); + static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); +@@ -505,8 +509,10 @@ cleanupmon(Monitor *mon) + for (m = mons; m && m->next != mon; m = m->next); + m->next = mon->next; + } +- XUnmapWindow(dpy, mon->barwin); +- XDestroyWindow(dpy, mon->barwin); ++ if (!usealtbar) { ++ XUnmapWindow(dpy, mon->barwin); ++ XDestroyWindow(dpy, mon->barwin); ++ } + free(mon); + } + +@@ -568,7 +574,7 @@ configurenotify(XEvent *e) + for (c = m->clients; c; c = c->next) + if (c->isfullscreen) + resizeclient(c, m->mx, m->my, m->mw, m->mh); +- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, m->bh); + } + focus(NULL); + arrange(NULL); +@@ -639,6 +645,7 @@ createmon(void) + m->nmaster = nmaster; + m->showbar = showbar; + m->topbar = topbar; ++ m->bh = bh; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); +@@ -649,10 +656,13 @@ void + destroynotify(XEvent *e) + { + Client *c; ++ Monitor *m; + XDestroyWindowEvent *ev = &e->xdestroywindow; + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); ++ else if ((m = wintomon(ev->window)) && m->barwin == ev->window) ++ unmanagealtbar(ev->window); + } + + void +@@ -696,6 +706,9 @@ dirtomon(int dir) + void + drawbar(Monitor *m) + { ++ if (usealtbar) ++ return; ++ + int x, w, tw = 0; + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; +@@ -1077,6 +1090,25 @@ manage(Window w, XWindowAttributes *wa) + focus(NULL); + } + ++void ++managealtbar(Window win, XWindowAttributes *wa) ++{ ++ Monitor *m; ++ if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height))) ++ return; ++ ++ m->barwin = win; ++ m->by = wa->y; ++ bh = m->bh = wa->height; ++ updatebarpos(m); ++ arrange(m); ++ XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); ++ XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height); ++ XMapWindow(dpy, win); ++ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, ++ (unsigned char *) &win, 1); ++} ++ + void + mappingnotify(XEvent *e) + { +@@ -1097,7 +1129,9 @@ maprequest(XEvent *e) + return; + if (wa.override_redirect) + return; +- if (!wintoclient(ev->window)) ++ if (wmclasscontains(ev->window, altbarclass, "")) ++ managealtbar(ev->window, &wa); ++ else if (!wintoclient(ev->window)) + manage(ev->window, &wa); + } + +@@ -1393,7 +1427,9 @@ scan(void) + if (!XGetWindowAttributes(dpy, wins[i], &wa) + || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) + continue; +- if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) ++ if (wmclasscontains(wins[i], altbarclass, "")) ++ managealtbar(wins[i], &wa); ++ else if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) + manage(wins[i], &wa); + } + for (i = 0; i < num; i++) { /* now the transients */ +@@ -1546,7 +1582,7 @@ setup(void) + if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) + die("no fonts could be loaded."); + lrpad = drw->fonts->h; +- bh = drw->fonts->h + 2; ++ bh = usealtbar ? 0 : drw->fonts->h + 2; + updategeom(); + /* init atoms */ + utf8string = XInternAtom(dpy, "UTF8_STRING", False); +@@ -1595,6 +1631,7 @@ setup(void) + XSelectInput(dpy, root, wa.event_mask); + grabkeys(); + focus(NULL); ++ spawnbar(); + } + + +@@ -1653,6 +1690,13 @@ spawn(const Arg *arg) + } + } + ++void ++spawnbar() ++{ ++ if (*altbarcmd) ++ system(altbarcmd); ++} ++ + void + tag(const Arg *arg) + { +@@ -1704,7 +1748,7 @@ togglebar(const Arg *arg) + { + selmon->showbar = !selmon->showbar; + updatebarpos(selmon); +- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); ++ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, selmon->bh); + arrange(selmon); + } + +@@ -1787,10 +1831,26 @@ unmanage(Client *c, int destroyed) + arrange(m); + } + ++void ++unmanagealtbar(Window w) ++{ ++ Monitor *m = wintomon(w); ++ ++ if (!m) ++ return; ++ ++ m->barwin = 0; ++ m->by = 0; ++ m->bh = 0; ++ updatebarpos(m); ++ arrange(m); ++} ++ + void + unmapnotify(XEvent *e) + { + Client *c; ++ Monitor *m; + XUnmapEvent *ev = &e->xunmap; + + if ((c = wintoclient(ev->window))) { +@@ -1798,12 +1858,16 @@ unmapnotify(XEvent *e) + setclientstate(c, WithdrawnState); + else + unmanage(c, 0); +- } ++ } else if ((m = wintomon(ev->window)) && m->barwin == ev->window) ++ unmanagealtbar(ev->window); + } + + void + updatebars(void) + { ++ if (usealtbar) ++ return; ++ + Monitor *m; + XSetWindowAttributes wa = { + .override_redirect = True, +@@ -1829,11 +1893,11 @@ updatebarpos(Monitor *m) + m->wy = m->my; + m->wh = m->mh; + if (m->showbar) { +- m->wh -= bh; ++ m->wh -= m->bh; + m->by = m->topbar ? m->wy : m->wy + m->wh; +- m->wy = m->topbar ? m->wy + bh : m->wy; ++ m->wy = m->topbar ? m->wy + m->bh : m->wy; + } else +- m->by = -bh; ++ m->by = -m->bh; + } + + void +@@ -2077,6 +2141,28 @@ wintomon(Window w) + return selmon; + } + ++int ++wmclasscontains(Window win, const char *class, const char *name) ++{ ++ XClassHint ch = { NULL, NULL }; ++ int res = 1; ++ ++ if (XGetClassHint(dpy, win, &ch)) { ++ if (ch.res_name && strstr(ch.res_name, name) == NULL) ++ res = 0; ++ if (ch.res_class && strstr(ch.res_class, class) == NULL) ++ res = 0; ++ } else ++ res = 0; ++ ++ if (ch.res_class) ++ XFree(ch.res_class); ++ if (ch.res_name) ++ XFree(ch.res_name); ++ ++ return res; ++} ++ + /* There's no way to check accesses to destroyed windows, thus those cases are + * ignored (especially on UnmapNotify's). Other types of errors call Xlibs + * default error handler, which may call exit. */ +-- +2.28.0 +