336 lines
10 KiB
Diff
336 lines
10 KiB
Diff
|
From 782f63d8f858b1c14df38aaf623438d7ea2f75e1 Mon Sep 17 00:00:00 2001
|
||
|
From: mihirlad55 <mihirlad55@gmail.com>
|
||
|
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
|
||
|
|