commit 7269c5355d257dd2ad2c53f15dc9c1cf6796aea5
parent 6be057f060543bb0f3ed9423904263617cdffffe
Author: NRK <nrk@disroot.org>
Date:   Thu, 24 Mar 2022 02:04:04 +0600
significantly improve performance on large strings
this replaces inefficient pattern of `MIN(TEXTW(..), n)` with
drw_fontset_getwidth_clamp() instead, which is far more efficient when
we only want up to a certain width.
dumping a decently sized (unicode) emoji file into dmenu, I see the
startup time drop significantly with this patch.
before -> after
360ms  -> 160ms
this should also noticeably improve input latency (responsiveness) given
that calcoffsets() and drawmenu() are pretty hot functions.
Diffstat:
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/dmenu.c b/dmenu.c
@@ -58,6 +58,13 @@ static Clr *scheme[SchemeLast];
 static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
 static char *(*fstrstr)(const char *, const char *) = strstr;
 
+static unsigned int
+textw_clamp(const char *str, unsigned int n)
+{
+	unsigned int w = drw_fontset_getwidth_clamp(drw, str, n) + lrpad;
+	return MIN(w, n);
+}
+
 static void
 appenditem(struct item *item, struct item **list, struct item **last)
 {
@@ -82,10 +89,10 @@ calcoffsets(void)
 		n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
 	/* calculate which items will begin the next page and previous page */
 	for (i = 0, next = curr; next; next = next->right)
-		if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n)
+		if ((i += (lines > 0) ? bh : textw_clamp(next->text, n)) > n)
 			break;
 	for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
-		if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n)
+		if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n)
 			break;
 }
 
@@ -172,7 +179,7 @@ drawmenu(void)
 		}
 		x += w;
 		for (item = curr; item != next; item = item->right)
-			x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">")));
+			x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW(">")));
 		if (next) {
 			w = TEXTW(">");
 			drw_setscheme(drw, scheme[SchemeNorm]);