Luke Smith %!s(int64=6) %!d(string=hai) anos
pai
achega
274d4f9a7b
Modificáronse 7 ficheiros con 179 adicións e 108 borrados
  1. 7 5
      LICENSE
  2. 34 44
      Makefile
  3. 8 8
      config.mk
  4. 40 28
      dmenu.1
  5. 70 17
      dmenu.c
  6. 6 6
      dmenu_path
  7. 14 0
      drw.c

+ 7 - 5
LICENSE

@@ -1,13 +1,15 @@
 MIT/X Consortium License
 MIT/X Consortium License
 
 
-© 2006-2014 Anselm R Garbe <anselm@garbe.us>
-© 2010-2012 Connor Lane Smith <cls@lubutu.com>
+© 2006-2019 Anselm R Garbe <anselm@garbe.ca>
+© 2006-2008 Sander van Dijk <a.h.vandijk@gmail.com>
+© 2006-2007 Michał Janeczek <janeczek@gmail.com>
+© 2007 Kris Maglione <jg@suckless.org>
 © 2009 Gottox <gottox@s01.de>
 © 2009 Gottox <gottox@s01.de>
 © 2009 Markus Schnalke <meillo@marmaro.de>
 © 2009 Markus Schnalke <meillo@marmaro.de>
 © 2009 Evan Gates <evan.gates@gmail.com>
 © 2009 Evan Gates <evan.gates@gmail.com>
-© 2006-2008 Sander van Dijk <a dot h dot vandijk at gmail dot com>
-© 2006-2007 Michał Janeczek <janeczek at gmail dot com>
-© 2014-2015 Hiltjo Posthuma <hiltjo@codemadness.org>
+© 2010-2012 Connor Lane Smith <cls@lubutu.com>
+© 2014-2019 Hiltjo Posthuma <hiltjo@codemadness.org>
+© 2015-2018 Quentin Rameau <quinq@fifth.space>
 
 
 Permission is hereby granted, free of charge, to any person obtaining a
 Permission is hereby granted, free of charge, to any person obtaining a
 copy of this software and associated documentation files (the "Software"),
 copy of this software and associated documentation files (the "Software"),

+ 34 - 44
Makefile

@@ -4,71 +4,61 @@
 include config.mk
 include config.mk
 
 
 SRC = drw.c dmenu.c stest.c util.c
 SRC = drw.c dmenu.c stest.c util.c
-OBJ = ${SRC:.c=.o}
+OBJ = $(SRC:.c=.o)
 
 
 all: options dmenu stest
 all: options dmenu stest
 
 
 options:
 options:
 	@echo dmenu build options:
 	@echo dmenu build options:
-	@echo "CFLAGS   = ${CFLAGS}"
-	@echo "LDFLAGS  = ${LDFLAGS}"
-	@echo "CC       = ${CC}"
+	@echo "CFLAGS   = $(CFLAGS)"
+	@echo "LDFLAGS  = $(LDFLAGS)"
+	@echo "CC       = $(CC)"
 
 
 .c.o:
 .c.o:
-	@echo CC $<
-	@${CC} -c ${CFLAGS} $<
+	$(CC) -c $(CFLAGS) $<
 
 
 config.h:
 config.h:
-	@echo creating $@ from config.def.h
-	@cp config.def.h $@
+	cp config.def.h $@
 
 
-${OBJ}: arg.h config.h config.mk drw.h
+$(OBJ): arg.h config.h config.mk drw.h
 
 
 dmenu: dmenu.o drw.o util.o
 dmenu: dmenu.o drw.o util.o
-	@echo CC -o $@
-	@${CC} -o $@ dmenu.o drw.o util.o ${LDFLAGS}
+	$(CC) -o $@ dmenu.o drw.o util.o $(LDFLAGS)
 
 
 stest: stest.o
 stest: stest.o
-	@echo CC -o $@
-	@${CC} -o $@ stest.o ${LDFLAGS}
+	$(CC) -o $@ stest.o $(LDFLAGS)
 
 
 clean:
 clean:
-	@echo cleaning
-	@rm -f dmenu stest ${OBJ} dmenu-${VERSION}.tar.gz
+	rm -f dmenu stest $(OBJ) dmenu-$(VERSION).tar.gz
 
 
 dist: clean
 dist: clean
-	@echo creating dist tarball
-	@mkdir -p dmenu-${VERSION}
-	@cp LICENSE Makefile README arg.h config.def.h config.mk dmenu.1 \
-		drw.h util.h dmenu_path dmenu_run stest.1 ${SRC} \
-		dmenu-${VERSION}
-	@tar -cf dmenu-${VERSION}.tar dmenu-${VERSION}
-	@gzip dmenu-${VERSION}.tar
-	@rm -rf dmenu-${VERSION}
+	mkdir -p dmenu-$(VERSION)
+	cp LICENSE Makefile README arg.h config.def.h config.mk dmenu.1\
+		drw.h util.h dmenu_path dmenu_run stest.1 $(SRC)\
+		dmenu-$(VERSION)
+	tar -cf dmenu-$(VERSION).tar dmenu-$(VERSION)
+	gzip dmenu-$(VERSION).tar
+	rm -rf dmenu-$(VERSION)
 
 
 install: all
 install: all
-	@echo installing executables to ${DESTDIR}${PREFIX}/bin
-	@mkdir -p ${DESTDIR}${PREFIX}/bin
-	@cp -f dmenu dmenu_path dmenu_run stest ${DESTDIR}${PREFIX}/bin
-	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu
-	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_path
-	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_run
-	@chmod 755 ${DESTDIR}${PREFIX}/bin/stest
-	@echo installing manual pages to ${DESTDIR}${MANPREFIX}/man1
-	@mkdir -p ${DESTDIR}${MANPREFIX}/man1
-	@sed "s/VERSION/${VERSION}/g" < dmenu.1 > ${DESTDIR}${MANPREFIX}/man1/dmenu.1
-	@sed "s/VERSION/${VERSION}/g" < stest.1 > ${DESTDIR}${MANPREFIX}/man1/stest.1
-	@chmod 644 ${DESTDIR}${MANPREFIX}/man1/dmenu.1
-	@chmod 644 ${DESTDIR}${MANPREFIX}/man1/stest.1
+	mkdir -p $(DESTDIR)$(PREFIX)/bin
+	cp -f dmenu dmenu_path dmenu_run stest $(DESTDIR)$(PREFIX)/bin
+	chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu
+	chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu_path
+	chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu_run
+	chmod 755 $(DESTDIR)$(PREFIX)/bin/stest
+	mkdir -p $(DESTDIR)$(MANPREFIX)/man1
+	sed "s/VERSION/$(VERSION)/g" < dmenu.1 > $(DESTDIR)$(MANPREFIX)/man1/dmenu.1
+	sed "s/VERSION/$(VERSION)/g" < stest.1 > $(DESTDIR)$(MANPREFIX)/man1/stest.1
+	chmod 644 $(DESTDIR)$(MANPREFIX)/man1/dmenu.1
+	chmod 644 $(DESTDIR)$(MANPREFIX)/man1/stest.1
 
 
 uninstall:
 uninstall:
-	@echo removing executables from ${DESTDIR}${PREFIX}/bin
-	@rm -f ${DESTDIR}${PREFIX}/bin/dmenu
-	@rm -f ${DESTDIR}${PREFIX}/bin/dmenu_path
-	@rm -f ${DESTDIR}${PREFIX}/bin/dmenu_run
-	@rm -f ${DESTDIR}${PREFIX}/bin/stest
-	@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
-	@rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1
-	@rm -f ${DESTDIR}${MANPREFIX}/man1/stest.1
+	rm -f $(DESTDIR)$(PREFIX)/bin/dmenu\
+		$(DESTDIR)$(PREFIX)/bin/dmenu_path\
+		$(DESTDIR)$(PREFIX)/bin/dmenu_run\
+		$(DESTDIR)$(PREFIX)/bin/stest\
+		$(DESTDIR)$(MANPREFIX)/man1/dmenu.1\
+		$(DESTDIR)$(MANPREFIX)/man1/stest.1
 
 
 .PHONY: all options clean dist install uninstall
 .PHONY: all options clean dist install uninstall

+ 8 - 8
config.mk

@@ -1,9 +1,9 @@
 # dmenu version
 # dmenu version
-VERSION = 4.7
+VERSION = 4.9
 
 
 # paths
 # paths
 PREFIX = /usr/local
 PREFIX = /usr/local
-MANPREFIX = ${PREFIX}/share/man
+MANPREFIX = $(PREFIX)/share/man
 
 
 X11INC = /usr/X11R6/include
 X11INC = /usr/X11R6/include
 X11LIB = /usr/X11R6/lib
 X11LIB = /usr/X11R6/lib
@@ -16,16 +16,16 @@ XINERAMAFLAGS = -DXINERAMA
 FREETYPELIBS = -lfontconfig -lXft
 FREETYPELIBS = -lfontconfig -lXft
 FREETYPEINC = /usr/include/freetype2
 FREETYPEINC = /usr/include/freetype2
 # OpenBSD (uncomment)
 # OpenBSD (uncomment)
-#FREETYPEINC = ${X11INC}/freetype2
+#FREETYPEINC = $(X11INC)/freetype2
 
 
 # includes and libs
 # includes and libs
-INCS = -I${X11INC} -I${FREETYPEINC}
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
+INCS = -I$(X11INC) -I$(FREETYPEINC)
+LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS)
 
 
 # flags
 # flags
-CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
-CFLAGS   = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
-LDFLAGS  = -s ${LIBS}
+CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS)
+CFLAGS   = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS)
+LDFLAGS  = $(LIBS)
 
 
 # compiler and linker
 # compiler and linker
 CC = cc
 CC = cc

+ 40 - 28
dmenu.1

@@ -41,8 +41,8 @@ which lists programs in the user's $PATH and runs the result in their $SHELL.
 dmenu appears at the bottom of the screen.
 dmenu appears at the bottom of the screen.
 .TP
 .TP
 .B \-f
 .B \-f
-dmenu grabs the keyboard before reading stdin.  This is faster, but will lock up
-X until stdin reaches end\-of\-file.
+dmenu grabs the keyboard before reading stdin if not reading from a tty. This
+is faster, but will lock up X until stdin reaches end\-of\-file.
 .TP
 .TP
 .B \-i
 .B \-i
 dmenu matches menu items case insensitively.
 dmenu matches menu items case insensitively.
@@ -100,82 +100,94 @@ Confirm input.  Prints the input text to stdout and exits, returning success.
 .B Escape
 .B Escape
 Exit without selecting an item, returning failure.
 Exit without selecting an item, returning failure.
 .TP
 .TP
-C\-a
+.B Ctrl-Left
+Move cursor to the start of the current word
+.TP
+.B Ctrl-Right
+Move cursor to the end of the current word
+.TP
+.B C\-a
 Home
 Home
 .TP
 .TP
-C\-b
+.B C\-b
 Left
 Left
 .TP
 .TP
-C\-c
+.B C\-c
 Escape
 Escape
 .TP
 .TP
-C\-d
+.B C\-d
 Delete
 Delete
 .TP
 .TP
-C\-e
+.B C\-e
 End
 End
 .TP
 .TP
-C\-f
+.B C\-f
 Right
 Right
 .TP
 .TP
-C\-g
+.B C\-g
 Escape
 Escape
 .TP
 .TP
-C\-h
+.B C\-h
 Backspace
 Backspace
 .TP
 .TP
-C\-i
+.B C\-i
 Tab
 Tab
 .TP
 .TP
-C\-j
+.B C\-j
 Return
 Return
 .TP
 .TP
-C\-J
+.B C\-J
 Shift-Return
 Shift-Return
 .TP
 .TP
-C\-k
+.B C\-k
 Delete line right
 Delete line right
 .TP
 .TP
-C\-m
+.B C\-m
 Return
 Return
 .TP
 .TP
-C\-M
+.B C\-M
 Shift-Return
 Shift-Return
 .TP
 .TP
-C\-n
+.B C\-n
 Down
 Down
 .TP
 .TP
-C\-p
+.B C\-p
 Up
 Up
 .TP
 .TP
-C\-u
+.B C\-u
 Delete line left
 Delete line left
 .TP
 .TP
-C\-w
+.B C\-w
 Delete word left
 Delete word left
 .TP
 .TP
-C\-y
+.B C\-y
 Paste from primary X selection
 Paste from primary X selection
 .TP
 .TP
-C\-Y
+.B C\-Y
 Paste from X clipboard
 Paste from X clipboard
 .TP
 .TP
-M\-g
+.B M\-b
+Move cursor to the start of the current word
+.TP
+.B M\-f
+Move cursor to the end of the current word
+.TP
+.B M\-g
 Home
 Home
 .TP
 .TP
-M\-G
+.B M\-G
 End
 End
 .TP
 .TP
-M\-h
+.B M\-h
 Up
 Up
 .TP
 .TP
-M\-j
+.B M\-j
 Page down
 Page down
 .TP
 .TP
-M\-k
+.B M\-k
 Page up
 Page up
 .TP
 .TP
-M\-l
+.B M\-l
 Down
 Down
 .SH SEE ALSO
 .SH SEE ALSO
 .IR dwm (1),
 .IR dwm (1),

+ 70 - 17
dmenu.c

@@ -6,6 +6,7 @@
 #include <string.h>
 #include <string.h>
 #include <strings.h>
 #include <strings.h>
 #include <time.h>
 #include <time.h>
+#include <unistd.h>
 
 
 #include <X11/Xlib.h>
 #include <X11/Xlib.h>
 #include <X11/Xatom.h>
 #include <X11/Xatom.h>
@@ -144,7 +145,7 @@ drawmenu(void)
 	drw_setscheme(drw, scheme[SchemeNorm]);
 	drw_setscheme(drw, scheme[SchemeNorm]);
 	drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0);
 	drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0);
 
 
-	drw_font_getexts(drw->fonts, text, cursor, &curpos, NULL);
+	curpos = TEXTW(text) - TEXTW(&text[cursor]);
 	if ((curpos += lrpad / 2 - 1) < w) {
 	if ((curpos += lrpad / 2 - 1) < w) {
 		drw_setscheme(drw, scheme[SchemeNorm]);
 		drw_setscheme(drw, scheme[SchemeNorm]);
 		drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0);
 		drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0);
@@ -287,18 +288,42 @@ nextrune(int inc)
 	return n;
 	return n;
 }
 }
 
 
+static void
+movewordedge(int dir)
+{
+	if (dir < 0) { /* move cursor to the start of the word*/
+		while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)]))
+			cursor = nextrune(-1);
+		while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)]))
+			cursor = nextrune(-1);
+	} else { /* move cursor to the end of the word */
+		while (text[cursor] && strchr(worddelimiters, text[cursor]))
+			cursor = nextrune(+1);
+		while (text[cursor] && !strchr(worddelimiters, text[cursor]))
+			cursor = nextrune(+1);
+	}
+}
+
 static void
 static void
 keypress(XKeyEvent *ev)
 keypress(XKeyEvent *ev)
 {
 {
 	char buf[32];
 	char buf[32];
 	int len;
 	int len;
-	KeySym ksym = NoSymbol;
+	KeySym ksym;
 	Status status;
 	Status status;
 
 
 	len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status);
 	len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status);
-	if (status == XBufferOverflow)
+	switch (status) {
+	default: /* XLookupNone, XBufferOverflow */
 		return;
 		return;
-	if (ev->state & ControlMask)
+	case XLookupChars:
+		goto insert;
+	case XLookupKeySym:
+	case XLookupBoth:
+		break;
+	}
+
+	if (ev->state & ControlMask) {
 		switch(ksym) {
 		switch(ksym) {
 		case XK_a: ksym = XK_Home;      break;
 		case XK_a: ksym = XK_Home;      break;
 		case XK_b: ksym = XK_Left;      break;
 		case XK_b: ksym = XK_Left;      break;
@@ -334,6 +359,12 @@ keypress(XKeyEvent *ev)
 			XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY,
 			XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY,
 			                  utf8, utf8, win, CurrentTime);
 			                  utf8, utf8, win, CurrentTime);
 			return;
 			return;
+		case XK_Left:
+			movewordedge(-1);
+			goto draw;
+		case XK_Right:
+			movewordedge(+1);
+			goto draw;
 		case XK_Return:
 		case XK_Return:
 		case XK_KP_Enter:
 		case XK_KP_Enter:
 			break;
 			break;
@@ -343,8 +374,14 @@ keypress(XKeyEvent *ev)
 		default:
 		default:
 			return;
 			return;
 		}
 		}
-	else if (ev->state & Mod1Mask)
+	} else if (ev->state & Mod1Mask) {
 		switch(ksym) {
 		switch(ksym) {
+		case XK_b:
+			movewordedge(-1);
+			goto draw;
+		case XK_f:
+			movewordedge(+1);
+			goto draw;
 		case XK_g: ksym = XK_Home;  break;
 		case XK_g: ksym = XK_Home;  break;
 		case XK_G: ksym = XK_End;   break;
 		case XK_G: ksym = XK_End;   break;
 		case XK_h: ksym = XK_Up;    break;
 		case XK_h: ksym = XK_Up;    break;
@@ -354,8 +391,11 @@ keypress(XKeyEvent *ev)
 		default:
 		default:
 			return;
 			return;
 		}
 		}
+	}
+
 	switch(ksym) {
 	switch(ksym) {
 	default:
 	default:
+insert:
 		if (!iscntrl(*buf))
 		if (!iscntrl(*buf))
 			insert(buf, len);
 			insert(buf, len);
 		break;
 		break;
@@ -455,6 +495,8 @@ keypress(XKeyEvent *ev)
 		match();
 		match();
 		break;
 		break;
 	}
 	}
+
+draw:
 	drawmenu();
 	drawmenu();
 }
 }
 
 
@@ -467,10 +509,12 @@ paste(void)
 	Atom da;
 	Atom da;
 
 
 	/* we have been given the current selection, now insert it into input */
 	/* we have been given the current selection, now insert it into input */
-	XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False,
-	                   utf8, &da, &di, &dl, &dl, (unsigned char **)&p);
-	insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p));
-	XFree(p);
+	if (XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False,
+	                   utf8, &da, &di, &dl, &dl, (unsigned char **)&p)
+	    == Success && p) {
+		insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p));
+		XFree(p);
+	}
 	drawmenu();
 	drawmenu();
 }
 }
 
 
@@ -509,7 +553,7 @@ run(void)
 	XEvent ev;
 	XEvent ev;
 
 
 	while (!XNextEvent(dpy, &ev)) {
 	while (!XNextEvent(dpy, &ev)) {
-		if (XFilterEvent(&ev, win))
+		if (XFilterEvent(&ev, None))
 			continue;
 			continue;
 		switch(ev.type) {
 		switch(ev.type) {
 		case Expose:
 		case Expose:
@@ -539,22 +583,21 @@ run(void)
 static void
 static void
 setup(void)
 setup(void)
 {
 {
-	int x, y, i = 0;
+	int x, y, i, j;
 	unsigned int du;
 	unsigned int du;
 	XSetWindowAttributes swa;
 	XSetWindowAttributes swa;
 	XIM xim;
 	XIM xim;
 	Window w, dw, *dws;
 	Window w, dw, *dws;
 	XWindowAttributes wa;
 	XWindowAttributes wa;
+	XClassHint ch = {"dmenu", "dmenu"};
 #ifdef XINERAMA
 #ifdef XINERAMA
 	XineramaScreenInfo *info;
 	XineramaScreenInfo *info;
 	Window pw;
 	Window pw;
-	int a, j, di, n, area = 0;
+	int a, di, n, area = 0;
 #endif
 #endif
-
 	/* init appearance */
 	/* init appearance */
-	scheme[SchemeNorm] = drw_scm_create(drw, colors[SchemeNorm], 2);
-	scheme[SchemeSel] = drw_scm_create(drw, colors[SchemeSel], 2);
-	scheme[SchemeOut] = drw_scm_create(drw, colors[SchemeOut], 2);
+	for (j = 0; j < SchemeLast; j++)
+		scheme[j] = drw_scm_create(drw, colors[j], 2);
 
 
 	clip = XInternAtom(dpy, "CLIPBOARD",   False);
 	clip = XInternAtom(dpy, "CLIPBOARD",   False);
 	utf8 = XInternAtom(dpy, "UTF8_STRING", False);
 	utf8 = XInternAtom(dpy, "UTF8_STRING", False);
@@ -564,6 +607,7 @@ setup(void)
 	lines = MAX(lines, 0);
 	lines = MAX(lines, 0);
 	mh = (lines + 1) * bh;
 	mh = (lines + 1) * bh;
 #ifdef XINERAMA
 #ifdef XINERAMA
+	i = 0;
 	if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
 	if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
 		XGetInputFocus(dpy, &w, &di);
 		XGetInputFocus(dpy, &w, &di);
 		if (mon >= 0 && mon < n)
 		if (mon >= 0 && mon < n)
@@ -613,6 +657,7 @@ setup(void)
 	win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
 	win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
 	                    CopyFromParent, CopyFromParent, CopyFromParent,
 	                    CopyFromParent, CopyFromParent, CopyFromParent,
 	                    CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
 	                    CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
+	XSetClassHint(dpy, win, &ch);
 
 
 	/* open input methods */
 	/* open input methods */
 	xim = XOpenIM(dpy, NULL, NULL, NULL);
 	xim = XOpenIM(dpy, NULL, NULL, NULL);
@@ -620,6 +665,7 @@ setup(void)
 	                XNClientWindow, win, XNFocusWindow, win, NULL);
 	                XNClientWindow, win, XNFocusWindow, win, NULL);
 
 
 	XMapRaised(dpy, win);
 	XMapRaised(dpy, win);
+	XSetInputFocus(dpy, win, RevertToParent, CurrentTime);
 	if (embed) {
 	if (embed) {
 		XSelectInput(dpy, parentwin, FocusChangeMask);
 		XSelectInput(dpy, parentwin, FocusChangeMask);
 		if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) {
 		if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) {
@@ -685,6 +731,8 @@ main(int argc, char *argv[])
 
 
 	if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
 	if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
 		fputs("warning: no locale support\n", stderr);
 		fputs("warning: no locale support\n", stderr);
+	if (!XSetLocaleModifiers(""))
+		fputs("warning: no locale modifiers support\n", stderr);
 	if (!(dpy = XOpenDisplay(NULL)))
 	if (!(dpy = XOpenDisplay(NULL)))
 		die("cannot open display");
 		die("cannot open display");
 	screen = DefaultScreen(dpy);
 	screen = DefaultScreen(dpy);
@@ -699,7 +747,12 @@ main(int argc, char *argv[])
 		die("no fonts could be loaded.");
 		die("no fonts could be loaded.");
 	lrpad = drw->fonts->h;
 	lrpad = drw->fonts->h;
 
 
-	if (fast) {
+#ifdef __OpenBSD__
+	if (pledge("stdio rpath", NULL) == -1)
+		die("pledge");
+#endif
+
+	if (fast && !isatty(0)) {
 		grabkeyboard();
 		grabkeyboard();
 		readstdin();
 		readstdin();
 	} else {
 	} else {

+ 6 - 6
dmenu_path

@@ -1,10 +1,10 @@
 #!/bin/sh
 #!/bin/sh
-cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"}
-if [ -d "$cachedir" ]; then
-	cache=$cachedir/dmenu_run
-else
-	cache=$HOME/.dmenu_cache # if no xdg dir, fall back to dotfile in ~
-fi
+
+cachedir="${XDG_CACHE_HOME:-"$HOME/.cache"}"
+cache="$cachedir/dmenu_run"
+
+[ ! -e "$cachedir" ] && mkdir -p "$cachedir"
+
 IFS=:
 IFS=:
 if stest -dqr -n "$cache" $PATH; then
 if stest -dqr -n "$cache" $PATH; then
 	stest -flx $PATH | sort -u | tee "$cache"
 	stest -flx $PATH | sort -u | tee "$cache"

+ 14 - 0
drw.c

@@ -132,6 +132,19 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
 		die("no font specified.");
 		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 = ecalloc(1, sizeof(Fnt));
 	font->xfont = xfont;
 	font->xfont = xfont;
 	font->pattern = pattern;
 	font->pattern = pattern;
@@ -337,6 +350,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
 			fcpattern = FcPatternDuplicate(drw->fonts->pattern);
 			fcpattern = FcPatternDuplicate(drw->fonts->pattern);
 			FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
 			FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
 			FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
 			FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
+			FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
 
 
 			FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
 			FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
 			FcDefaultSubstitute(fcpattern);
 			FcDefaultSubstitute(fcpattern);