imanage: propertynotify: Reduce cost of unused size hints - dwm - dynamic window manager Err parazyd.org 70 hgit clone https://git.parazyd.org/dwm URL:https://git.parazyd.org/dwm parazyd.org 70 1Log /git/dwm/log.gph parazyd.org 70 1Files /git/dwm/files.gph parazyd.org 70 1Refs /git/dwm/refs.gph parazyd.org 70 1README /git/dwm/file/README.gph parazyd.org 70 1LICENSE /git/dwm/file/LICENSE.gph parazyd.org 70 i--- Err parazyd.org 70 1commit 8806b6e2379372900e3d9e0bf6604bc7f727350b /git/dwm/commit/8806b6e2379372900e3d9e0bf6604bc7f727350b.gph parazyd.org 70 1parent bece862a0fc4fc18ef9065b18cd28e2032d0d975 /git/dwm/commit/bece862a0fc4fc18ef9065b18cd28e2032d0d975.gph parazyd.org 70 hAuthor: Chris Down URL:mailto:chris@chrisdown.name parazyd.org 70 iDate: Thu, 17 Mar 2022 15:56:13 +0000 Err parazyd.org 70 i Err parazyd.org 70 imanage: propertynotify: Reduce cost of unused size hints Err parazyd.org 70 i Err parazyd.org 70 iThis patch defers all size hint calculations until they are actually Err parazyd.org 70 ineeded, drastically reducing the number of calls to updatesizehints(), Err parazyd.org 70 iwhich can be expensive when called repeatedly (as it currently is during Err parazyd.org 70 iresizes). Err parazyd.org 70 i Err parazyd.org 70 iIn my unscientific testing this reduces calls to updatesizehints() by Err parazyd.org 70 iover 90% during a typical work session. There are no functional changes Err parazyd.org 70 ifor users other than an increase in responsiveness after resizes and Err parazyd.org 70 ia reduction in CPU time. Err parazyd.org 70 i Err parazyd.org 70 iIn slower environments or X servers, this patch also offers an Err parazyd.org 70 iimprovement in responsiveness that is often tangible after resizing a Err parazyd.org 70 iclient that changes hints during resizes. Err parazyd.org 70 i Err parazyd.org 70 iThere are two main motivations to defer this work to the time of hint Err parazyd.org 70 iapplication: Err parazyd.org 70 i Err parazyd.org 70 i1. Some clients, especially terminals using incremental size hints, Err parazyd.org 70 i resend XA_WM_NORMAL_HINTS events on resize to avoid fighting with the Err parazyd.org 70 i WM or mouse resizing. For example, some terminals like urxvt clear Err parazyd.org 70 i PBaseSize and PResizeInc during XResizeWindow and restore them Err parazyd.org 70 i afterwards. Err parazyd.org 70 i Err parazyd.org 70 i For this reason, after the resize is concluded, we typically receive Err parazyd.org 70 i a backlogged XA_WM_NORMAL_HINTS message for each update period with Err parazyd.org 70 i movement, which is useless. In some cases one may get hundreds or Err parazyd.org 70 i thousands of XA_WM_NORMAL_HINTS messages on large resizes, and Err parazyd.org 70 i currently all of these result in a separate updatesizehints() call, Err parazyd.org 70 i of which all but the final one are immediately outdated. Err parazyd.org 70 i Err parazyd.org 70 i (We can't just blindly discard these messages during resizes like we Err parazyd.org 70 i do for EnterNotify, because some of them might actually be for other Err parazyd.org 70 i windows, and may not be XA_WM_NORMAL_HINTS events.) Err parazyd.org 70 i Err parazyd.org 70 i2. For users which use resizehints=0 most of these updates are unused Err parazyd.org 70 i anyway -- in the normal case where the client is not floating these Err parazyd.org 70 i values won't be used, so there's no need to calculate them up front. Err parazyd.org 70 i Err parazyd.org 70 iA synthetic test using the mouse to resize a floating terminal window Err parazyd.org 70 ifrom roughly 256x256 to 1024x1024 and back again shows that the number Err parazyd.org 70 iof calls to updatesizehints() goes from over 500 before this patch (one Err parazyd.org 70 ifor each update interval with movement) to 2 after this patch (one for Err parazyd.org 70 ieach hint application), with no change in user visible behaviour. Err parazyd.org 70 i Err parazyd.org 70 iThis also reduces the delay before dwm is ready to process new events Err parazyd.org 70 iagain after a large resize on such a client, as it avoids the thundering Err parazyd.org 70 iherd of updatesizehints() calls when hundreds of backlogged Err parazyd.org 70 iXA_WM_NORMAL_HINTS messages appear at once after a resize is finished. Err parazyd.org 70 i Err parazyd.org 70 iDiffstat: Err parazyd.org 70 i M dwm.c | 8 +++++--- Err parazyd.org 70 i Err parazyd.org 70 i1 file changed, 5 insertions(+), 3 deletions(-) Err parazyd.org 70 i--- Err parazyd.org 70 1diff --git a/dwm.c b/dwm.c /git/dwm/file/dwm.c.gph parazyd.org 70 i@@ -89,7 +89,7 @@ struct Client { Err parazyd.org 70 i float mina, maxa; Err parazyd.org 70 i int x, y, w, h; Err parazyd.org 70 i int oldx, oldy, oldw, oldh; Err parazyd.org 70 i- int basew, baseh, incw, inch, maxw, maxh, minw, minh; Err parazyd.org 70 i+ int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid; Err parazyd.org 70 i int bw, oldbw; Err parazyd.org 70 i unsigned int tags; Err parazyd.org 70 i int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; Err parazyd.org 70 i@@ -345,6 +345,8 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) Err parazyd.org 70 i if (*w < bh) Err parazyd.org 70 i *w = bh; Err parazyd.org 70 i if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { Err parazyd.org 70 i+ if (!c->hintsvalid) Err parazyd.org 70 i+ updatesizehints(c); Err parazyd.org 70 i /* see last two sentences in ICCCM 4.1.2.3 */ Err parazyd.org 70 i baseismin = c->basew == c->minw && c->baseh == c->minh; Err parazyd.org 70 i if (!baseismin) { /* temporarily remove base dimensions */ Err parazyd.org 70 i@@ -1059,7 +1061,6 @@ manage(Window w, XWindowAttributes *wa) Err parazyd.org 70 i XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel); Err parazyd.org 70 i configure(c); /* propagates border_width, if size doesn't change */ Err parazyd.org 70 i updatewindowtype(c); Err parazyd.org 70 i- updatesizehints(c); Err parazyd.org 70 i updatewmhints(c); Err parazyd.org 70 i XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); Err parazyd.org 70 i grabbuttons(c, 0); Err parazyd.org 70 i@@ -1233,7 +1234,7 @@ propertynotify(XEvent *e) Err parazyd.org 70 i arrange(c->mon); Err parazyd.org 70 i break; Err parazyd.org 70 i case XA_WM_NORMAL_HINTS: Err parazyd.org 70 i- updatesizehints(c); Err parazyd.org 70 i+ c->hintsvalid = 0; Err parazyd.org 70 i break; Err parazyd.org 70 i case XA_WM_HINTS: Err parazyd.org 70 i updatewmhints(c); Err parazyd.org 70 i@@ -1989,6 +1990,7 @@ updatesizehints(Client *c) Err parazyd.org 70 i } else Err parazyd.org 70 i c->maxa = c->mina = 0.0; Err parazyd.org 70 i c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); Err parazyd.org 70 i+ c->hintsvalid = 1; Err parazyd.org 70 i } Err parazyd.org 70 i Err parazyd.org 70 i void Err parazyd.org 70 .