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 0000000..2da67fa Binary files /dev/null and b/stest differ 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);