significantly improve performance on large strings 7269c535
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.
NRK · 2022-03-24 02:04 1 file(s) · +10 −3
dmenu.c +10 −3
58 58
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
59 59
static char *(*fstrstr)(const char *, const char *) = strstr;
60 60
61 +
static unsigned int
62 +
textw_clamp(const char *str, unsigned int n)
63 +
{
64 +
	unsigned int w = drw_fontset_getwidth_clamp(drw, str, n) + lrpad;
65 +
	return MIN(w, n);
66 +
}
67 +
61 68
static void
62 69
appenditem(struct item *item, struct item **list, struct item **last)
63 70
{
82 89
		n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
83 90
	/* calculate which items will begin the next page and previous page */
84 91
	for (i = 0, next = curr; next; next = next->right)
85 -
		if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n)
92 +
		if ((i += (lines > 0) ? bh : textw_clamp(next->text, n)) > n)
86 93
			break;
87 94
	for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
88 -
		if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n)
95 +
		if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n)
89 96
			break;
90 97
}
91 98
172 179
		}
173 180
		x += w;
174 181
		for (item = curr; item != next; item = item->right)
175 -
			x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">")));
182 +
			x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW(">")));
176 183
		if (next) {
177 184
			w = TEXTW(">");
178 185
			drw_setscheme(drw, scheme[SchemeNorm]);