dmenu: init personal fork
14 files changed, 213 insertions(+), 39 deletions(-) A .gitignore M Makefile M README A config.h M config.mk A dmenu-pass A dmenu-path A dmenu-pinentry A dmenu-run A dmenu-run-recent M dmenu.1 M dmenu.c D dmenu_path D dmenu_run
A .gitignore => .gitignore +3 -0
M Makefile => Makefile +12 -6
@@ 34,7 34,7 @@ clean: dist: clean 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)\ drw.h util.h dmenu-path dmenu-run dmenu-run-recent dmenu-pass dmenu-pinentry stest.1 $(SRC)\ dmenu-$(VERSION) tar -cf dmenu-$(VERSION).tar dmenu-$(VERSION) @@ gzip dmenu-$(VERSION).tar 42,10 42,13 @@ dist: clean install: all mkdir -p $(DESTDIR)$(PREFIX)/bin cp -f dmenu dmenu_path dmenu_run stest $(DESTDIR)$(PREFIX)/bin cp -f dmenu dmenu-path dmenu-run dmenu-run-recent dmenu-pass dmenu-pinentry 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/dmenu-path chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu-run chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu-run-recent chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu-pass chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu-pinentry chmod 755 $(DESTDIR)$(PREFIX)/bin/stest mkdir -p $(DESTDIR)$(MANPREFIX)/man1 @@ sed "s/VERSION/$(VERSION)/g" < dmenu.1 > $(DESTDIR)$(MANPREFIX)/man1/dmenu.1 55,8 58,11 @@ install: all uninstall: rm -f $(DESTDIR)$(PREFIX)/bin/dmenu\ $(DESTDIR)$(PREFIX)/bin/dmenu_path\ $(DESTDIR)$(PREFIX)/bin/dmenu_run\ $(DESTDIR)$(PREFIX)/bin/dmenu-path\ $(DESTDIR)$(PREFIX)/bin/dmenu-run\ $(DESTDIR)$(PREFIX)/bin/dmenu-run-recent\ $(DESTDIR)$(PREFIX)/bin/dmenu-pass\ $(DESTDIR)$(PREFIX)/bin/dmenu-pinentry\ $(DESTDIR)$(PREFIX)/bin/stest\ $(DESTDIR)$(MANPREFIX)/man1/dmenu.1\ $(DESTDIR)$(MANPREFIX)/man1/stest.1
M README => README +8 -0
@@ 22,3 22,11 @@ Afterwards enter the following command to build and install dmenu Running dmenu ------------- See the man page for details. Customizations -------------- Patches: 1. https://tools.suckless.org/dmenu/patches/line-height/ 2. https://tools.suckless.org/dmenu/patches/center/ 3. https://tools.suckless.org/dmenu/patches/border/ 4. https://tools.suckless.org/dmenu/patches/password/
A config.h => config.h +28 -0
@@ 0,0 1,28 @@ /* See LICENSE file for copyright and license details. */ /* 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 const char *fonts[] = { "monospace:size=12:antialias=true:autohint=true", }; static const char *prompt = ">>"; /* -p option; prompt to the left of input field */ static const char *colors[SchemeLast][2] = { /* fg bg */ [SchemeNorm] = { "#bbbbbb", "#222222" }, [SchemeSel] = { "#eeeeee", "#005577" }, [SchemeOut] = { "#000000", "#00ffff" }, }; static unsigned int lines = 20; /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ static unsigned int lineheight = 24; /* -h option; minimum height of a menu line */ static int centered = 1; /* -c option; centers dmenu on screen */ static int min_width = 500; /* minimum width when centered */ static const unsigned int border_width = 4; /* * Characters not considered part of a word while deleting words * for example: " /?\"&[]" */ static const char worddelimiters[] = " ";
M config.mk => config.mk +5 -2
@@ 5,8 5,11 @@ VERSION = 5.2 PREFIX = /usr/local MANPREFIX = $(PREFIX)/share/man X11INC = /usr/X11R6/include X11LIB = /usr/X11R6/lib # X11INC = /usr/X11R6/include # X11LIB = /usr/X11R6/lib X11INC = /usr/include/X11 X11LIB = /usr/lib/X11 # Xinerama, comment if you don't want it XINERAMALIBS = -lXinerama
A dmenu-pass => dmenu-pass +45 -0
@@ 0,0 1,45 @@ #!/usr/bin/env bash # set -e set -o pipefail shopt -s nullglob globstar typeit=0 if [[ $1 == "--type" ]]; then typeit=1 shift fi if [[ -n $WAYLAND_DISPLAY ]]; then dmenu=dmenu-wl xdotool="ydotool type --file -" elif [[ -n $DISPLAY ]]; then dmenu=dmenu xdotool="xdotool type --clearmodifiers --file -" else echo "Error: No Wayland or X11 display detected" >&2 exit 1 fi prefix=${PASSWORD_STORE_DIR-~/.password-store} password_files=( "$prefix"/**/*.gpg ) password_files=( "${password_files[@]#"$prefix"/}" ) password_files=( "${password_files[@]%.gpg}" ) password=$(printf '%s\n' "${password_files[@]}" | "$dmenu" "$@") [[ -n $password ]] || exit if [[ $typeit -eq 0 ]]; then pass show -c "$password" 2>/dev/null else pass show "$password" | { IFS= read -r pass; printf %s "$pass"; } | $xdotool fi if [ "$?" -eq "0" ] then notify-send "Password store" "# Password $password copied for 45s." else notify-send "Password store" "# FAILED to copy password." fi
A dmenu-path => dmenu-path +12 -0
@@ 0,0 1,12 @@ #!/bin/sh # # dmenu-path: Override dmenu_path sorting results by atime. # # By default, dmenu-path sorts executables alphabetically. It seems to make # more sense to sort them by atime in an effort to reduce the number of # keystrokes needed to start a program. echo $PATH | tr ':' '\n' | uniq | sed 's#$#/#' | # List directories in $PATH xargs ls -lu --time-style=+%s | # Add atime epoch awk '/^(-|l)/ { print $6, $7 }' | # Only print timestamp and name sort -rn | cut -d' ' -f 2 | uniq
A dmenu-pinentry => dmenu-pinentry +12 -0
@@ 0,0 1,12 @@ #!/bin/bash printf "OK Pleased to meet you\n" while read stdin; do case $stdin in *BYE*) break ;; *SETDESC*) KEYNAME=${stdin#*:%0A%22}; KEYNAME=${KEYNAME%\%22\%0A*}; KEYID=${stdin#*ID }; KEYID=${KEYID%,*}; printf "OK\n" ;; *GETPIN*) printf "D $(dmenu -P -p "PIN:")\nOK\n" ;; *) printf "OK\n" esac done
A dmenu-run => dmenu-run +2 -0
A dmenu-run-recent => dmenu-run-recent +21 -0
@@ 0,0 1,21 @@ #!/usr/bin/env bash TERMINAL="st -e" CACHE_DIR=${XDG_CACHE_HOME:-"$HOME/.cache/dmenu"} CACHE="$CACHE_DIR/recent" touch "$CACHE" MOST_USED=$(sort "$CACHE" | grep -v "^$" | sort | uniq -c | awk '{print $2}') RUN=$((echo "$MOST_USED"; dmenu-path | grep -vxF "$MOST_USED") | dmenu -i "$@") if [ "$RUN" == "" ]; then exit 0; fi (echo "$RUN"; head -n 99 "$CACHE") > "$CACHE.$$" mv "$CACHE.$$" "$CACHE" case "$RUN" in *\;) exec $(echo $TERMINAL "$RUN" | sed -e 's/;$//') ;; *) exec "$RUN" ;; esac
M dmenu.1 => dmenu.1 +7 -1
@@ 3,7 3,7 @@ dmenu \- dynamic menu .SH SYNOPSIS .B dmenu .RB [ \-bfiv ] .RB [ \-bfivP ] .RB [ \-l .IR lines ] @@ .RB [ \-m 47,9 47,15 @@ is faster, but will lock up X until stdin reaches end\-of\-file. .B \-i dmenu matches menu items case insensitively. .TP .B \-P dmenu will not directly display the keyboard input, but instead replace it with dots. All data from stdin will be ignored. .TP .BI \-l " lines" dmenu lists items vertically, with the given number of lines. .TP .BI \-h " height" dmenu uses a menu line of at least 'height' pixels tall, but no less than 8. .TP .BI \-m " monitor" dmenu is displayed on the monitor number supplied. Monitor numbers are starting from 0.
M dmenu.c => dmenu.c +58 -15
@@ 21,7 21,7 @@ /* 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))) && 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) @@ 37,7 37,7 @@ struct item { static char text[BUFSIZ] = ""; static char *embed; static int bh, mw, mh; static int inputw = 0, promptw; static int inputw = 0, promptw, passwd = 0; static int lrpad; /* sum of left and right padding */ static size_t cursor; @@ static struct item *items = NULL; 96,6 96,15 @@ calcoffsets(void) break; } static int max_textw(void) { int len = 0; for (struct item *item = items; item && item->text; item++) len = MAX(TEXTW(item->text), len); return len; } static void cleanup(void) @@ { 148,7 157,8 @@ drawmenu(void) { unsigned int curpos; struct item *item; int x = 0, y = 0, w; int x = 0, y = 0, fh = drw->fonts->h, w; char *censort; drw_setscheme(drw, scheme[SchemeNorm]); @@ drw_rect(drw, 0, 0, mw, mh, 1, 1); 160,12 170,17 @@ drawmenu(void) /* draw input field */ w = (lines > 0 || !matches) ? mw - x : inputw; drw_setscheme(drw, scheme[SchemeNorm]); drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0); if (passwd) { censort = ecalloc(1, sizeof(text)); memset(censort, '*', strlen(text)); drw_text(drw, x, 0, w, bh, lrpad / 2, censort, 0); free(censort); } else drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0); 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); drw_rect(drw, x + curpos, 2 + (bh-fh)/2, 2, fh - 4, 1, 0); } @@ if (lines > 0) { 552,6 567,10 @@ readstdin(void) char *line = NULL; size_t i, junk, itemsiz = 0; ssize_t len; if (passwd) { inputw = lines = 0; return; } /* read each line from stdin and add it to the item list */ @@ for (i = 0; (len = getline(&line, &junk, stdin)) != -1; i++) { 634,8 653,10 @@ setup(void) /* calculate menu geometry */ bh = drw->fonts->h + 2; bh = MAX(bh,lineheight); /* make a menu line AT LEAST 'lineheight' tall */ lines = MAX(lines, 0); mh = (lines + 1) * bh; promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; #ifdef XINERAMA i = 0; @@ if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { 662,9 683,16 @@ setup(void) if (INTERSECT(x, y, 1, 1, info[i]) != 0) break; x = info[i].x_org; y = info[i].y_org + (topbar ? 0 : info[i].height - mh); mw = info[i].width; if (centered) { mw = MIN(MAX(max_textw() + promptw, min_width), info[i].width); x = info[i].x_org + ((info[i].width - mw) / 2); y = info[i].y_org + ((info[i].height - mh) / 2); } else { x = info[i].x_org; y = info[i].y_org + (topbar ? 0 : info[i].height - mh); mw = info[i].width; } XFree(info); } else @@ #endif 672,11 700,17 @@ setup(void) if (!XGetWindowAttributes(dpy, parentwin, &wa)) die("could not get embedding window attributes: 0x%lx", parentwin); x = 0; y = topbar ? 0 : wa.height - mh; mw = wa.width; if (centered) { mw = MIN(MAX(max_textw() + promptw, min_width), wa.width); x = (wa.width - mw) / 2; y = (wa.height - mh) / 2; } else { x = 0; y = topbar ? 0 : wa.height - mh; mw = wa.width; } } promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; inputw = mw / 3; /* input width: ~33% of monitor width */ match(); @@ 684,9 718,10 @@ setup(void) swa.override_redirect = True; swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0, win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width, CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel); XSetClassHint(dpy, win, &ch); @@ 714,7 749,7 @@ setup(void) static void usage(void) { die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" die("usage: dmenu [-bfivP] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]"); } @@ 733,10 768,14 @@ main(int argc, char *argv[]) topbar = 0; else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ fast = 1; else if (!strcmp(argv[i], "-c")) /* centers dmenu on screen */ centered = 1; else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ fstrncmp = strncasecmp; fstrstr = cistrstr; } else if (i + 1 == argc) } else if (!strcmp(argv[i], "-P")) /* is the input a password */ passwd = 1; else if (i + 1 == argc) usage(); /* these options take one argument */ @@ else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */ 747,6 786,10 @@ main(int argc, char *argv[]) prompt = argv[++i]; else if (!strcmp(argv[i], "-fn")) /* font or font set */ fonts[0] = argv[++i]; else if(!strcmp(argv[i], "-h")) { /* minimum height of one menu line */ lineheight = atoi(argv[++i]); lineheight = MAX(lineheight,8); /* reasonable default in case of value too small/negative */ } else if (!strcmp(argv[i], "-nb")) /* normal background color */ colors[SchemeNorm][ColBg] = argv[++i]; else if (!strcmp(argv[i], "-nf")) /* normal foreground color */
D dmenu_path => dmenu_path +0 -13
@@ 1,13 0,0 @@ #!/bin/sh 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" else cat "$cache" fi
D dmenu_run => dmenu_run +0 -2