summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Down <chris@chrisdown.name>2022-03-17 15:56:13 +0000
committerHiltjo Posthuma <hiltjo@codemadness.org>2022-04-16 16:37:46 +0200
commit8806b6e2379372900e3d9e0bf6604bc7f727350b (patch)
treeae2d6c1af222db410906861f9a02da7138d1512e
parentbece862a0fc4fc18ef9065b18cd28e2032d0d975 (diff)
downloaddwm-8806b6e2379372900e3d9e0bf6604bc7f727350b.tar.gz
dwm-8806b6e2379372900e3d9e0bf6604bc7f727350b.zip
manage: propertynotify: Reduce cost of unused size hints
This patch defers all size hint calculations until they are actually needed, drastically reducing the number of calls to updatesizehints(), which can be expensive when called repeatedly (as it currently is during resizes). In my unscientific testing this reduces calls to updatesizehints() by over 90% during a typical work session. There are no functional changes for users other than an increase in responsiveness after resizes and a reduction in CPU time. In slower environments or X servers, this patch also offers an improvement in responsiveness that is often tangible after resizing a client that changes hints during resizes. There are two main motivations to defer this work to the time of hint application: 1. Some clients, especially terminals using incremental size hints, resend XA_WM_NORMAL_HINTS events on resize to avoid fighting with the WM or mouse resizing. For example, some terminals like urxvt clear PBaseSize and PResizeInc during XResizeWindow and restore them afterwards. For this reason, after the resize is concluded, we typically receive a backlogged XA_WM_NORMAL_HINTS message for each update period with movement, which is useless. In some cases one may get hundreds or thousands of XA_WM_NORMAL_HINTS messages on large resizes, and currently all of these result in a separate updatesizehints() call, of which all but the final one are immediately outdated. (We can't just blindly discard these messages during resizes like we do for EnterNotify, because some of them might actually be for other windows, and may not be XA_WM_NORMAL_HINTS events.) 2. For users which use resizehints=0 most of these updates are unused anyway -- in the normal case where the client is not floating these values won't be used, so there's no need to calculate them up front. A synthetic test using the mouse to resize a floating terminal window from roughly 256x256 to 1024x1024 and back again shows that the number of calls to updatesizehints() goes from over 500 before this patch (one for each update interval with movement) to 2 after this patch (one for each hint application), with no change in user visible behaviour. This also reduces the delay before dwm is ready to process new events again after a large resize on such a client, as it avoids the thundering herd of updatesizehints() calls when hundreds of backlogged XA_WM_NORMAL_HINTS messages appear at once after a resize is finished.
-rw-r--r--dwm.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/dwm.c b/dwm.c
index 5f16260..d8075ad 100644
--- a/dwm.c
+++ b/dwm.c
@@ -89,7 +89,7 @@ struct Client {
89 float mina, maxa; 89 float mina, maxa;
90 int x, y, w, h; 90 int x, y, w, h;
91 int oldx, oldy, oldw, oldh; 91 int oldx, oldy, oldw, oldh;
92 int basew, baseh, incw, inch, maxw, maxh, minw, minh; 92 int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
93 int bw, oldbw; 93 int bw, oldbw;
94 unsigned int tags; 94 unsigned int tags;
95 int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; 95 int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
@@ -345,6 +345,8 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact)
345 if (*w < bh) 345 if (*w < bh)
346 *w = bh; 346 *w = bh;
347 if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { 347 if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
348 if (!c->hintsvalid)
349 updatesizehints(c);
348 /* see last two sentences in ICCCM 4.1.2.3 */ 350 /* see last two sentences in ICCCM 4.1.2.3 */
349 baseismin = c->basew == c->minw && c->baseh == c->minh; 351 baseismin = c->basew == c->minw && c->baseh == c->minh;
350 if (!baseismin) { /* temporarily remove base dimensions */ 352 if (!baseismin) { /* temporarily remove base dimensions */
@@ -1059,7 +1061,6 @@ manage(Window w, XWindowAttributes *wa)
1059 XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel); 1061 XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
1060 configure(c); /* propagates border_width, if size doesn't change */ 1062 configure(c); /* propagates border_width, if size doesn't change */
1061 updatewindowtype(c); 1063 updatewindowtype(c);
1062 updatesizehints(c);
1063 updatewmhints(c); 1064 updatewmhints(c);
1064 XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); 1065 XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
1065 grabbuttons(c, 0); 1066 grabbuttons(c, 0);
@@ -1233,7 +1234,7 @@ propertynotify(XEvent *e)
1233 arrange(c->mon); 1234 arrange(c->mon);
1234 break; 1235 break;
1235 case XA_WM_NORMAL_HINTS: 1236 case XA_WM_NORMAL_HINTS:
1236 updatesizehints(c); 1237 c->hintsvalid = 0;
1237 break; 1238 break;
1238 case XA_WM_HINTS: 1239 case XA_WM_HINTS:
1239 updatewmhints(c); 1240 updatewmhints(c);
@@ -1989,6 +1990,7 @@ updatesizehints(Client *c)
1989 } else 1990 } else
1990 c->maxa = c->mina = 0.0; 1991 c->maxa = c->mina = 0.0;
1991 c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); 1992 c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh);
1993 c->hintsvalid = 1;
1992} 1994}
1993 1995
1994void 1996void