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.

ref. https://git.suckless.org/dmenu/commit/7269c5355d257dd2ad2c53f15dc9c1cf6796aea5.html
This commit is contained in:
bakkeby 2022-03-28 11:02:11 +02:00
parent 78a3c399ee
commit 067aa41ac3

35
dmenu.c
View File

@ -189,6 +189,13 @@ static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
static char *(*fstrstr)(const char *, const char *) = strstr;
#endif // CASEINSENSITIVE_PATCH
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);
static void calcoffsets(void);
static void cleanup(void);
@ -248,18 +255,10 @@ calcoffsets(void)
#endif // SYMBOLS_PATCH
/* calculate which items will begin the next page and previous page */
for (i = 0, next = curr; next; next = next->right)
#if PANGO_PATCH
if ((i += (lines > 0) ? bh : MIN(TEXTWM(next->text), n)) > n)
#else
if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n)
#endif // PANGO_PATCH
if ((i += (lines > 0) ? bh : textw_clamp(next->text, n)) > n)
break;
for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
#if PANGO_PATCH
if ((i += (lines > 0) ? bh : MIN(TEXTWM(prev->left->text), n)) > n)
#else
if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n)
#endif // PANGO_PATCH
if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n)
break;
}
@ -641,21 +640,17 @@ drawmenu(void)
}
x += w;
for (item = curr; item != next; item = item->right) {
#if PANGO_PATCH && TSV_PATCH
itw = TEXTWM(item->stext);
#elif PANGO_PATCH
itw = TEXTWM(item->text);
#elif TSV_PATCH
itw = TEXTW(item->stext);
#else
itw = TEXTW(item->text);
#endif // PANGO_PATCH | TSV_PATCH
#if SYMBOLS_PATCH
stw = TEXTW(symbol_2);
#else
stw = TEXTW(">");
#endif // SYMBOLS_PATCH
x = drawitem(item, x, 0, MIN(itw, mw - x - stw - rpad));
#if TSV_PATCH
itw = textw_clamp(item->stext, mw - x - stw - rpad);
#else
itw = textw_clamp(item->text, mw - x - stw - rpad);
#endif // PANGO_PATCH | TSV_PATCH
x = drawitem(item, x, 0, itw);
}
if (next) {
#if SYMBOLS_PATCH