Re: [hackers] [tabbed] Urgency Hint

From: Mikau <mikau_AT_aaathats3as.com>
Date: Tue, 30 Mar 2021 01:05:22 +0200

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 <mikau_AT_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
_AT_@ -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);
_AT_@ -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
_AT_@ -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) {
_AT_@ -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);
 }
_AT_@ -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);
_AT_@ -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
Received on Tue Mar 30 2021 - 01:05:22 CEST

This archive was generated by hypermail 2.3.0 : Tue Mar 30 2021 - 03:12:33 CEST