4.9 update
7 files changed, 179 insertions(+), 108 deletions(-) M LICENSE M Makefile M config.mk M dmenu.1 M dmenu.c M dmenu_path M drw.c
M LICENSE => LICENSE +7 -5
@@ 1,13 1,15 @@ 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 Markus Schnalke <meillo@marmaro.de> © 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 copy of this software and associated documentation files (the "Software"),
M Makefile => Makefile +34 -44
@@ 4,71 4,61 @@ include config.mk SRC = drw.c dmenu.c stest.c util.c OBJ = ${SRC:.c=.o} OBJ = $(SRC:.c=.o) all: options dmenu stest 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: @echo CC $< @${CC} -c ${CFLAGS} $< $(CC) -c $(CFLAGS) $< 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 @echo CC -o $@ @${CC} -o $@ dmenu.o drw.o util.o ${LDFLAGS} $(CC) -o $@ dmenu.o drw.o util.o $(LDFLAGS) stest: stest.o @echo CC -o $@ @${CC} -o $@ stest.o ${LDFLAGS} $(CC) -o $@ stest.o $(LDFLAGS) clean: @echo cleaning @rm -f dmenu stest ${OBJ} dmenu-${VERSION}.tar.gz rm -f dmenu stest $(OBJ) dmenu-$(VERSION).tar.gz 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 @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: @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
M config.mk => config.mk +8 -8
@@ 1,9 1,9 @@ # dmenu version VERSION = 4.7 VERSION = 4.9 # paths PREFIX = /usr/local MANPREFIX = ${PREFIX}/share/man MANPREFIX = $(PREFIX)/share/man X11INC = /usr/X11R6/include X11LIB = /usr/X11R6/lib @@ 16,16 16,16 @@ XINERAMAFLAGS = -DXINERAMA FREETYPELIBS = -lfontconfig -lXft FREETYPEINC = /usr/include/freetype2 # OpenBSD (uncomment) #FREETYPEINC = ${X11INC}/freetype2 #FREETYPEINC = $(X11INC)/freetype2 # 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 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 CC = cc
M dmenu.1 => dmenu.1 +40 -28
@@ 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. .TP .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 .B \-i dmenu matches menu items case insensitively. @@ 100,82 100,94 @@ Confirm input. Prints the input text to stdout and exits, returning success. .B Escape Exit without selecting an item, returning failure. .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 .TP C\-b .B C\-b Left .TP C\-c .B C\-c Escape .TP C\-d .B C\-d Delete .TP C\-e .B C\-e End .TP C\-f .B C\-f Right .TP C\-g .B C\-g Escape .TP C\-h .B C\-h Backspace .TP C\-i .B C\-i Tab .TP C\-j .B C\-j Return .TP C\-J .B C\-J Shift-Return .TP C\-k .B C\-k Delete line right .TP C\-m .B C\-m Return .TP C\-M .B C\-M Shift-Return .TP C\-n .B C\-n Down .TP C\-p .B C\-p Up .TP C\-u .B C\-u Delete line left .TP C\-w .B C\-w Delete word left .TP C\-y .B C\-y Paste from primary X selection .TP C\-Y .B C\-Y Paste from X clipboard .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 .TP M\-G .B M\-G End .TP M\-h .B M\-h Up .TP M\-j .B M\-j Page down .TP M\-k .B M\-k Page up .TP M\-l .B M\-l Down .SH SEE ALSO .IR dwm (1),
M dmenu.c => dmenu.c +70 -17
@@ 6,6 6,7 @@ #include <string.h> #include <strings.h> #include <time.h> #include <unistd.h> #include <X11/Xlib.h> #include <X11/Xatom.h> @@ 144,7 145,7 @@ drawmenu(void) drw_setscheme(drw, scheme[SchemeNorm]); 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) { drw_setscheme(drw, scheme[SchemeNorm]); drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0); @@ 288,17 289,41 @@ nextrune(int inc) } 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 keypress(XKeyEvent *ev) { char buf[32]; int len; KeySym ksym = NoSymbol; KeySym ksym; Status status; len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status); if (status == XBufferOverflow) switch (status) { default: /* XLookupNone, XBufferOverflow */ return; if (ev->state & ControlMask) case XLookupChars: goto insert; case XLookupKeySym: case XLookupBoth: break; } if (ev->state & ControlMask) { switch(ksym) { case XK_a: ksym = XK_Home; break; case XK_b: ksym = XK_Left; break; @@ 334,6 359,12 @@ keypress(XKeyEvent *ev) XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, utf8, utf8, win, CurrentTime); return; case XK_Left: movewordedge(-1); goto draw; case XK_Right: movewordedge(+1); goto draw; case XK_Return: case XK_KP_Enter: break; @@ 343,8 374,14 @@ keypress(XKeyEvent *ev) default: return; } else if (ev->state & Mod1Mask) } else if (ev->state & Mod1Mask) { 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_End; break; case XK_h: ksym = XK_Up; break; @@ 354,8 391,11 @@ keypress(XKeyEvent *ev) default: return; } } switch(ksym) { default: insert: if (!iscntrl(*buf)) insert(buf, len); break; @@ 455,6 495,8 @@ keypress(XKeyEvent *ev) match(); break; } draw: drawmenu(); } @@ 467,10 509,12 @@ paste(void) Atom da; /* 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(); } @@ 509,7 553,7 @@ run(void) XEvent ev; while (!XNextEvent(dpy, &ev)) { if (XFilterEvent(&ev, win)) if (XFilterEvent(&ev, None)) continue; switch(ev.type) { case Expose: @@ 539,22 583,21 @@ run(void) static void setup(void) { int x, y, i = 0; int x, y, i, j; unsigned int du; XSetWindowAttributes swa; XIM xim; Window w, dw, *dws; XWindowAttributes wa; XClassHint ch = {"dmenu", "dmenu"}; #ifdef XINERAMA XineramaScreenInfo *info; Window pw; int a, j, di, n, area = 0; int a, di, n, area = 0; #endif /* 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); utf8 = XInternAtom(dpy, "UTF8_STRING", False); @@ 564,6 607,7 @@ setup(void) lines = MAX(lines, 0); mh = (lines + 1) * bh; #ifdef XINERAMA i = 0; if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { XGetInputFocus(dpy, &w, &di); if (mon >= 0 && mon < n) @@ 613,6 657,7 @@ setup(void) win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0, CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); XSetClassHint(dpy, win, &ch); /* open input methods */ xim = XOpenIM(dpy, NULL, NULL, NULL); @@ 620,6 665,7 @@ setup(void) XNClientWindow, win, XNFocusWindow, win, NULL); XMapRaised(dpy, win); XSetInputFocus(dpy, win, RevertToParent, CurrentTime); if (embed) { XSelectInput(dpy, parentwin, FocusChangeMask); if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) { @@ 685,6 731,8 @@ main(int argc, char *argv[]) if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) fputs("warning: no locale support\n", stderr); if (!XSetLocaleModifiers("")) fputs("warning: no locale modifiers support\n", stderr); if (!(dpy = XOpenDisplay(NULL))) die("cannot open display"); screen = DefaultScreen(dpy); @@ 699,7 747,12 @@ main(int argc, char *argv[]) die("no fonts could be loaded."); lrpad = drw->fonts->h; if (fast) { #ifdef __OpenBSD__ if (pledge("stdio rpath", NULL) == -1) die("pledge"); #endif if (fast && !isatty(0)) { grabkeyboard(); readstdin(); } else {
M dmenu_path => dmenu_path +6 -6
@@ 1,10 1,10 @@ #!/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=: if stest -dqr -n "$cache" $PATH; then stest -flx $PATH | sort -u | tee "$cache"
M drw.c => drw.c +14 -0
@@ 132,6 132,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; @@ 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); FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); FcDefaultSubstitute(fcpattern);