diff --git a/PKGBUILD b/PKGBUILD index 5476feb..44a319f 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,11 +1,9 @@ # Maintainer: Jef Roosens -pkgname=jjr-dmenu -pkgver=5.3 +pkgname="jjr-dmenu" +pkgver="5.2" pkgrel=1 pkgdesc="Chewing_Bever's custom build of Suckless's dmenu." -url="https://git.rustybever.be/Chewing_Bever/dmenu" - arch=( "x86_64" "x86_64_tigerlake" @@ -13,10 +11,11 @@ arch=( "aarch64" ) +url="https://git.rustybever.be/Chewing_Bever/dmenu" license=("MIT") -depends=("glibc" "libxinerama" "libxft" "fontconfig" "freetype2") -makedepends=("gcc") +depends=("libxinerama" "libxft" "fontconfig" "freetype2") +makedepends=("glibc" "gcc") provides=("dmenu") conflicts=("dmenu-git") @@ -25,19 +24,19 @@ source=("arg.h" "config.h" "config.mk" "dmenu.1" "dmenu.c" "dmenu_path.sh" "stest.c" "util.c" "util.h") sha256sums=('9ed2b2e3396fdebc8ecab2cdbb09db115cca015f63ec0443b8ccc56340b6b03c' '9ae33f74aed02823abb8381e553d38455541ce3b6a0d642282b693992e71caef' - '5a6066f1cf97aaee4792708893faa1f16fad39d4dce22c79ccfb7590349fe0cc' + 'f6de4c72dab3b9bef214bd52e6a7dff22e87a3118abaffd26ec1ae589cf68b3f' '9f749419697381a1db77e9b23cb41629808fd7e451d475c9b5ee0e88bee803f6' - 'dc93fd213531f01c968ec073382d4c91c14a3fb2464e1a62e23e94653a74fb81' + '5b2a53db7ba608d392efaa96be5530665b46107dc4e0ee1a864745a6e8a8587d' 'a3f19e648e20eb80532dfe87e9bd9feeaa92df838e6ecc061f274c9da579d617' '564035fd8a8ade6504521d98fa10e8732e135403d546d04ca77316fe4a67b21c' - '8c9f81b98f447440cf59dd3eefda99eec4e7733266ad0c072612163ccff4e1df' - '7ed1cf72bfcb0f5444f338293aef74c455ce4ed5463f171a48358f64d7835d49' + 'a7c7358ce13c8571044b79d5d91d01314d9174793474a27faa37d23c75ab603f' + 'c35796210ea8410ae096025cc0d7996dccb3d9936306dff7531a0bb253e079f5' '9f8e922fcfc18ffcc4975dd0b1bee38302bd4e0c538251dfef6d77cd7ed59c89' 'c32b5173eddf376296af085725cb878e4ca2603d4fda8bba3faac6a2bb1b4390' 'ec98e8759049af796598f0790752a21a69eaea1d438b09c39922d4a9f4a7cfe2' '00d3389ef8858a565cf3fb3445620b90eb67d1a9b31434f4d54b05ed6c5abefb' 'ba76404e61abbd734e315999ffe4e883419c4c69ff17a5d4d88a5cd11dd4b055' - '1c093b9969daaf3e1a001b924c6c2da3770993916b444dfe65fe39aa0090aa1a' + 'dec870d0b5834c9008ff62f495710daf524cffdf12d0cf8ba4fadf5643623987' '1196a7b6efbf4cb3f5c435fffd72e7647f977483845d5c78c1c48d9ab8b96819') build() { @@ -57,5 +56,3 @@ package() { # install $installopts "$docdir" README.terminfo.rst # install $installopts "$shrdir/$pkgname" "$_sourcedir/st.info" } - -# vim: ft=bash diff --git a/config.mk b/config.mk index 0ea1efd..ddb33fa 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ # dmenu version -VERSION = 5.3 +VERSION = 5.2 # paths PREFIX = /usr/local @@ -17,7 +17,6 @@ FREETYPELIBS = -lfontconfig -lXft FREETYPEINC = /usr/include/freetype2 # OpenBSD (uncomment) #FREETYPEINC = $(X11INC)/freetype2 -#MANPREFIX = ${PREFIX}/man # includes and libs INCS = -I$(X11INC) -I$(FREETYPEINC) diff --git a/dmenu.c b/dmenu.c index 0363aa0..b264d53 100644 --- a/dmenu.c +++ b/dmenu.c @@ -61,13 +61,6 @@ static char * cistrstr(const char *s, const char *sub); static int (*fstrncmp)(const char *, const char *, size_t) = strncasecmp; static char *(*fstrstr)(const char *, const char *) = cistrstr; -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) { @@ -92,10 +85,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 : textw_clamp(next->text, n)) > n) + if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n) break; for (i = 0, prev = curr; prev && prev->left; prev = prev->left) - if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n) + if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n) break; } @@ -107,9 +100,6 @@ cleanup(void) XUngrabKey(dpy, AnyKey, AnyModifier, root); for (i = 0; i < SchemeLast; i++) free(scheme[i]); - for (i = 0; items && items[i].text; ++i) - free(items[i].text); - free(items); drw_free(drw); XSync(dpy, False); XCloseDisplay(dpy); @@ -185,7 +175,7 @@ drawmenu(void) } x += w; for (item = curr; item != next; item = item->right) - x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW(">"))); + x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">"))); if (next) { w = TEXTW(">"); drw_setscheme(drw, scheme[SchemeNorm]); @@ -330,7 +320,7 @@ match(void) /* separate input text into tokens to be matched individually */ for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " ")) if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv))) - die("cannot realloc %zu bytes:", tokn * sizeof *tokv); + die("cannot realloc %u bytes:", tokn * sizeof *tokv); len = tokc ? strlen(tokv[0]) : 0; matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL; @@ -503,7 +493,7 @@ keypress(XKeyEvent *ev) switch(ksym) { default: insert: - if (!iscntrl((unsigned char)*buf)) + if (!iscntrl(*buf)) insert(buf, len); break; case XK_Delete: @@ -605,9 +595,9 @@ insert: case XK_Tab: if (!sel) return; - cursor = strnlen(sel->text, sizeof text - 1); - memcpy(text, sel->text, cursor); - text[cursor] = '\0'; + strncpy(text, sel->text, sizeof text - 1); + text[sizeof text - 1] = '\0'; + cursor = strlen(text); match(); break; } @@ -637,22 +627,29 @@ paste(void) static void readstdin(void) { - char *line = NULL; - size_t i, junk, size = 0; - ssize_t len; + char buf[sizeof text], *p; + size_t i, imax = 0, size = 0; + unsigned int tmpmax = 0; /* read each line from stdin and add it to the item list */ - for (i = 0; (len = getline(&line, &junk, stdin)) != -1; i++, line = NULL) { + for (i = 0; fgets(buf, sizeof buf, stdin); i++) { if (i + 1 >= size / sizeof *items) if (!(items = realloc(items, (size += BUFSIZ)))) - die("cannot realloc %zu bytes:", size); - if (line[len - 1] == '\n') - line[len - 1] = '\0'; - items[i].text = line; + die("cannot realloc %u bytes:", size); + if ((p = strchr(buf, '\n'))) + *p = '\0'; + if (!(items[i].text = strdup(buf))) + die("cannot strdup %u bytes:", strlen(buf) + 1); items[i].out = 0; + drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL); + if (tmpmax > inputw) { + inputw = tmpmax; + imax = i; + } } if (items) items[i].text = NULL; + inputw = items ? TEXTW(items[imax].text) : 0; lines = MIN(lines, i); } @@ -761,7 +758,7 @@ setup(void) mw = wa.width; } promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; - inputw = mw / 3; /* input width: ~33% of monitor width */ + inputw = MIN(inputw, mw/3); match(); /* create menu window */ @@ -798,8 +795,9 @@ setup(void) static void usage(void) { - die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" - " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]"); + fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" + " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); + exit(1); } int diff --git a/drw.c b/drw.c index a58a2b4..4cdbcbe 100644 --- a/drw.c +++ b/drw.c @@ -133,6 +133,19 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) die("no font specified."); } + /* Do not allow using color fonts. This is a workaround for a BadLength + * error from Xft with color glyphs. Modelled on the Xterm workaround. See + * https://bugzilla.redhat.com/show_bug.cgi?id=1498269 + * https://lists.suckless.org/dev/1701/30932.html + * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349 + * and lots more all over the internet. + */ + FcBool iscol; + if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) { + XftFontClose(drw->dpy, xfont); + return NULL; + } + font = ecalloc(1, sizeof(Fnt)); font->xfont = xfont; font->pattern = pattern; @@ -238,10 +251,12 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) { - int i, ty, ellipsis_x = 0; - unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len; + char buf[1024]; + int ty; + unsigned int ew; XftDraw *d = NULL; Fnt *usedfont, *curfont, *nextfont; + size_t i, len; int utf8strlen, utf8charlen, render = x || y || w || h; long utf8codepoint = 0; const char *utf8str; @@ -249,17 +264,13 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp FcPattern *fcpattern; FcPattern *match; XftResult result; - int charexists = 0, overflow = 0; - /* keep track of a couple codepoints for which we have no match. */ - enum { nomatches_len = 64 }; - static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches; - static unsigned int ellipsis_width = 0; + int charexists = 0; - if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) + if (!drw || (render && !drw->scheme) || !text || !drw->fonts) return 0; if (!render) { - w = invert ? invert : ~invert; + w = ~w; } else { XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); @@ -271,10 +282,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp } usedfont = drw->fonts; - if (!ellipsis_width && render) - ellipsis_width = drw_fontset_getwidth(drw, "..."); while (1) { - ew = ellipsis_len = utf8strlen = 0; + utf8strlen = 0; utf8str = text; nextfont = NULL; while (*text) { @@ -282,27 +291,9 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp for (curfont = drw->fonts; curfont; curfont = curfont->next) { charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); if (charexists) { - drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL); - if (ew + ellipsis_width <= w) { - /* keep track where the ellipsis still fits */ - ellipsis_x = x + ew; - ellipsis_w = w - ew; - ellipsis_len = utf8strlen; - } - - if (ew + tmpw > w) { - overflow = 1; - /* called from drw_fontset_getwidth_clamp(): - * it wants the width AFTER the overflow - */ - if (!render) - x += tmpw; - else - utf8strlen = ellipsis_len; - } else if (curfont == usedfont) { + if (curfont == usedfont) { utf8strlen += utf8charlen; text += utf8charlen; - ew += tmpw; } else { nextfont = curfont; } @@ -310,25 +301,36 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp } } - if (overflow || !charexists || nextfont) + if (!charexists || nextfont) break; else charexists = 0; } if (utf8strlen) { - if (render) { - ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; - XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], - usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen); - } - x += ew; - w -= ew; - } - if (render && overflow) - drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert); + drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL); + /* shorten text if necessary */ + for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--) + drw_font_getexts(usedfont, utf8str, len, &ew, NULL); - if (!*text || overflow) { + if (len) { + memcpy(buf, utf8str, len); + buf[len] = '\0'; + if (len < utf8strlen) + for (i = len; i && i > len - 3; buf[--i] = '.') + ; /* NOP */ + + if (render) { + ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; + XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], + usedfont->xfont, x, ty, (XftChar8 *)buf, len); + } + x += ew; + w -= ew; + } + } + + if (!*text) { break; } else if (nextfont) { charexists = 0; @@ -338,12 +340,6 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp * character must be drawn. */ charexists = 1; - for (i = 0; i < nomatches_len; ++i) { - /* avoid calling XftFontMatch if we know we won't find a match */ - if (utf8codepoint == nomatches.codepoint[i]) - goto no_match; - } - fccharset = FcCharSetCreate(); FcCharSetAddChar(fccharset, utf8codepoint); @@ -355,6 +351,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp fcpattern = FcPatternDuplicate(drw->fonts->pattern); FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); + FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); FcDefaultSubstitute(fcpattern); @@ -371,8 +368,6 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp curfont->next = usedfont; } else { xfont_free(usedfont); - nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint; -no_match: usedfont = drw->fonts; } } @@ -402,15 +397,6 @@ drw_fontset_getwidth(Drw *drw, const char *text) return drw_text(drw, 0, 0, 0, 0, 0, text, 0); } -unsigned int -drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n) -{ - unsigned int tmp = 0; - if (drw && drw->fonts && text && n) - tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n); - return MIN(n, tmp); -} - void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h) { diff --git a/drw.h b/drw.h index fd7631b..4c67419 100644 --- a/drw.h +++ b/drw.h @@ -35,7 +35,6 @@ void drw_free(Drw *drw); Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount); void drw_fontset_free(Fnt* set); unsigned int drw_fontset_getwidth(Drw *drw, const char *text); -unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n); void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h); /* Colorscheme abstraction */ diff --git a/util.c b/util.c index 96b82c9..fe044fc 100644 --- a/util.c +++ b/util.c @@ -6,9 +6,18 @@ #include "util.h" -void -die(const char *fmt, ...) +void * +ecalloc(size_t nmemb, size_t size) { + void *p; + + if (!(p = calloc(nmemb, size))) + die("calloc:"); + return p; +} + +void +die(const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -24,13 +33,3 @@ die(const char *fmt, ...) exit(1); } - -void * -ecalloc(size_t nmemb, size_t size) -{ - void *p; - - if (!(p = calloc(nmemb, size))) - die("calloc:"); - return p; -}