The recent messages about contributions with no reply reminded my of my own. I'd really like to know the maintainers' opinion on it. For convenience, I've squashed the commits (including a newer one that fixed a memory leak in my code) and made the message a bit more concise:
----------------------------------------------------------------------- From a8fdfca011934b8c252730b0b5ec2b180b646ff9 Mon Sep 17 00:00:00 2001 From: Mikau <mi...@aaathats3as.com> Date: Tue, 30 Mar 2021 00:46:03 +0200 Subject: [PATCH] ICCCM-compliant handling of urgency hint When a client sets the urgency hint, mark its tab as urgent. When a client, whose tab is marked as urgent, unsets its urgency hint (or deletes its WM_HINTS property), unmark its tab. The tabbed window itself is urgent whenever a tab is urgent. This fixes the following issues: - Tabbed modifying clients' WM_HINTS property (should only be modified by the client itself) - Tabbed never unsetting its own urgency hint (therefore staying urgent forever if ever becoming urgent in the first place) --- tabbed.c | 111 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 75 insertions(+), 36 deletions(-) diff --git a/tabbed.c b/tabbed.c index eafe28a..fe6bc61 100644 --- a/tabbed.c +++ b/tabbed.c @@ -131,6 +131,7 @@ static int textnw(const char *text, unsigned int len); static void toggle(const Arg *arg); static void unmanage(int c); static void unmapnotify(const XEvent *e); +static void unurgent(int c); static void updatenumlockmask(void); static void updatetitle(int c); static int xerror(Display *dpy, XErrorEvent *ee); @@ -305,8 +306,10 @@ destroynotify(const XEvent *e) const XDestroyWindowEvent *ev = &e->xdestroywindow; int c; - if ((c = getclient(ev->window)) > -1) + if ((c = getclient(ev->window)) > -1) { + unurgent(c); unmanage(c); + } } void @@ -446,7 +449,6 @@ focus(int c) { char buf[BUFSIZ] = "tabbed-"VERSION" ::"; size_t i, n; - XWMHints* wmh; /* If c, sel and clients are -1, raise tabbed-win itself */ if (nclients == 0) { @@ -475,13 +477,6 @@ focus(int c) sel = c; } - if (clients[c]->urgent && (wmh = XGetWMHints(dpy, clients[c]->win))) { - wmh->flags &= ~XUrgencyHint; - XSetWMHints(dpy, clients[c]->win, wmh); - clients[c]->urgent = False; - XFree(wmh); - } - drawbar(); XSync(dpy, False); } @@ -839,35 +834,48 @@ propertynotify(const XEvent *e) arg.v = cmd; spawn(&arg); } - } else if (ev->state == PropertyNewValue && ev->atom == XA_WM_HINTS && - (c = getclient(ev->window)) > -1 && - (wmh = XGetWMHints(dpy, clients[c]->win))) { - if (wmh->flags & XUrgencyHint) { - XFree(wmh); - wmh = XGetWMHints(dpy, win); - if (c != sel) { - if (urgentswitch && wmh && - !(wmh->flags & XUrgencyHint)) { - /* only switch, if tabbed was focused - * since last urgency hint if WMHints - * could not be received, - * default to no switch */ - focus(c); - } else { - /* if no switch should be performed, - * mark tab as urgent */ - clients[c]->urgent = True; - drawbar(); + } else if (ev->atom == XA_WM_HINTS && (c = getclient(ev->window)) > -1) { + if (ev->state == PropertyNewValue && + (wmh = XGetWMHints(dpy, clients[c]->win))) { + if (wmh->flags & XUrgencyHint) { + XFree(wmh); + /* mark tab as urgent regardles of whether it is selected + * or not. sel has priorityover urg in drawbar() anyway, + * and we could end up switching to a different tab while + * this one remains urgent */ + clients[c]->urgent = True; + wmh = XGetWMHints(dpy, win); + if (c != sel) { + if (urgentswitch && wmh && + !(wmh->flags & XUrgencyHint)) { + /* only switch, if tabbed was focused + * since last urgency hint if WMHints + * could not be received, + * default to no switch */ + focus(c); + } else { + /* if no switch should be performed, + * call drawbar, since the appearance + * of the urgent tab changed */ + drawbar(); + } } + if (wmh && !(wmh->flags & XUrgencyHint)) { + /* update tabbed urgency hint + * if not set already */ + wmh->flags |= XUrgencyHint; + XSetWMHints(dpy, win, wmh); + } + } else { + /* client has unset its urgency hint */ + unurgent(c); } - if (wmh && !(wmh->flags & XUrgencyHint)) { - /* update tabbed urgency hint - * if not set already */ - wmh->flags |= XUrgencyHint; - XSetWMHints(dpy, win, wmh); - } + XFree(wmh); + } else { + /* client has deleted the WM_HINTS property. + * treat it as a loss of urgency */ + unurgent(c); } - XFree(wmh); } else if (ev->state != PropertyDelete && ev->atom == XA_WM_NAME && (c = getclient(ev->window)) > -1) { updatetitle(c); @@ -1188,8 +1196,39 @@ unmapnotify(const XEvent *e) const XUnmapEvent *ev = &e->xunmap; int c; - if ((c = getclient(ev->window)) > -1) + if ((c = getclient(ev->window)) > -1) { + unurgent(c); unmanage(c); + } +} + +void +unurgent(int c) +{ + XWMHints *wmh; + Bool urgent = False; + + if (clients[c]->urgent) { + clients[c]->urgent = False; + /* this client has lost its urgency but another + * might still be urgent*/ + for (c = 0; c < nclients; c++) { + if (clients[c]->urgent) { + urgent = True; + break; + } + } + if (!urgent && (wmh = XGetWMHints(dpy, win))) { + if (wmh->flags & XUrgencyHint) { + /* if no other tabs are urgent, we can + * remove the urgency hint on the tabbed + * window, should one exist */ + wmh->flags &= ~XUrgencyHint; + XSetWMHints(dpy, win, wmh); + } + XFree(wmh); + } + } } void -- 2.31.0