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



Reply via email to