commit c5bf9d703fb01bc8105edfa28a1c420a14d17e3c
Author: MrJensK <jens.se@icloud.com>
AuthorDate: Mon Aug 10 18:01:52 2026 +0200
Commit: MrJensK <jens.se@icloud.com>
CommitDate: Mon Aug 10 18:01:52 2026 +0200
crash fix
---
src/sxbar.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/src/sxbar.c b/src/sxbar.c
index e3af39f..9995ad8 100644
--- a/src/sxbar.c
+++ b/src/sxbar.c
@@ -65,6 +65,22 @@ int nmonitors = 0;
int scr;
static Popup popup;
+/* Windows pulled from _NET_CLIENT_LIST (taskbar, workspace dots, ...) are
+ * routinely destroyed between that snapshot and a follow-up property/attr
+ * query on them -- a normal race, not a bug. Xlib's default error handler
+ * would exit() the whole bar over it; swallow just that race instead and
+ * let callers' existing "did this call fail" checks handle it. */
+static int xerror(Display *d, XErrorEvent *ee)
+{
+ (void)d;
+ if (ee->error_code == BadWindow || ee->error_code == BadDrawable ||
+ ee->error_code == BadMatch)
+ return 0;
+ warnx("X error: request %d.%d, error code %d",
+ ee->request_code, ee->minor_code, ee->error_code);
+ return 0;
+}
+
int window_on_monitor(Window win, int monitor_index) {
XWindowAttributes attr;
if (!XGetWindowAttributes(dpy, win, &attr))
@@ -552,6 +568,18 @@ void create_bars(void)
}
}
+ /* sxwm only re-tiles/recalculates reserved screen space in reaction
+ * to a _NET_WM_STRUT_PARTIAL PropertyNotify on the root window; it
+ * doesn't do that on its own when a dock window first maps. Without
+ * this, windows only reflow around a (re)started bar the next time
+ * something unrelated happens to trigger a retile. Touch that same
+ * atom on root ourselves so it happens immediately -- the value is
+ * irrelevant, sxwm rescans all dock windows itself when it sees this. */
+ Atom A_ROOT_RETILE_KICK = XInternAtom(dpy, "_NET_WM_STRUT_PARTIAL", False);
+ long retile_kick = 0;
+ XChangeProperty(dpy, root, A_ROOT_RETILE_KICK, XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)&retile_kick, 1);
+
gc = XCreateGC(dpy, bars[0].win, 0, NULL);
font = XftFontOpenName(dpy, scr, config.font);
if (!font)
@@ -1904,6 +1932,7 @@ void setup(void)
if (!(dpy = XOpenDisplay(NULL))) {
errx(1, "can't open display");
}
+ XSetErrorHandler(xerror);
root = XDefaultRootWindow(dpy);
scr = DefaultScreen(dpy);
@@ -1935,6 +1964,15 @@ int main(int ac, char **av)
}
errx(1, "usage: sxbar [-v|--version]");
}
+
+ /* sxwm spawns us without setsid(), so we start out in its process
+ * group -- along with every other program it launches. Some apps
+ * (Electron ones observed in practice) signal their own process
+ * group on shutdown to clean up child processes, which then takes
+ * sxbar down as collateral. Detach into our own session so we're
+ * immune regardless of what else shares that group. */
+ setsid();
+
setup();
run();