From aaa18d5eb6c7a935766af489a3e3f3136278d3cc Mon Sep 17 00:00:00 2001 From: mrsu Date: Sat, 15 Jun 2024 23:10:51 +0100 Subject: [PATCH] updated dmenu and patched xresources --- Makefile | 10 +- config.def.h | 34 ++++- config.mk | 2 +- dmenu.c | 75 ++++++++++- drw.c | 25 ++-- drw.h | 2 +- patches/dmenu-xresources-alt-5.0.diff | 182 ++++++++++++++++++++++++++ stest | Bin 0 -> 16432 bytes util.h | 1 + 9 files changed, 297 insertions(+), 34 deletions(-) create mode 100644 patches/dmenu-xresources-alt-5.0.diff create mode 100755 stest diff --git a/Makefile b/Makefile index a03a95c..458c524 100644 --- a/Makefile +++ b/Makefile @@ -6,13 +6,7 @@ include config.mk SRC = drw.c dmenu.c stest.c util.c OBJ = $(SRC:.c=.o) -all: options dmenu stest - -options: - @echo dmenu build options: - @echo "CFLAGS = $(CFLAGS)" - @echo "LDFLAGS = $(LDFLAGS)" - @echo "CC = $(CC)" +all: dmenu stest .c.o: $(CC) -c $(CFLAGS) $< @@ -61,4 +55,4 @@ uninstall: $(DESTDIR)$(MANPREFIX)/man1/dmenu.1\ $(DESTDIR)$(MANPREFIX)/man1/stest.1 -.PHONY: all options clean dist install uninstall +.PHONY: all clean dist install uninstall diff --git a/config.def.h b/config.def.h index e63c997..cfbf03c 100644 --- a/config.def.h +++ b/config.def.h @@ -3,17 +3,25 @@ static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ static int fuzzy = 1; /* -F option; if 0, dmenu doesn't use fuzzy matching */ + /* -fn option overrides fonts[0]; default X11 font or font set */ +static char font[] = "monospace:size=10"; static const char *fonts[] = { - "monospace:size=14", - "NotoColorEmoji:pixelsize=48:antialias=true:autohint=true" + font, + "monospace:size=10", }; -static const char *prompt = NULL; /* -p option; prompt to the left of input field */ -static const char *colors[SchemeLast][2] = { + +static char *prompt = NULL; /* -p option; prompt to the left of input field */ + +static char normfgcolor[] = "#bbbbbb"; +static char normbgcolor[] = "#222222"; +static char selfgcolor[] = "#eeeeee"; +static char selbgcolor[] = "#005577"; +static char *colors[SchemeLast][2] = { /* fg bg */ - [SchemeNorm] = { "#ebdbb2", "#282828" }, - [SchemeSel] = { "#ffffff", "#005577" }, - [SchemeOut] = { "#000000", "#00ffff" }, + [SchemeNorm] = { normfgcolor, normbgcolor }, + [SchemeSel] = { selfgcolor, selbgcolor }, + [SchemeOut] = { "#000000", "#00ffff" }, }; /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ static unsigned int lines = 0; @@ -23,3 +31,15 @@ static unsigned int lines = 0; * for example: " /?\"&[]" */ static const char worddelimiters[] = " "; + +/* + * Xresources preferences to load at startup + */ +ResourcePref resources[] = { + { "font", STRING, &font }, + { "normfgcolor", STRING, &normfgcolor }, + { "normbgcolor", STRING, &normbgcolor }, + { "selfgcolor", STRING, &selfgcolor }, + { "selbgcolor", STRING, &selbgcolor }, + { "prompt", STRING, &prompt }, +}; diff --git a/config.mk b/config.mk index fd6ff05..6a19175 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ # dmenu version -VERSION = 5.2 +VERSION = 5.3 # paths PREFIX = /usr/local diff --git a/dmenu.c b/dmenu.c index 24c1558..c9756a5 100644 --- a/dmenu.c +++ b/dmenu.c @@ -12,6 +12,7 @@ #include #include #include +#include #ifdef XINERAMA #include #endif @@ -23,7 +24,6 @@ /* macros */ #define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \ * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) -#define LENGTH(X) (sizeof X / sizeof X[0]) #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) /* enums */ @@ -55,6 +55,21 @@ static XIC xic; static Drw *drw; static Clr *scheme[SchemeLast]; +/* Xresources preferences */ +enum resource_type { + STRING = 0, + INTEGER = 1, + FLOAT = 2 +}; +typedef struct { + char *name; + enum resource_type type; + void *dst; +} ResourcePref; + +static void load_xresources(void); +static void resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst); + #include "config.h" static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; @@ -501,7 +516,7 @@ keypress(XKeyEvent *ev) switch(ksym) { default: -insert: + insert: if (!iscntrl((unsigned char)*buf)) insert(buf, len); break; @@ -660,6 +675,54 @@ readstdin(void) lines = MIN(lines, i); } +void +resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst) +{ + char *sdst = NULL; + int *idst = NULL; + float *fdst = NULL; + sdst = dst; + idst = dst; + fdst = dst; + char fullname[256]; + char *type; + XrmValue ret; + snprintf(fullname, sizeof(fullname), "%s.%s", "dmenu", name); + fullname[sizeof(fullname) - 1] = '\0'; + XrmGetResource(db, fullname, "*", &type, &ret); + if (!(ret.addr == NULL || strncmp("String", type, 64))) + { + switch (rtype) { + case STRING: + strcpy(sdst, ret.addr); + break; + case INTEGER: + *idst = strtoul(ret.addr, NULL, 10); + break; + case FLOAT: + *fdst = strtof(ret.addr, NULL); + break; + } + } +} + +void +load_xresources(void) +{ + Display *display; + char *resm; + XrmDatabase db; + ResourcePref *p; + display = XOpenDisplay(NULL); + resm = XResourceManagerString(display); + if (!resm) + return; + db = XrmGetStringDatabase(resm); + for (p = resources; p < resources + LENGTH(resources); p++) + resource_load(db, p->name, p->type, p->dst); + XCloseDisplay(display); +} + static void run(void) { @@ -803,9 +866,8 @@ 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]\n" - " [-it text]\n"); + die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor] [-it text]\n" + " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]"); } int @@ -814,6 +876,9 @@ main(int argc, char *argv[]) XWindowAttributes wa; int i, fast = 0; + XrmInitialize(); + load_xresources(); + for (i = 1; i < argc; i++) /* these options take no arguments */ if (!strcmp(argv[i], "-v")) { /* prints version information */ diff --git a/drw.c b/drw.c index a58a2b4..85496b5 100644 --- a/drw.c +++ b/drw.c @@ -195,7 +195,7 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname) /* Wrapper to create color schemes. The caller has to call free(3) on the * returned color scheme when done using it. */ Clr * -drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) +drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount) { size_t i; Clr *ret; @@ -238,8 +238,8 @@ 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; + int ty, ellipsis_x = 0; + unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, hash, h0, h1; XftDraw *d = NULL; Fnt *usedfont, *curfont, *nextfont; int utf8strlen, utf8charlen, render = x || y || w || h; @@ -251,9 +251,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp 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; + static unsigned int nomatches[128], ellipsis_width; if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) return 0; @@ -338,11 +336,14 @@ 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; - } + hash = (unsigned int)utf8codepoint; + hash = ((hash >> 16) ^ hash) * 0x21F0AAAD; + hash = ((hash >> 15) ^ hash) * 0xD35A2D97; + h0 = ((hash >> 15) ^ hash) % LENGTH(nomatches); + h1 = (hash >> 17) % LENGTH(nomatches); + /* avoid expensive XftFontMatch call when we know we won't find a match */ + if (nomatches[h0] == utf8codepoint || nomatches[h1] == utf8codepoint) + goto no_match; fccharset = FcCharSetCreate(); FcCharSetAddChar(fccharset, utf8codepoint); @@ -371,7 +372,7 @@ 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; + nomatches[nomatches[h0] ? h1 : h0] = utf8codepoint; no_match: usedfont = drw->fonts; } diff --git a/drw.h b/drw.h index fd7631b..0d91aad 100644 --- a/drw.h +++ b/drw.h @@ -40,7 +40,7 @@ void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned in /* Colorscheme abstraction */ void drw_clr_create(Drw *drw, Clr *dest, const char *clrname); -Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount); +Clr *drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount); /* Cursor abstraction */ Cur *drw_cur_create(Drw *drw, int shape); diff --git a/patches/dmenu-xresources-alt-5.0.diff b/patches/dmenu-xresources-alt-5.0.diff new file mode 100644 index 0000000..f7f052f --- /dev/null +++ b/patches/dmenu-xresources-alt-5.0.diff @@ -0,0 +1,182 @@ +diff -rupN orig/config.def.h patched/config.def.h +--- orig/config.def.h 2021-04-16 06:30:47.713924755 +0300 ++++ patched/config.def.h 2021-04-16 06:34:14.956933252 +0300 +@@ -2,16 +2,25 @@ + /* Default settings; can be overriden by command line. */ + + static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ ++ + /* -fn option overrides fonts[0]; default X11 font or font set */ ++static char font[] = "monospace:size=10"; + static const char *fonts[] = { +- "monospace:size=10" ++ font, ++ "monospace:size=10", + }; +-static const char *prompt = NULL; /* -p option; prompt to the left of input field */ +-static const char *colors[SchemeLast][2] = { ++ ++static char *prompt = NULL; /* -p option; prompt to the left of input field */ ++ ++static char normfgcolor[] = "#bbbbbb"; ++static char normbgcolor[] = "#222222"; ++static char selfgcolor[] = "#eeeeee"; ++static char selbgcolor[] = "#005577"; ++static char *colors[SchemeLast][2] = { + /* fg bg */ +- [SchemeNorm] = { "#bbbbbb", "#222222" }, +- [SchemeSel] = { "#eeeeee", "#005577" }, +- [SchemeOut] = { "#000000", "#00ffff" }, ++ [SchemeNorm] = { normfgcolor, normbgcolor }, ++ [SchemeSel] = { selfgcolor, selbgcolor }, ++ [SchemeOut] = { "#000000", "#00ffff" }, + }; + /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ + static unsigned int lines = 0; +@@ -21,3 +30,15 @@ static unsigned int lines = 0; + * for example: " /?\"&[]" + */ + static const char worddelimiters[] = " "; ++ ++/* ++ * Xresources preferences to load at startup ++ */ ++ResourcePref resources[] = { ++ { "font", STRING, &font }, ++ { "normfgcolor", STRING, &normfgcolor }, ++ { "normbgcolor", STRING, &normbgcolor }, ++ { "selfgcolor", STRING, &selfgcolor }, ++ { "selbgcolor", STRING, &selbgcolor }, ++ { "prompt", STRING, &prompt }, ++}; +diff -rupN orig/dmenu.c patched/dmenu.c +--- orig/dmenu.c 2021-04-16 06:30:47.715924755 +0300 ++++ patched/dmenu.c 2021-04-16 06:30:59.668925245 +0300 +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #ifdef XINERAMA + #include + #endif +@@ -53,6 +54,21 @@ static XIC xic; + static Drw *drw; + static Clr *scheme[SchemeLast]; + ++/* Xresources preferences */ ++enum resource_type { ++ STRING = 0, ++ INTEGER = 1, ++ FLOAT = 2 ++}; ++typedef struct { ++ char *name; ++ enum resource_type type; ++ void *dst; ++} ResourcePref; ++ ++static void load_xresources(void); ++static void resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst); ++ + #include "config.h" + + static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; +@@ -395,7 +411,7 @@ keypress(XKeyEvent *ev) + + switch(ksym) { + default: +-insert: ++ insert: + if (!iscntrl(*buf)) + insert(buf, len); + break; +@@ -547,6 +563,54 @@ readstdin(void) + lines = MIN(lines, i); + } + ++void ++resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst) ++{ ++ char *sdst = NULL; ++ int *idst = NULL; ++ float *fdst = NULL; ++ sdst = dst; ++ idst = dst; ++ fdst = dst; ++ char fullname[256]; ++ char *type; ++ XrmValue ret; ++ snprintf(fullname, sizeof(fullname), "%s.%s", "dmenu", name); ++ fullname[sizeof(fullname) - 1] = '\0'; ++ XrmGetResource(db, fullname, "*", &type, &ret); ++ if (!(ret.addr == NULL || strncmp("String", type, 64))) ++ { ++ switch (rtype) { ++ case STRING: ++ strcpy(sdst, ret.addr); ++ break; ++ case INTEGER: ++ *idst = strtoul(ret.addr, NULL, 10); ++ break; ++ case FLOAT: ++ *fdst = strtof(ret.addr, NULL); ++ break; ++ } ++ } ++} ++ ++void ++load_xresources(void) ++{ ++ Display *display; ++ char *resm; ++ XrmDatabase db; ++ ResourcePref *p; ++ display = XOpenDisplay(NULL); ++ resm = XResourceManagerString(display); ++ if (!resm) ++ return; ++ db = XrmGetStringDatabase(resm); ++ for (p = resources; p < resources + LENGTH(resources); p++) ++ resource_load(db, p->name, p->type, p->dst); ++ XCloseDisplay(display); ++} ++ + static void + run(void) + { +@@ -700,6 +764,9 @@ main(int argc, char *argv[]) + XWindowAttributes wa; + int i, fast = 0; + ++ XrmInitialize(); ++ load_xresources(); ++ + for (i = 1; i < argc; i++) + /* these options take no arguments */ + if (!strcmp(argv[i], "-v")) { /* prints version information */ +diff -rupN orig/drw.c patched/drw.c +--- orig/drw.c 2021-04-16 06:30:47.718924755 +0300 ++++ patched/drw.c 2021-04-16 06:30:59.670925245 +0300 +@@ -208,7 +208,7 @@ drw_clr_create(Drw *drw, Clr *dest, cons + /* Wrapper to create color schemes. The caller has to call free(3) on the + * returned color scheme when done using it. */ + Clr * +-drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) ++drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount) + { + size_t i; + Clr *ret; +diff -rupN orig/drw.h patched/drw.h +--- orig/drw.h 2021-04-16 06:30:47.718924755 +0300 ++++ patched/drw.h 2021-04-16 06:30:59.671925245 +0300 +@@ -39,7 +39,7 @@ void drw_font_getexts(Fnt *font, const c + + /* Colorscheme abstraction */ + void drw_clr_create(Drw *drw, Clr *dest, const char *clrname); +-Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount); ++Clr *drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount); + + /* Cursor abstraction */ + Cur *drw_cur_create(Drw *drw, int shape); diff --git a/stest b/stest new file mode 100755 index 0000000000000000000000000000000000000000..2da67fa6faa75834272fbf09bddbf42ce520da1a GIT binary patch literal 16432 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 W?Xn_0uGQ@S`bJaZ3Y&qA75@Xp8@xvV literal 0 HcmV?d00001 diff --git a/util.h b/util.h index f633b51..c0a50d4 100644 --- a/util.h +++ b/util.h @@ -3,6 +3,7 @@ #define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MIN(A, B) ((A) < (B) ? (A) : (B)) #define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) +#define LENGTH(X) (sizeof (X) / sizeof (X)[0]) void die(const char *fmt, ...); void *ecalloc(size_t nmemb, size_t size);