diff options
| author | zachir <zachir@librem.one> | 2023-02-21 14:30:34 -0600 | 
|---|---|---|
| committer | zachir <zachir@librem.one> | 2023-02-21 14:30:34 -0600 | 
| commit | ee4eee0e05b567fe72f94eabcec9656a096625bc (patch) | |
| tree | af857dbbee2fae2f7ff2674750c0871b24c753b5 | |
| parent | 0e8723fdc24c099954f6356f22d1a1df47eddb20 (diff) | |
| parent | 96e4a549ce8b3da7d5d339a94487bb2849520ae7 (diff) | |
merge master to version 5.25.2
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | README.md | 3 | ||||
| -rw-r--r-- | config.def.h | 14 | ||||
| -rw-r--r-- | config.h | 34 | ||||
| -rw-r--r-- | config.mk | 5 | ||||
| -rw-r--r-- | dmenu-5.1.diff | 3199 | ||||
| -rw-r--r-- | dmenu.1 | 5 | ||||
| -rw-r--r-- | dmenu.c | 207 | ||||
| -rw-r--r-- | drw.c | 102 | ||||
| -rw-r--r-- | drw.h | 1 | ||||
| -rw-r--r-- | patches/dmenu-center-5.2.diff (renamed from patches/dmenu-center-20200111-8cd37e1.diff) | 34 | ||||
| -rw-r--r-- | patches/dmenu-fuzzyhighlight-caseinsensitive-4.9.diff (renamed from patches/dmenu-fuzzyhighlight-4.9.diff) | 60 | ||||
| -rw-r--r-- | patches/dmenu-lineheight-5.2.diff (renamed from patches/dmenu-lineheight-5.0.diff) | 22 | ||||
| -rw-r--r-- | patches/dmenu-mousesupport-5.2.diff (renamed from patches/dmenu-mousesupport-5.1.diff) | 8 | ||||
| -rw-r--r-- | patches/dmenu-mousesupporthoverbgcol-5.0.diff | 184 | ||||
| -rw-r--r-- | patches/dmenu-separator-5.2.patch (renamed from patches/dmenu-separator-20210904-d78ff08.diff) | 76 | ||||
| -rw-r--r-- | util.c | 23 | 
17 files changed, 285 insertions, 3693 deletions
@@ -1,3 +1,4 @@  *.o  dmenu  stest +config.h diff --git a/README.md b/README.md deleted file mode 100644 index 743aa3f..0000000 --- a/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# dmenu-zir - -My personal fork of dmenu
\ No newline at end of file diff --git a/config.def.h b/config.def.h index 3fb3def..47c1e3e 100644 --- a/config.def.h +++ b/config.def.h @@ -2,15 +2,15 @@  /* Default settings; can be overriden by command line. */  static int topbar = 1;                      /* -b  option; if 0, dmenu appears at bottom     */ -static int centered = 0;                    /* -c  option; centers dmenu on screen */ -static int min_width = 500;                 /* minimum width when centered */ -static int fuzzy = 0;                       /* -F  option; if 0, dmenu doesn't use fuzzy matching     */ +static int fuzzy = 0;                       /* -F option; if 0, dmenu doesn't use fuzzy matching    */ +static int centered = 0;                    /* -c option; centers dmenu on screen */ +static int min_width = 500;                    /* minimum width when centered */  /* -fn option overrides fonts[0]; default X11 font or font set */ -static char *fonts[] = { -	"monospace:size=10" +static const char *fonts[] = { +	"mononoki Nerd Font Mono:size=12"  };  static const char *prompt      = NULL;      /* -p  option; prompt to the left of input field */ -static char *colors[SchemeLast][2] = { +static const char *colors[SchemeLast][2] = {  	/*     fg         bg       */  	[SchemeNorm] = { "#bbbbbb", "#222222" },  	[SchemeSel] = { "#eeeeee", "#005577" }, @@ -21,7 +21,7 @@ static char *colors[SchemeLast][2] = {  /* -l option; if nonzero, dmenu uses vertical list with given number of lines */  static unsigned int lines      = 0;  /* -h option; minimum height of a menu line */ -static unsigned int lineheight = 0; +static unsigned int lineheight = 24;  static unsigned int min_lineheight = 8;  /* diff --git a/config.h b/config.h deleted file mode 100644 index 19c566f..0000000 --- a/config.h +++ /dev/null @@ -1,34 +0,0 @@ -/* 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     */ -static int centered = 0;                    /* -c  option; centers dmenu on screen */ -static int min_width = 500;                 /* minimum width when centered */ -static int fuzzy = 0;                       /* -F  option; if 0, dmenu doesn't use fuzzy matching     */ -/* -fn option overrides fonts[0]; default X11 font or font set */ -static char *fonts[] = { -	"monospace:size=10" -}; -static const char *prompt      = NULL;      /* -p  option; prompt to the left of input field */ -static char *colors[SchemeLast][2] = { -	/*     fg         bg       */ -	[SchemeNorm] = { "#bbbbbb", "#222222" }, -	[SchemeSel] = { "#eeeeee", "#005577" }, -	[SchemeSelHighlight] = { "#ffc978", "#005577" }, -	[SchemeNormHighlight] = { "#ffc978", "#222222" }, -	[SchemeOut] = { "#000000", "#00ffff" }, -}; -/* -l option; if nonzero, dmenu uses vertical list with given number of lines */ -static unsigned int lines      = 0; -/* -h option; minimum height of a menu line */ -static unsigned int lineheight = 24; -static unsigned int min_lineheight = 8; - -/* - * Characters not considered part of a word while deleting words - * for example: " /?\"&[]" - */ -static const char worddelimiters[] = " "; - -/* Size of the window border */ -static unsigned int border_width = 0; @@ -1,5 +1,5 @@  # dmenu version -VERSION = 5.1 +VERSION = 5.2  # paths  PREFIX = /usr/local @@ -17,6 +17,7 @@ FREETYPELIBS = -lfontconfig -lXft  FREETYPEINC = /usr/include/freetype2  # OpenBSD (uncomment)  #FREETYPEINC = $(X11INC)/freetype2 +#MANPREFIX = ${PREFIX}/man  # includes and libs  INCS = -I$(X11INC) -I$(FREETYPEINC) @@ -24,7 +25,7 @@ LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lm  # 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 -O3 -march=native $(INCS) $(CPPFLAGS) +CFLAGS   = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS)  LDFLAGS  = $(LIBS)  # compiler and linker diff --git a/dmenu-5.1.diff b/dmenu-5.1.diff deleted file mode 100644 index f062280..0000000 --- a/dmenu-5.1.diff +++ /dev/null @@ -1,3199 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 1edb647..3fb3def 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -2,22 +2,33 @@ - /* Default settings; can be overriden by command line. */ -  - static int topbar = 1;                      /* -b  option; if 0, dmenu appears at bottom     */ -+static int centered = 0;                    /* -c  option; centers dmenu on screen */ -+static int min_width = 500;                 /* minimum width when centered */ -+static int fuzzy = 0;                       /* -F  option; if 0, dmenu doesn't use fuzzy matching     */ - /* -fn option overrides fonts[0]; default X11 font or font set */ --static const char *fonts[] = { -+static char *fonts[] = { - 	"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 *colors[SchemeLast][2] = { - 	/*     fg         bg       */ - 	[SchemeNorm] = { "#bbbbbb", "#222222" }, - 	[SchemeSel] = { "#eeeeee", "#005577" }, -+	[SchemeSelHighlight] = { "#ffc978", "#005577" }, -+	[SchemeNormHighlight] = { "#ffc978", "#222222" }, - 	[SchemeOut] = { "#000000", "#00ffff" }, - }; - /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ - static unsigned int lines      = 0; -+/* -h option; minimum height of a menu line */ -+static unsigned int lineheight = 0; -+static unsigned int min_lineheight = 8; -  - /* -  * Characters not considered part of a word while deleting words -  * for example: " /?\"&[]" -  */ - static const char worddelimiters[] = " "; -+ -+/* Size of the window border */ -+static unsigned int border_width = 0; -diff --git a/config.mk b/config.mk -index 0df3fc8..3423b6a 100644 ---- a/config.mk -+++ b/config.mk -@@ -20,7 +20,7 @@ FREETYPEINC = /usr/include/freetype2 -  - # includes and libs - INCS = -I$(X11INC) -I$(FREETYPEINC) --LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -+LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lm -  - # flags - CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) -diff --git a/dmenu.1 b/dmenu.1 -index 323f93c..1602793 100644 ---- a/dmenu.1 -+++ b/dmenu.1 -@@ -3,9 +3,11 @@ - dmenu \- dynamic menu - .SH SYNOPSIS - .B dmenu --.RB [ \-bfiv ] -+.RB [ \-bFfirvP ] - .RB [ \-l - .IR lines ] -+.RB [ \-h -+.IR height ] - .RB [ \-m - .IR monitor ] - .RB [ \-p -@@ -20,8 +22,20 @@ dmenu \- dynamic menu - .IR color ] - .RB [ \-sf - .IR color ] -+.RB [ \-nhb -+.IR color ] -+.RB [ \-nhf -+.IR color ] -+.RB [ \-shb -+.IR color ] -+.RB [ \-shf -+.IR color ] - .RB [ \-w - .IR windowid ] -+.RB [ \-d -+.IR separator ] -+.RB [ \-D -+.IR separator ] - .P - .BR dmenu_run " ..." - .SH DESCRIPTION -@@ -40,6 +54,12 @@ which lists programs in the user's $PATH and runs the result in their $SHELL. - .B \-b - dmenu appears at the bottom of the screen. - .TP -+.B \-c -+dmenu appears centered on the screen. -+.TP -+.B \-F -+dmenu uses fuzzy matching -+.TP - .B \-f - 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. -@@ -47,9 +67,18 @@ 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 -+.B \-r -+dmenu will reject any input which would result in no matching option left. -+.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. -@@ -75,11 +104,31 @@ defines the selected background color. - .BI \-sf " color" - defines the selected foreground color. - .TP -+.BI \-nhb " color" -+defines the normal highlight background color. -+.TP -+.BI \-nhf " color" -+defines the normal highlight foreground color. -+.TP -+.BI \-shb " color" -+defines the selected highlight background color. -+.TP -+.BI \-shf " color" -+defines the selected highlight foreground color. -+.TP - .B \-v - prints version information to stdout, then exits. - .TP - .BI \-w " windowid" - embed into windowid. -+.TP -+.BI \-d " separator" -+separate the input into two halves on the first occurrence of the given charcter. -+Display only the first half in dmenu and print the second half to stdout upon selection. -+Appending '|' to the separator reverses the display/printing order. -+.TP -+.BI \-D " separator" -+same as \-d but separate based on the last occurrence. - .SH USAGE - dmenu is completely controlled by the keyboard.  Items are selected using the - arrow keys, page up, page down, home, and end. -diff --git a/dmenu.c b/dmenu.c -index d95e6c6..d304e3a 100644 ---- a/dmenu.c -+++ b/dmenu.c -@@ -1,6 +1,7 @@ - /* See LICENSE file for copyright and license details. */ - #include <ctype.h> - #include <locale.h> -+#include <math.h> - #include <stdio.h> - #include <stdlib.h> - #include <string.h> -@@ -15,6 +16,7 @@ - #include <X11/extensions/Xinerama.h> - #endif - #include <X11/Xft/Xft.h> -+#include <X11/Xresource.h> -  - #include "drw.h" - #include "util.h" -@@ -22,23 +24,33 @@ - /* 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 BOOL_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 */ --enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ -+enum { SchemeNorm, SchemeSel, SchemeNormHighlight, SchemeSelHighlight, -+       SchemeOut, SchemeLast }; /* color schemes */ -+ -  - struct item { - 	char *text; -+        char *text_output; - 	struct item *left, *right; - 	int out; -+	double distance; - }; -  - static char text[BUFSIZ] = ""; - static char *embed; -+static char separator; -+static int separator_greedy; -+static int separator_reverse; - 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 int reject_no_match = 0; - static size_t cursor; - static struct item *items = NULL; - static struct item *matches, *matchend; -@@ -53,6 +65,10 @@ static XIC xic; - static Drw *drw; - static Clr *scheme[SchemeLast]; -  -+/* Temporary arrays to allow overriding xresources values */ -+static char *colortemp[4]; -+static char *tempfonts; -+ - #include "config.h" -  - static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; -@@ -89,6 +105,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) - { -@@ -120,9 +145,49 @@ cistrstr(const char *h, const char *n) - 	return NULL; - } -  -+static void -+drawhighlights(struct item *item, int x, int y, int maxw) -+{ -+	int i, indent; -+	char *highlight; -+	char c; -+ -+	if (!(strlen(item->text) && strlen(text))) -+		return; -+ -+	drw_setscheme(drw, scheme[item == sel -+	                   ? SchemeSelHighlight -+	                   : SchemeNormHighlight]); -+	for (i = 0, highlight = item->text; *highlight && text[i];) { -+		if (!fstrncmp(&(*highlight), &text[i], 1)) { -+			/* get indentation */ -+			c = *highlight; -+			*highlight = '\0'; -+			indent = TEXTW(item->text); -+			*highlight = c; -+ -+			/* highlight character */ -+			c = highlight[1]; -+			highlight[1] = '\0'; -+			drw_text( -+				drw, -+				x + indent - (lrpad / 2), -+				y, -+				MIN(maxw - indent, TEXTW(highlight) - lrpad), -+				bh, 0, highlight, 0 -+			); -+			highlight[1] = c; -+			i++; -+		} -+		highlight++; -+	} -+} -+ -+ - static int - drawitem(struct item *item, int x, int y, int w) - { -+	int r; - 	if (item == sel) - 		drw_setscheme(drw, scheme[SchemeSel]); - 	else if (item->out) -@@ -130,7 +195,9 @@ drawitem(struct item *item, int x, int y, int w) - 	else - 		drw_setscheme(drw, scheme[SchemeNorm]); -  --	return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); -+	r = drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); -+	drawhighlights(item, x, y, w); -+	return r; - } -  - static void -@@ -138,7 +205,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); -@@ -150,12 +218,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) { -@@ -217,9 +290,94 @@ grabkeyboard(void) - 	die("cannot grab keyboard"); - } -  -+int -+compare_distance(const void *a, const void *b) -+{ -+	struct item *da = *(struct item **) a; -+	struct item *db = *(struct item **) b; -+ -+	if (!db) -+		return 1; -+	if (!da) -+		return -1; -+ -+	return da->distance == db->distance ? 0 : da->distance < db->distance ? -1 : 1; -+} -+ -+void -+fuzzymatch(void) -+{ -+	/* bang - we have so much memory */ -+	struct item *it; -+	struct item **fuzzymatches = NULL; -+	char c; -+	int number_of_matches = 0, i, pidx, sidx, eidx; -+	int text_len = strlen(text), itext_len; -+ -+	matches = matchend = NULL; -+ -+	/* walk through all items */ -+	for (it = items; it && it->text; it++) { -+		if (text_len) { -+			itext_len = strlen(it->text); -+			pidx = 0; /* pointer */ -+			sidx = eidx = -1; /* start of match, end of match */ -+			/* walk through item text */ -+			for (i = 0; i < itext_len && (c = it->text[i]); i++) { -+				/* fuzzy match pattern */ -+				if (!fstrncmp(&text[pidx], &c, 1)) { -+					if(sidx == -1) -+						sidx = i; -+					pidx++; -+					if (pidx == text_len) { -+						eidx = i; -+						break; -+					} -+				} -+			} -+			/* build list of matches */ -+			if (eidx != -1) { -+				/* compute distance */ -+				/* add penalty if match starts late (log(sidx+2)) -+				 * add penalty for long a match without many matching characters */ -+				it->distance = log(sidx + 2) + (double)(eidx - sidx - text_len); -+				/* fprintf(stderr, "distance %s %f\n", it->text, it->distance); */ -+				appenditem(it, &matches, &matchend); -+				number_of_matches++; -+			} -+		} else { -+			appenditem(it, &matches, &matchend); -+		} -+	} -+ -+	if (number_of_matches) { -+		/* initialize array with matches */ -+		if (!(fuzzymatches = realloc(fuzzymatches, number_of_matches * sizeof(struct item*)))) -+			die("cannot realloc %u bytes:", number_of_matches * sizeof(struct item*)); -+		for (i = 0, it = matches; it && i < number_of_matches; i++, it = it->right) { -+			fuzzymatches[i] = it; -+		} -+		/* sort matches according to distance */ -+		qsort(fuzzymatches, number_of_matches, sizeof(struct item*), compare_distance); -+		/* rebuild list of matches */ -+		matches = matchend = NULL; -+		for (i = 0, it = fuzzymatches[i];  i < number_of_matches && it && \ -+				it->text; i++, it = fuzzymatches[i]) { -+			appenditem(it, &matches, &matchend); -+		} -+		free(fuzzymatches); -+	} -+	curr = sel = matches; -+	calcoffsets(); -+} -+ - static void - match(void) - { -+	if (fuzzy) { -+		fuzzymatch(); -+		return; -+	} - 	static char **tokv = NULL; - 	static int tokn = 0; -  -@@ -276,12 +434,26 @@ insert(const char *str, ssize_t n) - { - 	if (strlen(text) + n > sizeof text - 1) - 		return; -+ -+	static char last[BUFSIZ] = ""; -+	if(reject_no_match) { -+		/* store last text value in case we need to revert it */ -+		memcpy(last, text, BUFSIZ); -+	} -+ - 	/* move existing text out of the way, insert new text, and update cursor */ - 	memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0)); - 	if (n > 0) - 		memcpy(&text[cursor], str, n); - 	cursor += n; - 	match(); -+ -+	if(!matches && reject_no_match) { -+		/* revert to last text value if theres no match */ -+		memcpy(text, last, BUFSIZ); -+		cursor -= n; -+		match(); -+	} - } -  - static size_t -@@ -480,7 +652,7 @@ insert: - 		break; - 	case XK_Return: - 	case XK_KP_Enter: --		puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); -+		puts((sel && !(ev->state & ShiftMask)) ? sel->text_output : text); - 		if (!(ev->state & ControlMask)) { - 			cleanup(); - 			exit(0); -@@ -518,6 +690,156 @@ draw: - 	drawmenu(); - } -  -+static void -+buttonpress(XEvent *e) -+{ -+	struct item *item; -+	XButtonPressedEvent *ev = &e->xbutton; -+	int x = 0, y = 0, h = bh, w; -+ -+	if (ev->window != win) -+		return; -+ -+	/* right-click: exit */ -+	if (ev->button == Button3) -+		exit(1); -+ -+	if (prompt && *prompt) -+		x += promptw; -+ -+	/* input field */ -+	w = (lines > 0 || !matches) ? mw - x : inputw; -+ -+	/* left-click on input: clear input, -+	 * NOTE: if there is no left-arrow the space for < is reserved so -+	 *       add that to the input width */ -+	if (ev->button == Button1 && -+	   ((lines <= 0 && ev->x >= 0 && ev->x <= x + w + -+	   ((!prev || !curr->left) ? TEXTW("<") : 0)) || -+	   (lines > 0 && ev->y >= y && ev->y <= y + h))) { -+		insert(NULL, -cursor); -+		drawmenu(); -+		return; -+	} -+	/* middle-mouse click: paste selection */ -+	if (ev->button == Button2) { -+		XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, -+		                  utf8, utf8, win, CurrentTime); -+		drawmenu(); -+		return; -+	} -+	/* scroll up */ -+	if (ev->button == Button4 && prev) { -+		sel = curr = prev; -+		calcoffsets(); -+		drawmenu(); -+		return; -+	} -+	/* scroll down */ -+	if (ev->button == Button5 && next) { -+		sel = curr = next; -+		calcoffsets(); -+		drawmenu(); -+		return; -+	} -+	if (ev->button != Button1) -+		return; -+	/* disabled below, needs to be fixed */ -+	/* -+	if (ev->state & ~ControlMask) -+		return; -+	*/ -+	if (lines > 0) { -+		/* vertical list: (ctrl)left-click on item */ -+		w = mw - x; -+		for (item = curr; item != next; item = item->right) { -+			y += h; -+			if (ev->y >= y && ev->y <= (y + h)) { -+				puts(item->text); -+				if (!(ev->state & ControlMask)) -+					exit(0); -+				sel = item; -+				if (sel) { -+					sel->out = 1; -+					drawmenu(); -+				} -+				return; -+			} -+		} -+	} else if (matches) { -+		/* left-click on left arrow */ -+		x += inputw; -+		w = TEXTW("<"); -+		if (prev && curr->left) { -+			if (ev->x >= x && ev->x <= x + w) { -+				sel = curr = prev; -+				calcoffsets(); -+				drawmenu(); -+				return; -+			} -+		} -+		/* horizontal list: (ctrl)left-click on item */ -+		for (item = curr; item != next; item = item->right) { -+			x += w; -+			w = MIN(TEXTW(item->text), mw - x - TEXTW(">")); -+			if (ev->x >= x && ev->x <= x + w) { -+				puts(item->text); -+				if (!(ev->state & ControlMask)) -+					exit(0); -+				sel = item; -+				if (sel) { -+					sel->out = 1; -+					drawmenu(); -+				} -+				return; -+			} -+		} -+		/* left-click on right arrow */ -+		w = TEXTW(">"); -+		x = mw - w; -+		if (next && ev->x >= x && ev->x <= x + w) { -+			sel = curr = next; -+			calcoffsets(); -+			drawmenu(); -+			return; -+		} -+	} -+} -+ -+static void -+mousemove(XEvent *e) -+{ -+	struct item *item; -+	XPointerMovedEvent *ev = &e->xmotion; -+	int x = 0, y = 0, h = bh, w; -+ -+	if (lines > 0) { -+		w = mw - x; -+		for (item = curr; item != next; item = item->right) { -+			y += h; -+			if (ev->y >= y && ev->y <= (y + h)) { -+				sel = item; -+				calcoffsets(); -+				drawmenu(); -+				return; -+			} -+		} -+	} else if (matches) { -+		x += inputw; -+		w = TEXTW("<"); -+		for (item = curr; item != next; item = item->right) { -+			x += w; -+			w = MIN(TEXTW(item->text), mw - x - TEXTW(">")); -+			if (ev->x >= x && ev->x <= x + w) { -+				sel = item; -+				calcoffsets(); -+				drawmenu(); -+				return; -+			} -+		} -+	} -+} -+ - static void - paste(void) - { -@@ -542,6 +864,11 @@ readstdin(void) - 	char buf[sizeof text], *p; - 	size_t i, imax = 0, size = 0; - 	unsigned int tmpmax = 0; -+	if(passwd){ -+    	inputw = lines = 0; -+    	return; -+  	} -+ -  - 	/* read each line from stdin and add it to the item list */ - 	for (i = 0; fgets(buf, sizeof buf, stdin); i++) { -@@ -552,6 +879,18 @@ readstdin(void) - 			*p = '\0'; - 		if (!(items[i].text = strdup(buf))) - 			die("cannot strdup %u bytes:", strlen(buf) + 1); -+		if (separator && (p = separator_greedy ? -+		    strrchr(items[i].text, separator) : strchr(items[i].text, separator))) { -+			*p = '\0'; -+			items[i].text_output = ++p; -+		} else { -+			items[i].text_output = items[i].text; -+		} -+		if (separator_reverse) { -+			p = items[i].text; -+			items[i].text = items[i].text_output; -+			items[i].text_output = p; -+		} - 		items[i].out = 0; - 		drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL); - 		if (tmpmax > inputw) { -@@ -579,6 +918,12 @@ run(void) - 				break; - 			cleanup(); - 			exit(1); -+		case ButtonPress: -+			buttonpress(&ev); -+			break; -+                case MotionNotify: -+                        mousemove(&ev); -+                        break; - 		case Expose: - 			if (ev.xexpose.count == 0) - 				drw_map(drw, win, 0, 0, mw, mh); -@@ -619,16 +964,23 @@ setup(void) - 	int a, di, n, area = 0; - #endif - 	/* init appearance */ --	for (j = 0; j < SchemeLast; j++) --		scheme[j] = drw_scm_create(drw, colors[j], 2); -+	for (j = 0; j < SchemeLast; j++) { -+		scheme[j] = drw_scm_create(drw, (const char**)colors[j], 2); -+	} -+	for (j = 0; j < SchemeOut; ++j) { -+		for (i = 0; i < 2; ++i) -+			free(colors[j][i]); -+	} -  - 	clip = XInternAtom(dpy, "CLIPBOARD",   False); - 	utf8 = XInternAtom(dpy, "UTF8_STRING", False); -  - 	/* 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))) { -@@ -652,12 +1004,19 @@ setup(void) - 		/* no focused window is on screen, so use pointer location instead */ - 		if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) - 			for (i = 0; i < n; i++) --				if (INTERSECT(x, y, 1, 1, info[i])) -+				if (BOOL_INTERSECT(x, y, 1, 1, info[i])) - 					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 -@@ -665,21 +1024,30 @@ 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 = MIN(inputw, mw/3); - 	match(); -  - 	/* create menu window */ - 	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, -+	swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask | -+                         ButtonPressMask | PointerMotionMask; -+	win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width, - 	                    CopyFromParent, CopyFromParent, CopyFromParent, - 	                    CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); -+	if (border_width) -+		XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel); - 	XSetClassHint(dpy, win, &ch); -  -  -@@ -707,11 +1075,64 @@ setup(void) - static void - usage(void) - { --	fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" --	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); -+	fputs("usage: dmenu [-bfirvP] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" -+	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-bw width]\n" -+	      "             [-nhb color] [-nhf color] [-shb color] [-shf color] [-w windowid]\n" -+              "             [-d separator] [-D separator]\n", stderr); - 	exit(1); - } -  -+void -+readxresources(void) { -+	XrmInitialize(); -+ -+	char* xrm; -+	if ((xrm = XResourceManagerString(drw->dpy))) { -+		char *type; -+		XrmDatabase xdb = XrmGetStringDatabase(xrm); -+		XrmValue xval; -+ -+		if (XrmGetResource(xdb, "dmenu.font", "*", &type, &xval)) -+			fonts[0] = strdup(xval.addr); -+		else -+			fonts[0] = strdup(fonts[0]); -+		if (XrmGetResource(xdb, "dmenu.background", "*", &type, &xval)) -+			colors[SchemeNorm][ColBg] = strdup(xval.addr); -+		else -+			colors[SchemeNorm][ColBg] = strdup(colors[SchemeNorm][ColBg]); -+		if (XrmGetResource(xdb, "dmenu.foreground", "*", &type, &xval)) -+			colors[SchemeNorm][ColFg] = strdup(xval.addr); -+		else -+			colors[SchemeNorm][ColFg] = strdup(colors[SchemeNorm][ColFg]); -+		if (XrmGetResource(xdb, "dmenu.selbackground", "*", &type, &xval)) -+			colors[SchemeSel][ColBg] = strdup(xval.addr); -+		else -+			colors[SchemeSel][ColBg] = strdup(colors[SchemeSel][ColBg]); -+		if (XrmGetResource(xdb, "dmenu.selforeground", "*", &type, &xval)) -+			colors[SchemeSel][ColFg] = strdup(xval.addr); -+		else -+			colors[SchemeSel][ColFg] = strdup(colors[SchemeSel][ColFg]); -+		if (XrmGetResource(xdb, "dmenu.selhibackground", "*", &type, &xval)) -+			colors[SchemeSelHighlight][ColBg] = strdup(xval.addr); -+		else -+			colors[SchemeSelHighlight][ColBg] = strdup(colors[SchemeSel][ColBg]); -+		if (XrmGetResource(xdb, "dmenu.selhiforeground", "*", &type, &xval)) -+			colors[SchemeSelHighlight][ColFg] = strdup(xval.addr); -+		else -+			colors[SchemeSelHighlight][ColFg] = strdup(colors[SchemeSel][ColFg]); -+		if (XrmGetResource(xdb, "dmenu.hibackground", "*", &type, &xval)) -+			colors[SchemeNormHighlight][ColBg] = strdup(xval.addr); -+		else -+			colors[SchemeNormHighlight][ColBg] = strdup(colors[SchemeNorm][ColBg]); -+		if (XrmGetResource(xdb, "dmenu.hiforeground", "*", &type, &xval)) -+			colors[SchemeNormHighlight][ColFg] = strdup(xval.addr); -+		else -+			colors[SchemeNormHighlight][ColFg] = strdup(colors[SchemeNorm][ColFg]); -+ -+		XrmDestroyDatabase(xdb); -+	} -+} -+ - int - main(int argc, char *argv[]) - { -@@ -727,30 +1148,56 @@ 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], "-F"))   /* grabs keyboard before reading stdin */ -+			fuzzy = 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 (!strcmp(argv[i], "-r")) /* reject input which results in no match */ -+                        reject_no_match = 1; -+		else if (i + 1 == argc) - 			usage(); - 		/* these options take one argument */ - 		else if (!strcmp(argv[i], "-l"))   /* number of lines in vertical list */ - 			lines = atoi(argv[++i]); -+		else if (!strcmp(argv[i], "-h")) { /* minimum height of one menu line */ -+			lineheight = atoi(argv[++i]); -+			lineheight = MAX(lineheight, min_lineheight); -+		} - 		else if (!strcmp(argv[i], "-m")) - 			mon = atoi(argv[++i]); - 		else if (!strcmp(argv[i], "-p"))   /* adds prompt to left of input field */ - 			prompt = argv[++i]; - 		else if (!strcmp(argv[i], "-fn"))  /* font or font set */ --			fonts[0] = argv[++i]; -+			tempfonts = argv[++i]; - 		else if (!strcmp(argv[i], "-nb"))  /* normal background color */ --			colors[SchemeNorm][ColBg] = argv[++i]; -+			colortemp[0] = argv[++i]; - 		else if (!strcmp(argv[i], "-nf"))  /* normal foreground color */ --			colors[SchemeNorm][ColFg] = argv[++i]; -+			colortemp[1] = argv[++i]; - 		else if (!strcmp(argv[i], "-sb"))  /* selected background color */ --			colors[SchemeSel][ColBg] = argv[++i]; -+			colortemp[2] = argv[++i]; - 		else if (!strcmp(argv[i], "-sf"))  /* selected foreground color */ --			colors[SchemeSel][ColFg] = argv[++i]; -+			colortemp[3] = argv[++i]; -+                else if (!strcmp(argv[i], "-nhb")) /* normal hi background color */ -+                        colors[SchemeNormHighlight][ColBg] = argv[++i]; -+                else if (!strcmp(argv[i], "-nhf")) /* normal hi foreground color */ -+                        colors[SchemeNormHighlight][ColFg] = argv[++i]; -+                else if (!strcmp(argv[i], "-shb")) /* selected hi background color */ -+                        colors[SchemeSelHighlight][ColBg] = argv[++i]; -+                else if (!strcmp(argv[i], "-shf")) /* selected hi foreground color */ -+                        colors[SchemeSelHighlight][ColFg] = argv[++i]; - 		else if (!strcmp(argv[i], "-w"))   /* embedding window id */ - 			embed = argv[++i]; -+		else if (!strcmp(argv[i], "-d") || /* field separator */ -+			(separator_greedy = !strcmp(argv[i], "-D"))) { -+                        separator = argv[++i][0]; -+                        separator_reverse = argv[i][1] == '|'; -+                } else if (!strcmp(argv[i], "-bw")) -+			border_width = atoi(argv[++i]); /* border width */ - 		else - 			usage(); -  -@@ -766,8 +1213,23 @@ main(int argc, char *argv[]) - 		die("could not get embedding window attributes: 0x%lx", - 		    parentwin); - 	drw = drw_create(dpy, screen, root, wa.width, wa.height); --	if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) -+	readxresources(); -+	/* Now we check whether to override xresources with commandline parameters */ -+	if ( tempfonts ) -+	   fonts[0] = strdup(tempfonts); -+	if ( colortemp[0]) -+	   colors[SchemeNorm][ColBg] = strdup(colortemp[0]); -+	if ( colortemp[1]) -+	   colors[SchemeNorm][ColFg] = strdup(colortemp[1]); -+	if ( colortemp[2]) -+	   colors[SchemeSel][ColBg]  = strdup(colortemp[2]); -+	if ( colortemp[3]) -+	   colors[SchemeSel][ColFg]  = strdup(colortemp[3]); -+ -+	if (!drw_fontset_create(drw, (const char**)fonts, LENGTH(fonts))) - 		die("no fonts could be loaded."); -+ -+	free(fonts[0]); - 	lrpad = drw->fonts->h; -  - #ifdef __OpenBSD__ -diff --git a/patches/dmenu-borderoption-20200217-bf60a1e.diff b/patches/dmenu-borderoption-20200217-bf60a1e.diff -new file mode 100644 -index 0000000..b9b5726 ---- /dev/null -+++ b/patches/dmenu-borderoption-20200217-bf60a1e.diff -@@ -0,0 +1,46 @@ -+From bf60a1eaf98c7aebae51021914e35bc73dd8c23e Mon Sep 17 00:00:00 2001 -+From: 0x1bi <ben@0x1bi.net> -+Date: Mon, 17 Feb 2020 11:02:35 -0500 -+Subject: [PATCH] added border with option -+ -+ -+diff --git a/config.def.h b/config.def.h -+index 1edb647..dd3eb31 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -21,3 +21,6 @@ static unsigned int lines      = 0; -+  * for example: " /?\"&[]" -+  */ -+ static const char worddelimiters[] = " "; -++ -++/* Size of the window border */ -++static unsigned int border_width = 0; -+diff --git a/dmenu.c b/dmenu.c -+index 65f25ce..f0c3c6f 100644 -+--- a/dmenu.c -++++ b/dmenu.c -+@@ -659,9 +659,11 @@ 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); -++	if (border_width) -++		XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel); -+ 	XSetClassHint(dpy, win, &ch); -+  -+  -+@@ -733,6 +735,8 @@ main(int argc, char *argv[]) -+ 			colors[SchemeSel][ColFg] = argv[++i]; -+ 		else if (!strcmp(argv[i], "-w"))   /* embedding window id */ -+ 			embed = argv[++i]; -++		else if (!strcmp(argv[i], "-bw")) -++			border_width = atoi(argv[++i]); /* border width */ -+ 		else -+ 			usage(); -+  -+--  -+2.24.1 -+ -diff --git a/patches/dmenu-center-20200111-8cd37e1.diff b/patches/dmenu-center-20200111-8cd37e1.diff -new file mode 100644 -index 0000000..af249a6 ---- /dev/null -+++ b/patches/dmenu-center-20200111-8cd37e1.diff -@@ -0,0 +1,120 @@ -+From 8cd37e1ab9e7cb025224aeb3543f1a5be8bceb93 Mon Sep 17 00:00:00 2001 -+From: Nihal Jere <nihal@nihaljere.xyz> -+Date: Sat, 11 Jan 2020 21:16:08 -0600 -+Subject: [PATCH] center patch now has adjustable minimum width -+ -+--- -+ config.def.h |  2 ++ -+ dmenu.1      |  3 +++ -+ dmenu.c      | 39 ++++++++++++++++++++++++++++++++------- -+ 3 files changed, 37 insertions(+), 7 deletions(-) -+ -+diff --git a/config.def.h b/config.def.h -+index 1edb647..88ef264 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -2,6 +2,8 @@ -+ /* Default settings; can be overriden by command line. */ -+  -+ static int topbar = 1;                      /* -b  option; if 0, dmenu appears at bottom     */ -++static int centered = 0;                    /* -c option; centers dmenu on screen */ -++static int min_width = 500;                    /* minimum width when centered */ -+ /* -fn option overrides fonts[0]; default X11 font or font set */ -+ static const char *fonts[] = { -+ 	"monospace:size=10" -+diff --git a/dmenu.1 b/dmenu.1 -+index 323f93c..c036baa 100644 -+--- a/dmenu.1 -++++ b/dmenu.1 -+@@ -40,6 +40,9 @@ which lists programs in the user's $PATH and runs the result in their $SHELL. -+ .B \-b -+ dmenu appears at the bottom of the screen. -+ .TP -++.B \-c -++dmenu appears centered on the screen. -++.TP -+ .B \-f -+ 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. -+diff --git a/dmenu.c b/dmenu.c -+index 65f25ce..041c7f8 100644 -+--- a/dmenu.c -++++ b/dmenu.c -+@@ -89,6 +89,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) -+ { -+@@ -611,6 +620,7 @@ setup(void) -+ 	bh = drw->fonts->h + 2; -+ 	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))) { -+@@ -637,9 +647,16 @@ setup(void) -+ 				if (INTERSECT(x, y, 1, 1, info[i])) -+ 					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 -+@@ -647,11 +664,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 = MIN(inputw, mw/3); -+ 	match(); -+  -+@@ -709,6 +732,8 @@ 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; -+--  -+2.24.1 -+ -diff --git a/patches/dmenu-fuzzyhighlight-4.9.diff b/patches/dmenu-fuzzyhighlight-4.9.diff -new file mode 100644 -index 0000000..58d5c6f ---- /dev/null -+++ b/patches/dmenu-fuzzyhighlight-4.9.diff -@@ -0,0 +1,152 @@ -+Author: Chris Noxz <chris@noxz.tech> -+note: This patch is meant to be used together with fuzzymatch -+ -+diff -upN dmenu-4.9/config.def.h dmenu-4.9-fuzzyhighlight/config.def.h -+--- dmenu-4.9/config.def.h	2019-02-02 13:55:02.000000000 +0100 -++++ dmenu-4.9-fuzzyhighlight/config.def.h	2020-04-04 10:26:36.990890854 +0200 -+@@ -11,6 +11,8 @@ static const char *colors[SchemeLast][2] -+ 	/*     fg         bg       */ -+ 	[SchemeNorm] = { "#bbbbbb", "#222222" }, -+ 	[SchemeSel] = { "#eeeeee", "#005577" }, -++	[SchemeSelHighlight] = { "#ffc978", "#005577" }, -++	[SchemeNormHighlight] = { "#ffc978", "#222222" }, -+ 	[SchemeOut] = { "#000000", "#00ffff" }, -+ }; -+ /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ -+diff -upN dmenu-4.9/dmenu.1 dmenu-4.9-fuzzyhighlight/dmenu.1 -+--- dmenu-4.9/dmenu.1	2019-02-02 13:55:02.000000000 +0100 -++++ dmenu-4.9-fuzzyhighlight/dmenu.1	2020-04-04 10:30:16.430054933 +0200 -+@@ -20,6 +20,14 @@ dmenu \- dynamic menu -+ .IR color ] -+ .RB [ \-sf -+ .IR color ] -++.RB [ \-nhb -++.IR color ] -++.RB [ \-nhf -++.IR color ] -++.RB [ \-shb -++.IR color ] -++.RB [ \-shf -++.IR color ] -+ .RB [ \-w -+ .IR windowid ] -+ .P -+@@ -75,6 +83,18 @@ defines the selected background color. -+ .BI \-sf " color" -+ defines the selected foreground color. -+ .TP -++.BI \-nhb " color" -++defines the normal highlight background color. -++.TP -++.BI \-nhf " color" -++defines the normal highlight foreground color. -++.TP -++.BI \-shb " color" -++defines the selected highlight background color. -++.TP -++.BI \-shf " color" -++defines the selected highlight foreground color. -++.TP -+ .B \-v -+ prints version information to stdout, then exits. -+ .TP -+diff -upN dmenu-4.9/dmenu.c dmenu-4.9-fuzzyhighlight/dmenu.c -+--- dmenu-4.9/dmenu.c	2019-02-02 13:55:02.000000000 +0100 -++++ dmenu-4.9-fuzzyhighlight/dmenu.c	2020-04-04 10:27:43.888026309 +0200 -+@@ -26,7 +26,9 @@ -+ #define TEXTW(X)              (drw_fontset_getwidth(drw, (X)) + lrpad) -+  -+ /* enums */ -+-enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ -++enum { SchemeNorm, SchemeSel, SchemeNormHighlight, SchemeSelHighlight, -++       SchemeOut, SchemeLast }; /* color schemes */ -++ -+  -+ struct item { -+ 	char *text; -+@@ -113,9 +115,49 @@ cistrstr(const char *s, const char *sub) -+ 	return NULL; -+ } -+  -++static void -++drawhighlights(struct item *item, int x, int y, int maxw) -++{ -++	int i, indent; -++	char *highlight; -++	char c; -++ -++	if (!(strlen(item->text) && strlen(text))) -++		return; -++ -++	drw_setscheme(drw, scheme[item == sel -++	                   ? SchemeSelHighlight -++	                   : SchemeNormHighlight]); -++	for (i = 0, highlight = item->text; *highlight && text[i];) { -++		if (*highlight == text[i]) { -++			/* get indentation */ -++			c = *highlight; -++			*highlight = '\0'; -++			indent = TEXTW(item->text); -++			*highlight = c; -++ -++			/* highlight character */ -++			c = highlight[1]; -++			highlight[1] = '\0'; -++			drw_text( -++				drw, -++				x + indent - (lrpad / 2), -++				y, -++				MIN(maxw - indent, TEXTW(highlight) - lrpad), -++				bh, 0, highlight, 0 -++			); -++			highlight[1] = c; -++			i++; -++		} -++		highlight++; -++	} -++} -++ -++ -+ static int -+ drawitem(struct item *item, int x, int y, int w) -+ { -++	int r; -+ 	if (item == sel) -+ 		drw_setscheme(drw, scheme[SchemeSel]); -+ 	else if (item->out) -+@@ -123,7 +165,9 @@ drawitem(struct item *item, int x, int y -+ 	else -+ 		drw_setscheme(drw, scheme[SchemeNorm]); -+  -+-	return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); -++	r = drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); -++	drawhighlights(item, x, y, w); -++	return r; -+ } -+  -+ static void -+@@ -683,7 +727,8 @@ static void -+ usage(void) -+ { -+ 	fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" -+-	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); -++	      "             [-nb color] [-nf color] [-sb color] [-sf color]\n" -++	      "             [-nhb color] [-nhf color] [-shb color] [-shf color] [-w windowid]\n", stderr); -+ 	exit(1); -+ } -+  -+@@ -724,6 +769,14 @@ main(int argc, char *argv[]) -+ 			colors[SchemeSel][ColBg] = argv[++i]; -+ 		else if (!strcmp(argv[i], "-sf"))  /* selected foreground color */ -+ 			colors[SchemeSel][ColFg] = argv[++i]; -++		else if (!strcmp(argv[i], "-nhb")) /* normal hi background color */ -++			colors[SchemeNormHighlight][ColBg] = argv[++i]; -++		else if (!strcmp(argv[i], "-nhf")) /* normal hi foreground color */ -++			colors[SchemeNormHighlight][ColFg] = argv[++i]; -++		else if (!strcmp(argv[i], "-shb")) /* selected hi background color */ -++			colors[SchemeSelHighlight][ColBg] = argv[++i]; -++		else if (!strcmp(argv[i], "-shf")) /* selected hi foreground color */ -++			colors[SchemeSelHighlight][ColFg] = argv[++i]; -+ 		else if (!strcmp(argv[i], "-w"))   /* embedding window id */ -+ 			embed = argv[++i]; -+ 		else -diff --git a/patches/dmenu-fuzzymatch-4.9.diff b/patches/dmenu-fuzzymatch-4.9.diff -new file mode 100644 -index 0000000..9fd206d ---- /dev/null -+++ b/patches/dmenu-fuzzymatch-4.9.diff -@@ -0,0 +1,163 @@ -+From 94353eb52055927d9079f3d9e33da1c954abf386 Mon Sep 17 00:00:00 2001 -+From: aleks <aleks.stier@icloud.com> -+Date: Wed, 26 Jun 2019 13:25:10 +0200 -+Subject: [PATCH] Add support for fuzzy-matching -+ -+--- -+ config.def.h |  1 + -+ config.mk    |  2 +- -+ dmenu.c      | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++ -+ 3 files changed, 91 insertions(+), 1 deletion(-) -+ -+diff --git a/config.def.h b/config.def.h -+index 1edb647..51612b9 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -2,6 +2,7 @@ -+ /* Default settings; can be overriden by command line. */ -+  -+ 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 const char *fonts[] = { -+ 	"monospace:size=10" -+diff --git a/config.mk b/config.mk -+index 0929b4a..d14309a 100644 -+--- a/config.mk -++++ b/config.mk -+@@ -20,7 +20,7 @@ FREETYPEINC = /usr/include/freetype2 -+  -+ # includes and libs -+ INCS = -I$(X11INC) -I$(FREETYPEINC) -+-LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -++LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lm -+  -+ # flags -+ CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) -+diff --git a/dmenu.c b/dmenu.c -+index 6b8f51b..96ddc98 100644 -+--- a/dmenu.c -++++ b/dmenu.c -+@@ -1,6 +1,7 @@ -+ /* See LICENSE file for copyright and license details. */ -+ #include <ctype.h> -+ #include <locale.h> -++#include <math.h> -+ #include <stdio.h> -+ #include <stdlib.h> -+ #include <string.h> -+@@ -32,6 +33,7 @@ struct item { -+ 	char *text; -+ 	struct item *left, *right; -+ 	int out; -++	double distance; -+ }; -+  -+ static char text[BUFSIZ] = ""; -+@@ -210,9 +212,94 @@ grabkeyboard(void) -+ 	die("cannot grab keyboard"); -+ } -+  -++int -++compare_distance(const void *a, const void *b) -++{ -++	struct item *da = *(struct item **) a; -++	struct item *db = *(struct item **) b; -++ -++	if (!db) -++		return 1; -++	if (!da) -++		return -1; -++ -++	return da->distance == db->distance ? 0 : da->distance < db->distance ? -1 : 1; -++} -++ -++void -++fuzzymatch(void) -++{ -++	/* bang - we have so much memory */ -++	struct item *it; -++	struct item **fuzzymatches = NULL; -++	char c; -++	int number_of_matches = 0, i, pidx, sidx, eidx; -++	int text_len = strlen(text), itext_len; -++ -++	matches = matchend = NULL; -++ -++	/* walk through all items */ -++	for (it = items; it && it->text; it++) { -++		if (text_len) { -++			itext_len = strlen(it->text); -++			pidx = 0; /* pointer */ -++			sidx = eidx = -1; /* start of match, end of match */ -++			/* walk through item text */ -++			for (i = 0; i < itext_len && (c = it->text[i]); i++) { -++				/* fuzzy match pattern */ -++				if (!fstrncmp(&text[pidx], &c, 1)) { -++					if(sidx == -1) -++						sidx = i; -++					pidx++; -++					if (pidx == text_len) { -++						eidx = i; -++						break; -++					} -++				} -++			} -++			/* build list of matches */ -++			if (eidx != -1) { -++				/* compute distance */ -++				/* add penalty if match starts late (log(sidx+2)) -++				 * add penalty for long a match without many matching characters */ -++				it->distance = log(sidx + 2) + (double)(eidx - sidx - text_len); -++				/* fprintf(stderr, "distance %s %f\n", it->text, it->distance); */ -++				appenditem(it, &matches, &matchend); -++				number_of_matches++; -++			} -++		} else { -++			appenditem(it, &matches, &matchend); -++		} -++	} -++ -++	if (number_of_matches) { -++		/* initialize array with matches */ -++		if (!(fuzzymatches = realloc(fuzzymatches, number_of_matches * sizeof(struct item*)))) -++			die("cannot realloc %u bytes:", number_of_matches * sizeof(struct item*)); -++		for (i = 0, it = matches; it && i < number_of_matches; i++, it = it->right) { -++			fuzzymatches[i] = it; -++		} -++		/* sort matches according to distance */ -++		qsort(fuzzymatches, number_of_matches, sizeof(struct item*), compare_distance); -++		/* rebuild list of matches */ -++		matches = matchend = NULL; -++		for (i = 0, it = fuzzymatches[i];  i < number_of_matches && it && \ -++				it->text; i++, it = fuzzymatches[i]) { -++			appenditem(it, &matches, &matchend); -++		} -++		free(fuzzymatches); -++	} -++	curr = sel = matches; -++	calcoffsets(); -++} -++ -+ static void -+ match(void) -+ { -++	if (fuzzy) { -++		fuzzymatch(); -++		return; -++	} -+ 	static char **tokv = NULL; -+ 	static int tokn = 0; -+  -+@@ -702,6 +789,8 @@ 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], "-F"))   /* grabs keyboard before reading stdin */ -++			fuzzy = 0; -+ 		else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ -+ 			fstrncmp = strncasecmp; -+ 			fstrstr = cistrstr; -+--  -+2.22.0 -+ -diff --git a/patches/dmenu-lineheight-5.0.diff b/patches/dmenu-lineheight-5.0.diff -new file mode 100644 -index 0000000..3b0df3d ---- /dev/null -+++ b/patches/dmenu-lineheight-5.0.diff -@@ -0,0 +1,106 @@ -+From ba103e38ea4ab07f9a3ee90627714b9bea17c329 Mon Sep 17 00:00:00 2001 -+From: pskry <peter@skrypalle.dk> -+Date: Sun, 8 Nov 2020 22:04:22 +0100 -+Subject: [PATCH] Add an option which defines the lineheight -+ -+Despite both the panel and dmenu using the same font (a Terminus 12), -+dmenu is shorter and the panel is visible from under the dmenu bar. -+The appearance can be even more distracting when using similar colors -+for background and selections. With the option added by this patch, -+dmenu can be launched with a '-h 24', thus completely covering the panel. -+--- -+ config.def.h |  3 +++ -+ dmenu.1      |  5 +++++ -+ dmenu.c      | 11 ++++++++--- -+ 3 files changed, 16 insertions(+), 3 deletions(-) -+ -+diff --git a/config.def.h b/config.def.h -+index 1edb647..4394dec 100644 -+--- a/config.def.h -++++ b/config.def.h -+@@ -15,6 +15,9 @@ static const char *colors[SchemeLast][2] = { -+ }; -+ /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ -+ static unsigned int lines      = 0; -++/* -h option; minimum height of a menu line */ -++static unsigned int lineheight = 0; -++static unsigned int min_lineheight = 8; -+  -+ /* -+  * Characters not considered part of a word while deleting words -+diff --git a/dmenu.1 b/dmenu.1 -+index 323f93c..f2a82b4 100644 -+--- a/dmenu.1 -++++ b/dmenu.1 -+@@ -6,6 +6,8 @@ dmenu \- dynamic menu -+ .RB [ \-bfiv ] -+ .RB [ \-l -+ .IR lines ] -++.RB [ \-h -++.IR height ] -+ .RB [ \-m -+ .IR monitor ] -+ .RB [ \-p -+@@ -50,6 +52,9 @@ dmenu matches menu items case insensitively. -+ .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. -+diff --git a/dmenu.c b/dmenu.c -+index 65f25ce..f2a4047 100644 -+--- a/dmenu.c -++++ b/dmenu.c -+@@ -131,7 +131,7 @@ drawmenu(void) -+ { -+ 	unsigned int curpos; -+ 	struct item *item; -+-	int x = 0, y = 0, w; -++	int x = 0, y = 0, fh = drw->fonts->h, w; -+  -+ 	drw_setscheme(drw, scheme[SchemeNorm]); -+ 	drw_rect(drw, 0, 0, mw, mh, 1, 1); -+@@ -148,7 +148,7 @@ drawmenu(void) -+ 	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) { -+@@ -609,6 +609,7 @@ 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; -+ #ifdef XINERAMA -+@@ -689,7 +690,7 @@ setup(void) -+ static void -+ usage(void) -+ { -+-	fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" -++	fputs("usage: dmenu [-bfiv] [-l lines] [-h height] [-p prompt] [-fn font] [-m monitor]\n" -+ 	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); -+ 	exit(1); -+ } -+@@ -717,6 +718,10 @@ main(int argc, char *argv[]) -+ 		/* these options take one argument */ -+ 		else if (!strcmp(argv[i], "-l"))   /* number of lines in vertical list */ -+ 			lines = atoi(argv[++i]); -++		else if (!strcmp(argv[i], "-h")) { /* minimum height of one menu line */ -++			lineheight = atoi(argv[++i]); -++			lineheight = MAX(lineheight, min_lineheight); -++		} -+ 		else if (!strcmp(argv[i], "-m")) -+ 			mon = atoi(argv[++i]); -+ 		else if (!strcmp(argv[i], "-p"))   /* adds prompt to left of input field */ -+--  -+2.29.2 -+ -diff --git a/patches/dmenu-mousesupport-5.1.diff b/patches/dmenu-mousesupport-5.1.diff -new file mode 100644 -index 0000000..49824ba ---- /dev/null -+++ b/patches/dmenu-mousesupport-5.1.diff -@@ -0,0 +1,144 @@ -+diff --git a/dmenu.c b/dmenu.c -+index d95e6c6..75a79d0 100644 -+--- a/dmenu.c -++++ b/dmenu.c -+@@ -518,6 +518,119 @@ draw: -+ 	drawmenu(); -+ } -+  -++static void -++buttonpress(XEvent *e) -++{ -++	struct item *item; -++	XButtonPressedEvent *ev = &e->xbutton; -++	int x = 0, y = 0, h = bh, w; -++ -++	if (ev->window != win) -++		return; -++ -++	/* right-click: exit */ -++	if (ev->button == Button3) -++		exit(1); -++ -++	if (prompt && *prompt) -++		x += promptw; -++ -++	/* input field */ -++	w = (lines > 0 || !matches) ? mw - x : inputw; -++ -++	/* left-click on input: clear input, -++	 * NOTE: if there is no left-arrow the space for < is reserved so -++	 *       add that to the input width */ -++	if (ev->button == Button1 && -++	   ((lines <= 0 && ev->x >= 0 && ev->x <= x + w + -++	   ((!prev || !curr->left) ? TEXTW("<") : 0)) || -++	   (lines > 0 && ev->y >= y && ev->y <= y + h))) { -++		insert(NULL, -cursor); -++		drawmenu(); -++		return; -++	} -++	/* middle-mouse click: paste selection */ -++	if (ev->button == Button2) { -++		XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, -++		                  utf8, utf8, win, CurrentTime); -++		drawmenu(); -++		return; -++	} -++	/* scroll up */ -++	if (ev->button == Button4 && prev) { -++		sel = curr = prev; -++		calcoffsets(); -++		drawmenu(); -++		return; -++	} -++	/* scroll down */ -++	if (ev->button == Button5 && next) { -++		sel = curr = next; -++		calcoffsets(); -++		drawmenu(); -++		return; -++	} -++	if (ev->button != Button1) -++		return; -++	if (ev->state & ~ControlMask) -++		return; -++	if (lines > 0) { -++		/* vertical list: (ctrl)left-click on item */ -++		w = mw - x; -++		for (item = curr; item != next; item = item->right) { -++			y += h; -++			if (ev->y >= y && ev->y <= (y + h)) { -++				puts(item->text); -++				if (!(ev->state & ControlMask)) -++					exit(0); -++				sel = item; -++				if (sel) { -++					sel->out = 1; -++					drawmenu(); -++				} -++				return; -++			} -++		} -++	} else if (matches) { -++		/* left-click on left arrow */ -++		x += inputw; -++		w = TEXTW("<"); -++		if (prev && curr->left) { -++			if (ev->x >= x && ev->x <= x + w) { -++				sel = curr = prev; -++				calcoffsets(); -++				drawmenu(); -++				return; -++			} -++		} -++		/* horizontal list: (ctrl)left-click on item */ -++		for (item = curr; item != next; item = item->right) { -++			x += w; -++			w = MIN(TEXTW(item->text), mw - x - TEXTW(">")); -++			if (ev->x >= x && ev->x <= x + w) { -++				puts(item->text); -++				if (!(ev->state & ControlMask)) -++					exit(0); -++				sel = item; -++				if (sel) { -++					sel->out = 1; -++					drawmenu(); -++				} -++				return; -++			} -++		} -++		/* left-click on right arrow */ -++		w = TEXTW(">"); -++		x = mw - w; -++		if (next && ev->x >= x && ev->x <= x + w) { -++			sel = curr = next; -++			calcoffsets(); -++			drawmenu(); -++			return; -++		} -++	} -++} -++ -+ static void -+ paste(void) -+ { -+@@ -579,6 +692,9 @@ run(void) -+ 				break; -+ 			cleanup(); -+ 			exit(1); -++		case ButtonPress: -++			buttonpress(&ev); -++			break; -+ 		case Expose: -+ 			if (ev.xexpose.count == 0) -+ 				drw_map(drw, win, 0, 0, mw, mh); -+@@ -676,7 +792,8 @@ setup(void) -+ 	/* create menu window */ -+ 	swa.override_redirect = True; -+ 	swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; -+-	swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; -++	swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask | -++	                 ButtonPressMask; -+ 	win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0, -+ 	                    CopyFromParent, CopyFromParent, CopyFromParent, -+ 	                    CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); -diff --git a/patches/dmenu-mousesupporthoverbgcol-5.0.diff b/patches/dmenu-mousesupporthoverbgcol-5.0.diff -new file mode 100644 -index 0000000..1fb7d41 ---- /dev/null -+++ b/patches/dmenu-mousesupporthoverbgcol-5.0.diff -@@ -0,0 +1,184 @@ -+Only in .: config.h -+diff -up ../dmenu-5.0/dmenu.c ./dmenu.c -+--- ../dmenu-5.0/dmenu.c	Wed Sep  2 18:37:07 2020 -++++ ./dmenu.c	Wed Nov  4 15:25:27 2020 -+@@ -501,6 +501,156 @@ draw: -+ } -+  -+ static void -++buttonpress(XEvent *e) -++{ -++	struct item *item; -++	XButtonPressedEvent *ev = &e->xbutton; -++	int x = 0, y = 0, h = bh, w; -++ -++	if (ev->window != win) -++		return; -++ -++	/* right-click: exit */ -++	if (ev->button == Button3) -++		exit(1); -++ -++	if (prompt && *prompt) -++		x += promptw; -++ -++	/* input field */ -++	w = (lines > 0 || !matches) ? mw - x : inputw; -++ -++	/* left-click on input: clear input, -++	 * NOTE: if there is no left-arrow the space for < is reserved so -++	 *       add that to the input width */ -++	if (ev->button == Button1 && -++	   ((lines <= 0 && ev->x >= 0 && ev->x <= x + w + -++	   ((!prev || !curr->left) ? TEXTW("<") : 0)) || -++	   (lines > 0 && ev->y >= y && ev->y <= y + h))) { -++		insert(NULL, -cursor); -++		drawmenu(); -++		return; -++	} -++	/* middle-mouse click: paste selection */ -++	if (ev->button == Button2) { -++		XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, -++		                  utf8, utf8, win, CurrentTime); -++		drawmenu(); -++		return; -++	} -++	/* scroll up */ -++	if (ev->button == Button4 && prev) { -++		sel = curr = prev; -++		calcoffsets(); -++		drawmenu(); -++		return; -++	} -++	/* scroll down */ -++	if (ev->button == Button5 && next) { -++		sel = curr = next; -++		calcoffsets(); -++		drawmenu(); -++		return; -++	} -++	if (ev->button != Button1) -++		return; -++	/* disabled below, needs to be fixed */ -++	/* -++	if (ev->state & ~ControlMask) -++		return; -++	*/ -++	if (lines > 0) { -++		/* vertical list: (ctrl)left-click on item */ -++		w = mw - x; -++		for (item = curr; item != next; item = item->right) { -++			y += h; -++			if (ev->y >= y && ev->y <= (y + h)) { -++				puts(item->text); -++				if (!(ev->state & ControlMask)) -++					exit(0); -++				sel = item; -++				if (sel) { -++					sel->out = 1; -++					drawmenu(); -++				} -++				return; -++			} -++		} -++	} else if (matches) { -++		/* left-click on left arrow */ -++		x += inputw; -++		w = TEXTW("<"); -++		if (prev && curr->left) { -++			if (ev->x >= x && ev->x <= x + w) { -++				sel = curr = prev; -++				calcoffsets(); -++				drawmenu(); -++				return; -++			} -++		} -++		/* horizontal list: (ctrl)left-click on item */ -++		for (item = curr; item != next; item = item->right) { -++			x += w; -++			w = MIN(TEXTW(item->text), mw - x - TEXTW(">")); -++			if (ev->x >= x && ev->x <= x + w) { -++				puts(item->text); -++				if (!(ev->state & ControlMask)) -++					exit(0); -++				sel = item; -++				if (sel) { -++					sel->out = 1; -++					drawmenu(); -++				} -++				return; -++			} -++		} -++		/* left-click on right arrow */ -++		w = TEXTW(">"); -++		x = mw - w; -++		if (next && ev->x >= x && ev->x <= x + w) { -++			sel = curr = next; -++			calcoffsets(); -++			drawmenu(); -++			return; -++		} -++	} -++} -++ -++static void -++mousemove(XEvent *e) -++{ -++	struct item *item; -++	XPointerMovedEvent *ev = &e->xmotion; -++	int x = 0, y = 0, h = bh, w; -++ -++	if (lines > 0) { -++		w = mw - x; -++		for (item = curr; item != next; item = item->right) { -++			y += h; -++			if (ev->y >= y && ev->y <= (y + h)) { -++				sel = item; -++				calcoffsets(); -++				drawmenu(); -++				return; -++			} -++		} -++	} else if (matches) { -++		x += inputw; -++		w = TEXTW("<"); -++		for (item = curr; item != next; item = item->right) { -++			x += w; -++			w = MIN(TEXTW(item->text), mw - x - TEXTW(">")); -++			if (ev->x >= x && ev->x <= x + w) { -++				sel = item; -++				calcoffsets(); -++				drawmenu(); -++				return; -++			} -++		} -++	} -++} -++ -++static void -+ paste(void) -+ { -+ 	char *p, *q; -+@@ -561,6 +711,12 @@ run(void) -+ 				break; -+ 			cleanup(); -+ 			exit(1); -++		case ButtonPress: -++			buttonpress(&ev); -++			break; -++		case MotionNotify: -++			mousemove(&ev); -++			break; -+ 		case Expose: -+ 			if (ev.xexpose.count == 0) -+ 				drw_map(drw, win, 0, 0, mw, mh); -+@@ -658,7 +814,8 @@ setup(void) -+ 	/* create menu window */ -+ 	swa.override_redirect = True; -+ 	swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; -+-	swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; -++	swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask | -++	                 ButtonPressMask | PointerMotionMask; -+ 	win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0, -+ 	                    CopyFromParent, CopyFromParent, CopyFromParent, -+ 	                    CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); -diff --git a/patches/dmenu-password-5.0.diff b/patches/dmenu-password-5.0.diff -new file mode 100644 -index 0000000..7a187b9 ---- /dev/null -+++ b/patches/dmenu-password-5.0.diff -@@ -0,0 +1,103 @@ -+From c4de1032bd4c247bc20b6ab92a10a8d778966679 Mon Sep 17 00:00:00 2001 -+From: Mehrad Mahmoudian <m.mahmoudian@gmail.com> -+Date: Tue, 4 May 2021 12:05:09 +0300 -+Subject: [PATCH] patched with password patch -+ -+--- -+ dmenu.1 |  5 ++++- -+ dmenu.c | 21 +++++++++++++++++---- -+ 2 files changed, 21 insertions(+), 5 deletions(-) -+ -+diff --git a/dmenu.1 b/dmenu.1 -+index 323f93c..762f707 100644 -+--- a/dmenu.1 -++++ b/dmenu.1 -+@@ -3,7 +3,7 @@ -+ dmenu \- dynamic menu -+ .SH SYNOPSIS -+ .B dmenu -+-.RB [ \-bfiv ] -++.RB [ \-bfivP ] -+ .RB [ \-l -+ .IR lines ] -+ .RB [ \-m -+@@ -47,6 +47,9 @@ 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 -+diff --git a/dmenu.c b/dmenu.c -+index 65f25ce..ad8f63b 100644 -+--- a/dmenu.c -++++ b/dmenu.c -+@@ -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; -+@@ -132,6 +132,7 @@ drawmenu(void) -+ 	unsigned int curpos; -+ 	struct item *item; -+ 	int x = 0, y = 0, w; -++	char *censort; -+  -+ 	drw_setscheme(drw, scheme[SchemeNorm]); -+ 	drw_rect(drw, 0, 0, mw, mh, 1, 1); -+@@ -143,7 +144,12 @@ 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) { -+@@ -524,6 +530,11 @@ readstdin(void) -+ 	char buf[sizeof text], *p; -+ 	size_t i, imax = 0, size = 0; -+ 	unsigned int tmpmax = 0; -++	if(passwd){ -++    	inputw = lines = 0; -++    	return; -++  	} -++ -+  -+ 	/* read each line from stdin and add it to the item list */ -+ 	for (i = 0; fgets(buf, sizeof buf, stdin); i++) { -+@@ -689,7 +700,7 @@ setup(void) -+ static void -+ usage(void) -+ { -+-	fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" -++	fputs("usage: dmenu [-bfivP] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" -+ 	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); -+ 	exit(1); -+ } -+@@ -712,7 +723,9 @@ main(int argc, char *argv[]) -+ 		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 */ -+--  -+2.31.1 -+ -diff --git a/patches/dmenu-rejectnomatch-4.7.diff b/patches/dmenu-rejectnomatch-4.7.diff -new file mode 100644 -index 0000000..329ab1d ---- /dev/null -+++ b/patches/dmenu-rejectnomatch-4.7.diff -@@ -0,0 +1,82 @@ -+diff --git a/dmenu.1 b/dmenu.1 -+index 9eab758..61084ab 100644 -+--- a/dmenu.1 -++++ b/dmenu.1 -+@@ -3,7 +3,7 @@ -+ dmenu \- dynamic menu -+ .SH SYNOPSIS -+ .B dmenu -+-.RB [ \-bfiv ] -++.RB [ \-bfirv ] -+ .RB [ \-l -+ .IR lines ] -+ .RB [ \-m -+@@ -47,6 +47,9 @@ X until stdin reaches end\-of\-file. -+ .B \-i -+ dmenu matches menu items case insensitively. -+ .TP -++.B \-r -++dmenu will reject any input which would result in no matching option left. -++.TP -+ .BI \-l " lines" -+ dmenu lists items vertically, with the given number of lines. -+ .TP -+diff --git a/dmenu.c b/dmenu.c -+index d605ab4..7505278 100644 -+--- a/dmenu.c -++++ b/dmenu.c -+@@ -38,6 +38,7 @@ static char *embed; -+ static int bh, mw, mh; -+ static int inputw = 0, promptw; -+ static int lrpad; /* sum of left and right padding */ -++static int reject_no_match = 0; -+ static size_t cursor; -+ static struct item *items = NULL; -+ static struct item *matches, *matchend; -+@@ -268,12 +269,26 @@ insert(const char *str, ssize_t n) -+ { -+ 	if (strlen(text) + n > sizeof text - 1) -+ 		return; -++ -++	static char last[BUFSIZ] = ""; -++	if(reject_no_match) { -++		/* store last text value in case we need to revert it */ -++		memcpy(last, text, BUFSIZ); -++	} -++ -+ 	/* move existing text out of the way, insert new text, and update cursor */ -+ 	memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0)); -+ 	if (n > 0) -+ 		memcpy(&text[cursor], str, n); -+ 	cursor += n; -+ 	match(); -++ -++	if(!matches && reject_no_match) { -++		/* revert to last text value if theres no match */ -++		memcpy(text, last, BUFSIZ); -++		cursor -= n; -++		match(); -++	} -+ } -+  -+ static size_t -+@@ -636,7 +651,7 @@ setup(void) -+ static void -+ usage(void) -+ { -+-	fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" -++	fputs("usage: dmenu [-bfirv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" -+ 	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); -+ 	exit(1); -+ } -+@@ -659,7 +674,9 @@ main(int argc, char *argv[]) -+ 		else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ -+ 			fstrncmp = strncasecmp; -+ 			fstrstr = cistrstr; -+-		} else if (i + 1 == argc) -++		} else if (!strcmp(argv[i], "-r")) /* reject input which results in no match */ -++			reject_no_match = 1; -++		else if (i + 1 == argc) -+ 			usage(); -+ 		/* these options take one argument */ -+ 		else if (!strcmp(argv[i], "-l"))   /* number of lines in vertical list */ -diff --git a/patches/dmenu-separator-20210904-d78ff08.diff b/patches/dmenu-separator-20210904-d78ff08.diff -new file mode 100644 -index 0000000..be30420 ---- /dev/null -+++ b/patches/dmenu-separator-20210904-d78ff08.diff -@@ -0,0 +1,101 @@ -+diff --git a/dmenu.1 b/dmenu.1 -+index 323f93c..d511148 100644 -+--- a/dmenu.1 -++++ b/dmenu.1 -+@@ -22,6 +22,10 @@ dmenu \- dynamic menu -+ .IR color ] -+ .RB [ \-w -+ .IR windowid ] -++.RB [ \-d -++.IR separator ] -++.RB [ \-D -++.IR separator ] -+ .P -+ .BR dmenu_run " ..." -+ .SH DESCRIPTION -+@@ -80,6 +84,14 @@ prints version information to stdout, then exits. -+ .TP -+ .BI \-w " windowid" -+ embed into windowid. -++.TP -++.BI \-d " separator" -++separate the input into two halves on the first occurrence of the given charcter. -++Display only the first half in dmenu and print the second half to stdout upon selection. -++Appending '|' to the separator reverses the display/printing order. -++.TP -++.BI \-D " separator" -++same as \-d but separate based on the last occurrence. -+ .SH USAGE -+ dmenu is completely controlled by the keyboard.  Items are selected using the -+ arrow keys, page up, page down, home, and end. -+diff --git a/dmenu.c b/dmenu.c -+index 98507d9..82227c8 100644 -+--- a/dmenu.c -++++ b/dmenu.c -+@@ -30,12 +30,16 @@ enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ -+  -+ struct item { -+ 	char *text; -++	char *text_output; -+ 	struct item *left, *right; -+ 	int out; -+ }; -+  -+ static char text[BUFSIZ] = ""; -+ static char *embed; -++static char separator; -++static int separator_greedy; -++static int separator_reverse; -+ static int bh, mw, mh; -+ static int inputw = 0, promptw; -+ static int lrpad; /* sum of left and right padding */ -+@@ -473,7 +477,7 @@ insert: -+ 		break; -+ 	case XK_Return: -+ 	case XK_KP_Enter: -+-		puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); -++		puts((sel && !(ev->state & ShiftMask)) ? sel->text_output : text); -+ 		if (!(ev->state & ControlMask)) { -+ 			cleanup(); -+ 			exit(0); -+@@ -545,6 +549,18 @@ readstdin(void) -+ 			*p = '\0'; -+ 		if (!(items[i].text = strdup(buf))) -+ 			die("cannot strdup %u bytes:", strlen(buf) + 1); -++		if (separator && (p = separator_greedy ? -++		    strrchr(items[i].text, separator) : strchr(items[i].text, separator))) { -++			*p = '\0'; -++			items[i].text_output = ++p; -++		} else { -++			items[i].text_output = items[i].text; -++		} -++		if (separator_reverse) { -++			p = items[i].text; -++			items[i].text = items[i].text_output; -++			items[i].text_output = p; -++		} -+ 		items[i].out = 0; -+ 		drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL); -+ 		if (tmpmax > inputw) { -+@@ -701,7 +717,8 @@ static void -+ usage(void) -+ { -+ 	fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" -+-	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); -++	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n" -++	      "             [-d separator] [-D separator]\n", stderr); -+ 	exit(1); -+ } -+  -+@@ -744,6 +761,11 @@ main(int argc, char *argv[]) -+ 			colors[SchemeSel][ColFg] = argv[++i]; -+ 		else if (!strcmp(argv[i], "-w"))   /* embedding window id */ -+ 			embed = argv[++i]; -++		else if (!strcmp(argv[i], "-d") || /* field separator */ -++		         (separator_greedy = !strcmp(argv[i], "-D"))) { -++			separator = argv[++i][0]; -++			separator_reverse = argv[i][1] == '|'; -++		} -+ 		else -+ 			usage(); -+  -diff --git a/patches/dmenu-xresources-4.9.diff b/patches/dmenu-xresources-4.9.diff -new file mode 100644 -index 0000000..267fb0a ---- /dev/null -+++ b/patches/dmenu-xresources-4.9.diff -@@ -0,0 +1,126 @@ -+diff '--color=auto' -up ../dmenu-4.9/dmenu.c ./dmenu.c -+--- ../dmenu-4.9/dmenu.c	2019-02-02 13:55:02.000000000 +0100 -++++ ./dmenu.c	2020-05-24 00:27:58.038586112 +0200 -+@@ -15,6 +15,7 @@ -+ #include <X11/extensions/Xinerama.h> -+ #endif -+ #include <X11/Xft/Xft.h> -++#include <X11/Xresource.h> -+ -+ #include "drw.h" -+ #include "util.h" -+@@ -53,6 +54,10 @@ static XIC xic; -+ static Drw *drw; -+ static Clr *scheme[SchemeLast]; -+ -++/* Temporary arrays to allow overriding xresources values */ -++static char *colortemp[4]; -++static char *tempfonts; -++ -+ #include "config.h" -+ -+ static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; -+@@ -596,8 +601,13 @@ setup(void) -+ 	int a, di, n, area = 0; -+ #endif -+ 	/* init appearance */ -+-	for (j = 0; j < SchemeLast; j++) -+-		scheme[j] = drw_scm_create(drw, colors[j], 2); -++	for (j = 0; j < SchemeLast; j++) { -++		scheme[j] = drw_scm_create(drw, (const char**)colors[j], 2); -++	} -++	for (j = 0; j < SchemeOut; ++j) { -++		for (i = 0; i < 2; ++i) -++			free(colors[j][i]); -++	} -+ -+ 	clip = XInternAtom(dpy, "CLIPBOARD",   False); -+ 	utf8 = XInternAtom(dpy, "UTF8_STRING", False); -+@@ -687,6 +697,41 @@ usage(void) -+ 	exit(1); -+ } -+ -++void -++readxresources(void) { -++	XrmInitialize(); -++ -++	char* xrm; -++	if ((xrm = XResourceManagerString(drw->dpy))) { -++		char *type; -++		XrmDatabase xdb = XrmGetStringDatabase(xrm); -++		XrmValue xval; -++ -++		if (XrmGetResource(xdb, "dmenu.font", "*", &type, &xval)) -++			fonts[0] = strdup(xval.addr); -++		else -++			fonts[0] = strdup(fonts[0]); -++		if (XrmGetResource(xdb, "dmenu.background", "*", &type, &xval)) -++			colors[SchemeNorm][ColBg] = strdup(xval.addr); -++		else -++			colors[SchemeNorm][ColBg] = strdup(colors[SchemeNorm][ColBg]); -++		if (XrmGetResource(xdb, "dmenu.foreground", "*", &type, &xval)) -++			colors[SchemeNorm][ColFg] = strdup(xval.addr); -++		else -++			colors[SchemeNorm][ColFg] = strdup(colors[SchemeNorm][ColFg]); -++		if (XrmGetResource(xdb, "dmenu.selbackground", "*", &type, &xval)) -++			colors[SchemeSel][ColBg] = strdup(xval.addr); -++		else -++			colors[SchemeSel][ColBg] = strdup(colors[SchemeSel][ColBg]); -++		if (XrmGetResource(xdb, "dmenu.selforeground", "*", &type, &xval)) -++			colors[SchemeSel][ColFg] = strdup(xval.addr); -++		else -++			colors[SchemeSel][ColFg] = strdup(colors[SchemeSel][ColFg]); -++ -++		XrmDestroyDatabase(xdb); -++	} -++} -++ -+ int -+ main(int argc, char *argv[]) -+ { -+@@ -715,15 +760,15 @@ main(int argc, char *argv[]) -+ 		else if (!strcmp(argv[i], "-p"))   /* adds prompt to left of input field */ -+ 			prompt = argv[++i]; -+ 		else if (!strcmp(argv[i], "-fn"))  /* font or font set */ -+-			fonts[0] = argv[++i]; -++			tempfonts = argv[++i]; -+ 		else if (!strcmp(argv[i], "-nb"))  /* normal background color */ -+-			colors[SchemeNorm][ColBg] = argv[++i]; -++			colortemp[0] = argv[++i]; -+ 		else if (!strcmp(argv[i], "-nf"))  /* normal foreground color */ -+-			colors[SchemeNorm][ColFg] = argv[++i]; -++			colortemp[1] = argv[++i]; -+ 		else if (!strcmp(argv[i], "-sb"))  /* selected background color */ -+-			colors[SchemeSel][ColBg] = argv[++i]; -++			colortemp[2] = argv[++i]; -+ 		else if (!strcmp(argv[i], "-sf"))  /* selected foreground color */ -+-			colors[SchemeSel][ColFg] = argv[++i]; -++			colortemp[3] = argv[++i]; -+ 		else if (!strcmp(argv[i], "-w"))   /* embedding window id */ -+ 			embed = argv[++i]; -+ 		else -+@@ -743,8 +788,23 @@ main(int argc, char *argv[]) -+ 		die("could not get embedding window attributes: 0x%lx", -+ 		    parentwin); -+ 	drw = drw_create(dpy, screen, root, wa.width, wa.height); -+-	if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) -++	readxresources(); -++	/* Now we check whether to override xresources with commandline parameters */ -++	if ( tempfonts ) -++	   fonts[0] = strdup(tempfonts); -++	if ( colortemp[0]) -++	   colors[SchemeNorm][ColBg] = strdup(colortemp[0]); -++	if ( colortemp[1]) -++	   colors[SchemeNorm][ColFg] = strdup(colortemp[1]); -++	if ( colortemp[2]) -++	   colors[SchemeSel][ColBg]  = strdup(colortemp[2]); -++	if ( colortemp[3]) -++	   colors[SchemeSel][ColFg]  = strdup(colortemp[3]); -++ -++	if (!drw_fontset_create(drw, (const char**)fonts, LENGTH(fonts))) -+ 		die("no fonts could be loaded."); -++ -++	free(fonts[0]); -+ 	lrpad = drw->fonts->h; -+ -+ #ifdef __OpenBSD__ -diff --git a/config.def.h b/config.def.h -index 1edb647..3fb3def 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -2,22 +2,33 @@ - /* Default settings; can be overriden by command line. */ -  - static int topbar = 1;                      /* -b  option; if 0, dmenu appears at bottom     */ -+static int centered = 0;                    /* -c  option; centers dmenu on screen */ -+static int min_width = 500;                 /* minimum width when centered */ -+static int fuzzy = 0;                       /* -F  option; if 0, dmenu doesn't use fuzzy matching     */ - /* -fn option overrides fonts[0]; default X11 font or font set */ --static const char *fonts[] = { -+static char *fonts[] = { - 	"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 *colors[SchemeLast][2] = { - 	/*     fg         bg       */ - 	[SchemeNorm] = { "#bbbbbb", "#222222" }, - 	[SchemeSel] = { "#eeeeee", "#005577" }, -+	[SchemeSelHighlight] = { "#ffc978", "#005577" }, -+	[SchemeNormHighlight] = { "#ffc978", "#222222" }, - 	[SchemeOut] = { "#000000", "#00ffff" }, - }; - /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ - static unsigned int lines      = 0; -+/* -h option; minimum height of a menu line */ -+static unsigned int lineheight = 0; -+static unsigned int min_lineheight = 8; -  - /* -  * Characters not considered part of a word while deleting words -  * for example: " /?\"&[]" -  */ - static const char worddelimiters[] = " "; -+ -+/* Size of the window border */ -+static unsigned int border_width = 0; -diff --git a/config.mk b/config.mk -index 0df3fc8..3423b6a 100644 ---- a/config.mk -+++ b/config.mk -@@ -20,7 +20,7 @@ FREETYPEINC = /usr/include/freetype2 -  - # includes and libs - INCS = -I$(X11INC) -I$(FREETYPEINC) --LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -+LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lm -  - # flags - CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) -diff --git a/dmenu.1 b/dmenu.1 -index 323f93c..1602793 100644 ---- a/dmenu.1 -+++ b/dmenu.1 -@@ -3,9 +3,11 @@ - dmenu \- dynamic menu - .SH SYNOPSIS - .B dmenu --.RB [ \-bfiv ] -+.RB [ \-bFfirvP ] - .RB [ \-l - .IR lines ] -+.RB [ \-h -+.IR height ] - .RB [ \-m - .IR monitor ] - .RB [ \-p -@@ -20,8 +22,20 @@ dmenu \- dynamic menu - .IR color ] - .RB [ \-sf - .IR color ] -+.RB [ \-nhb -+.IR color ] -+.RB [ \-nhf -+.IR color ] -+.RB [ \-shb -+.IR color ] -+.RB [ \-shf -+.IR color ] - .RB [ \-w - .IR windowid ] -+.RB [ \-d -+.IR separator ] -+.RB [ \-D -+.IR separator ] - .P - .BR dmenu_run " ..." - .SH DESCRIPTION -@@ -40,6 +54,12 @@ which lists programs in the user's $PATH and runs the result in their $SHELL. - .B \-b - dmenu appears at the bottom of the screen. - .TP -+.B \-c -+dmenu appears centered on the screen. -+.TP -+.B \-F -+dmenu uses fuzzy matching -+.TP - .B \-f - 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. -@@ -47,9 +67,18 @@ 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 -+.B \-r -+dmenu will reject any input which would result in no matching option left. -+.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. -@@ -75,11 +104,31 @@ defines the selected background color. - .BI \-sf " color" - defines the selected foreground color. - .TP -+.BI \-nhb " color" -+defines the normal highlight background color. -+.TP -+.BI \-nhf " color" -+defines the normal highlight foreground color. -+.TP -+.BI \-shb " color" -+defines the selected highlight background color. -+.TP -+.BI \-shf " color" -+defines the selected highlight foreground color. -+.TP - .B \-v - prints version information to stdout, then exits. - .TP - .BI \-w " windowid" - embed into windowid. -+.TP -+.BI \-d " separator" -+separate the input into two halves on the first occurrence of the given charcter. -+Display only the first half in dmenu and print the second half to stdout upon selection. -+Appending '|' to the separator reverses the display/printing order. -+.TP -+.BI \-D " separator" -+same as \-d but separate based on the last occurrence. - .SH USAGE - dmenu is completely controlled by the keyboard.  Items are selected using the - arrow keys, page up, page down, home, and end. -diff --git a/dmenu.c b/dmenu.c -index d95e6c6..d304e3a 100644 ---- a/dmenu.c -+++ b/dmenu.c -@@ -1,6 +1,7 @@ - /* See LICENSE file for copyright and license details. */ - #include <ctype.h> - #include <locale.h> -+#include <math.h> - #include <stdio.h> - #include <stdlib.h> - #include <string.h> -@@ -15,6 +16,7 @@ - #include <X11/extensions/Xinerama.h> - #endif - #include <X11/Xft/Xft.h> -+#include <X11/Xresource.h> -  - #include "drw.h" - #include "util.h" -@@ -22,23 +24,33 @@ - /* 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 BOOL_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 */ --enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ -+enum { SchemeNorm, SchemeSel, SchemeNormHighlight, SchemeSelHighlight, -+       SchemeOut, SchemeLast }; /* color schemes */ -+ -  - struct item { - 	char *text; -+        char *text_output; - 	struct item *left, *right; - 	int out; -+	double distance; - }; -  - static char text[BUFSIZ] = ""; - static char *embed; -+static char separator; -+static int separator_greedy; -+static int separator_reverse; - 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 int reject_no_match = 0; - static size_t cursor; - static struct item *items = NULL; - static struct item *matches, *matchend; -@@ -53,6 +65,10 @@ static XIC xic; - static Drw *drw; - static Clr *scheme[SchemeLast]; -  -+/* Temporary arrays to allow overriding xresources values */ -+static char *colortemp[4]; -+static char *tempfonts; -+ - #include "config.h" -  - static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; -@@ -89,6 +105,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) - { -@@ -120,9 +145,49 @@ cistrstr(const char *h, const char *n) - 	return NULL; - } -  -+static void -+drawhighlights(struct item *item, int x, int y, int maxw) -+{ -+	int i, indent; -+	char *highlight; -+	char c; -+ -+	if (!(strlen(item->text) && strlen(text))) -+		return; -+ -+	drw_setscheme(drw, scheme[item == sel -+	                   ? SchemeSelHighlight -+	                   : SchemeNormHighlight]); -+	for (i = 0, highlight = item->text; *highlight && text[i];) { -+		if (!fstrncmp(&(*highlight), &text[i], 1)) { -+			/* get indentation */ -+			c = *highlight; -+			*highlight = '\0'; -+			indent = TEXTW(item->text); -+			*highlight = c; -+ -+			/* highlight character */ -+			c = highlight[1]; -+			highlight[1] = '\0'; -+			drw_text( -+				drw, -+				x + indent - (lrpad / 2), -+				y, -+				MIN(maxw - indent, TEXTW(highlight) - lrpad), -+				bh, 0, highlight, 0 -+			); -+			highlight[1] = c; -+			i++; -+		} -+		highlight++; -+	} -+} -+ -+ - static int - drawitem(struct item *item, int x, int y, int w) - { -+	int r; - 	if (item == sel) - 		drw_setscheme(drw, scheme[SchemeSel]); - 	else if (item->out) -@@ -130,7 +195,9 @@ drawitem(struct item *item, int x, int y, int w) - 	else - 		drw_setscheme(drw, scheme[SchemeNorm]); -  --	return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); -+	r = drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); -+	drawhighlights(item, x, y, w); -+	return r; - } -  - static void -@@ -138,7 +205,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); -@@ -150,12 +218,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) { -@@ -217,9 +290,94 @@ grabkeyboard(void) - 	die("cannot grab keyboard"); - } -  -+int -+compare_distance(const void *a, const void *b) -+{ -+	struct item *da = *(struct item **) a; -+	struct item *db = *(struct item **) b; -+ -+	if (!db) -+		return 1; -+	if (!da) -+		return -1; -+ -+	return da->distance == db->distance ? 0 : da->distance < db->distance ? -1 : 1; -+} -+ -+void -+fuzzymatch(void) -+{ -+	/* bang - we have so much memory */ -+	struct item *it; -+	struct item **fuzzymatches = NULL; -+	char c; -+	int number_of_matches = 0, i, pidx, sidx, eidx; -+	int text_len = strlen(text), itext_len; -+ -+	matches = matchend = NULL; -+ -+	/* walk through all items */ -+	for (it = items; it && it->text; it++) { -+		if (text_len) { -+			itext_len = strlen(it->text); -+			pidx = 0; /* pointer */ -+			sidx = eidx = -1; /* start of match, end of match */ -+			/* walk through item text */ -+			for (i = 0; i < itext_len && (c = it->text[i]); i++) { -+				/* fuzzy match pattern */ -+				if (!fstrncmp(&text[pidx], &c, 1)) { -+					if(sidx == -1) -+						sidx = i; -+					pidx++; -+					if (pidx == text_len) { -+						eidx = i; -+						break; -+					} -+				} -+			} -+			/* build list of matches */ -+			if (eidx != -1) { -+				/* compute distance */ -+				/* add penalty if match starts late (log(sidx+2)) -+				 * add penalty for long a match without many matching characters */ -+				it->distance = log(sidx + 2) + (double)(eidx - sidx - text_len); -+				/* fprintf(stderr, "distance %s %f\n", it->text, it->distance); */ -+				appenditem(it, &matches, &matchend); -+				number_of_matches++; -+			} -+		} else { -+			appenditem(it, &matches, &matchend); -+		} -+	} -+ -+	if (number_of_matches) { -+		/* initialize array with matches */ -+		if (!(fuzzymatches = realloc(fuzzymatches, number_of_matches * sizeof(struct item*)))) -+			die("cannot realloc %u bytes:", number_of_matches * sizeof(struct item*)); -+		for (i = 0, it = matches; it && i < number_of_matches; i++, it = it->right) { -+			fuzzymatches[i] = it; -+		} -+		/* sort matches according to distance */ -+		qsort(fuzzymatches, number_of_matches, sizeof(struct item*), compare_distance); -+		/* rebuild list of matches */ -+		matches = matchend = NULL; -+		for (i = 0, it = fuzzymatches[i];  i < number_of_matches && it && \ -+				it->text; i++, it = fuzzymatches[i]) { -+			appenditem(it, &matches, &matchend); -+		} -+		free(fuzzymatches); -+	} -+	curr = sel = matches; -+	calcoffsets(); -+} -+ - static void - match(void) - { -+	if (fuzzy) { -+		fuzzymatch(); -+		return; -+	} - 	static char **tokv = NULL; - 	static int tokn = 0; -  -@@ -276,12 +434,26 @@ insert(const char *str, ssize_t n) - { - 	if (strlen(text) + n > sizeof text - 1) - 		return; -+ -+	static char last[BUFSIZ] = ""; -+	if(reject_no_match) { -+		/* store last text value in case we need to revert it */ -+		memcpy(last, text, BUFSIZ); -+	} -+ - 	/* move existing text out of the way, insert new text, and update cursor */ - 	memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0)); - 	if (n > 0) - 		memcpy(&text[cursor], str, n); - 	cursor += n; - 	match(); -+ -+	if(!matches && reject_no_match) { -+		/* revert to last text value if theres no match */ -+		memcpy(text, last, BUFSIZ); -+		cursor -= n; -+		match(); -+	} - } -  - static size_t -@@ -480,7 +652,7 @@ insert: - 		break; - 	case XK_Return: - 	case XK_KP_Enter: --		puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); -+		puts((sel && !(ev->state & ShiftMask)) ? sel->text_output : text); - 		if (!(ev->state & ControlMask)) { - 			cleanup(); - 			exit(0); -@@ -518,6 +690,156 @@ draw: - 	drawmenu(); - } -  -+static void -+buttonpress(XEvent *e) -+{ -+	struct item *item; -+	XButtonPressedEvent *ev = &e->xbutton; -+	int x = 0, y = 0, h = bh, w; -+ -+	if (ev->window != win) -+		return; -+ -+	/* right-click: exit */ -+	if (ev->button == Button3) -+		exit(1); -+ -+	if (prompt && *prompt) -+		x += promptw; -+ -+	/* input field */ -+	w = (lines > 0 || !matches) ? mw - x : inputw; -+ -+	/* left-click on input: clear input, -+	 * NOTE: if there is no left-arrow the space for < is reserved so -+	 *       add that to the input width */ -+	if (ev->button == Button1 && -+	   ((lines <= 0 && ev->x >= 0 && ev->x <= x + w + -+	   ((!prev || !curr->left) ? TEXTW("<") : 0)) || -+	   (lines > 0 && ev->y >= y && ev->y <= y + h))) { -+		insert(NULL, -cursor); -+		drawmenu(); -+		return; -+	} -+	/* middle-mouse click: paste selection */ -+	if (ev->button == Button2) { -+		XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, -+		                  utf8, utf8, win, CurrentTime); -+		drawmenu(); -+		return; -+	} -+	/* scroll up */ -+	if (ev->button == Button4 && prev) { -+		sel = curr = prev; -+		calcoffsets(); -+		drawmenu(); -+		return; -+	} -+	/* scroll down */ -+	if (ev->button == Button5 && next) { -+		sel = curr = next; -+		calcoffsets(); -+		drawmenu(); -+		return; -+	} -+	if (ev->button != Button1) -+		return; -+	/* disabled below, needs to be fixed */ -+	/* -+	if (ev->state & ~ControlMask) -+		return; -+	*/ -+	if (lines > 0) { -+		/* vertical list: (ctrl)left-click on item */ -+		w = mw - x; -+		for (item = curr; item != next; item = item->right) { -+			y += h; -+			if (ev->y >= y && ev->y <= (y + h)) { -+				puts(item->text); -+				if (!(ev->state & ControlMask)) -+					exit(0); -+				sel = item; -+				if (sel) { -+					sel->out = 1; -+					drawmenu(); -+				} -+				return; -+			} -+		} -+	} else if (matches) { -+		/* left-click on left arrow */ -+		x += inputw; -+		w = TEXTW("<"); -+		if (prev && curr->left) { -+			if (ev->x >= x && ev->x <= x + w) { -+				sel = curr = prev; -+				calcoffsets(); -+				drawmenu(); -+				return; -+			} -+		} -+		/* horizontal list: (ctrl)left-click on item */ -+		for (item = curr; item != next; item = item->right) { -+			x += w; -+			w = MIN(TEXTW(item->text), mw - x - TEXTW(">")); -+			if (ev->x >= x && ev->x <= x + w) { -+				puts(item->text); -+				if (!(ev->state & ControlMask)) -+					exit(0); -+				sel = item; -+				if (sel) { -+					sel->out = 1; -+					drawmenu(); -+				} -+				return; -+			} -+		} -+		/* left-click on right arrow */ -+		w = TEXTW(">"); -+		x = mw - w; -+		if (next && ev->x >= x && ev->x <= x + w) { -+			sel = curr = next; -+			calcoffsets(); -+			drawmenu(); -+			return; -+		} -+	} -+} -+ -+static void -+mousemove(XEvent *e) -+{ -+	struct item *item; -+	XPointerMovedEvent *ev = &e->xmotion; -+	int x = 0, y = 0, h = bh, w; -+ -+	if (lines > 0) { -+		w = mw - x; -+		for (item = curr; item != next; item = item->right) { -+			y += h; -+			if (ev->y >= y && ev->y <= (y + h)) { -+				sel = item; -+				calcoffsets(); -+				drawmenu(); -+				return; -+			} -+		} -+	} else if (matches) { -+		x += inputw; -+		w = TEXTW("<"); -+		for (item = curr; item != next; item = item->right) { -+			x += w; -+			w = MIN(TEXTW(item->text), mw - x - TEXTW(">")); -+			if (ev->x >= x && ev->x <= x + w) { -+				sel = item; -+				calcoffsets(); -+				drawmenu(); -+				return; -+			} -+		} -+	} -+} -+ - static void - paste(void) - { -@@ -542,6 +864,11 @@ readstdin(void) - 	char buf[sizeof text], *p; - 	size_t i, imax = 0, size = 0; - 	unsigned int tmpmax = 0; -+	if(passwd){ -+    	inputw = lines = 0; -+    	return; -+  	} -+ -  - 	/* read each line from stdin and add it to the item list */ - 	for (i = 0; fgets(buf, sizeof buf, stdin); i++) { -@@ -552,6 +879,18 @@ readstdin(void) - 			*p = '\0'; - 		if (!(items[i].text = strdup(buf))) - 			die("cannot strdup %u bytes:", strlen(buf) + 1); -+		if (separator && (p = separator_greedy ? -+		    strrchr(items[i].text, separator) : strchr(items[i].text, separator))) { -+			*p = '\0'; -+			items[i].text_output = ++p; -+		} else { -+			items[i].text_output = items[i].text; -+		} -+		if (separator_reverse) { -+			p = items[i].text; -+			items[i].text = items[i].text_output; -+			items[i].text_output = p; -+		} - 		items[i].out = 0; - 		drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL); - 		if (tmpmax > inputw) { -@@ -579,6 +918,12 @@ run(void) - 				break; - 			cleanup(); - 			exit(1); -+		case ButtonPress: -+			buttonpress(&ev); -+			break; -+                case MotionNotify: -+                        mousemove(&ev); -+                        break; - 		case Expose: - 			if (ev.xexpose.count == 0) - 				drw_map(drw, win, 0, 0, mw, mh); -@@ -619,16 +964,23 @@ setup(void) - 	int a, di, n, area = 0; - #endif - 	/* init appearance */ --	for (j = 0; j < SchemeLast; j++) --		scheme[j] = drw_scm_create(drw, colors[j], 2); -+	for (j = 0; j < SchemeLast; j++) { -+		scheme[j] = drw_scm_create(drw, (const char**)colors[j], 2); -+	} -+	for (j = 0; j < SchemeOut; ++j) { -+		for (i = 0; i < 2; ++i) -+			free(colors[j][i]); -+	} -  - 	clip = XInternAtom(dpy, "CLIPBOARD",   False); - 	utf8 = XInternAtom(dpy, "UTF8_STRING", False); -  - 	/* 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))) { -@@ -652,12 +1004,19 @@ setup(void) - 		/* no focused window is on screen, so use pointer location instead */ - 		if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) - 			for (i = 0; i < n; i++) --				if (INTERSECT(x, y, 1, 1, info[i])) -+				if (BOOL_INTERSECT(x, y, 1, 1, info[i])) - 					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 -@@ -665,21 +1024,30 @@ 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 = MIN(inputw, mw/3); - 	match(); -  - 	/* create menu window */ - 	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, -+	swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask | -+                         ButtonPressMask | PointerMotionMask; -+	win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width, - 	                    CopyFromParent, CopyFromParent, CopyFromParent, - 	                    CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); -+	if (border_width) -+		XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel); - 	XSetClassHint(dpy, win, &ch); -  -  -@@ -707,11 +1075,64 @@ setup(void) - static void - usage(void) - { --	fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" --	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); -+	fputs("usage: dmenu [-bfirvP] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" -+	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-bw width]\n" -+	      "             [-nhb color] [-nhf color] [-shb color] [-shf color] [-w windowid]\n" -+              "             [-d separator] [-D separator]\n", stderr); - 	exit(1); - } -  -+void -+readxresources(void) { -+	XrmInitialize(); -+ -+	char* xrm; -+	if ((xrm = XResourceManagerString(drw->dpy))) { -+		char *type; -+		XrmDatabase xdb = XrmGetStringDatabase(xrm); -+		XrmValue xval; -+ -+		if (XrmGetResource(xdb, "dmenu.font", "*", &type, &xval)) -+			fonts[0] = strdup(xval.addr); -+		else -+			fonts[0] = strdup(fonts[0]); -+		if (XrmGetResource(xdb, "dmenu.background", "*", &type, &xval)) -+			colors[SchemeNorm][ColBg] = strdup(xval.addr); -+		else -+			colors[SchemeNorm][ColBg] = strdup(colors[SchemeNorm][ColBg]); -+		if (XrmGetResource(xdb, "dmenu.foreground", "*", &type, &xval)) -+			colors[SchemeNorm][ColFg] = strdup(xval.addr); -+		else -+			colors[SchemeNorm][ColFg] = strdup(colors[SchemeNorm][ColFg]); -+		if (XrmGetResource(xdb, "dmenu.selbackground", "*", &type, &xval)) -+			colors[SchemeSel][ColBg] = strdup(xval.addr); -+		else -+			colors[SchemeSel][ColBg] = strdup(colors[SchemeSel][ColBg]); -+		if (XrmGetResource(xdb, "dmenu.selforeground", "*", &type, &xval)) -+			colors[SchemeSel][ColFg] = strdup(xval.addr); -+		else -+			colors[SchemeSel][ColFg] = strdup(colors[SchemeSel][ColFg]); -+		if (XrmGetResource(xdb, "dmenu.selhibackground", "*", &type, &xval)) -+			colors[SchemeSelHighlight][ColBg] = strdup(xval.addr); -+		else -+			colors[SchemeSelHighlight][ColBg] = strdup(colors[SchemeSel][ColBg]); -+		if (XrmGetResource(xdb, "dmenu.selhiforeground", "*", &type, &xval)) -+			colors[SchemeSelHighlight][ColFg] = strdup(xval.addr); -+		else -+			colors[SchemeSelHighlight][ColFg] = strdup(colors[SchemeSel][ColFg]); -+		if (XrmGetResource(xdb, "dmenu.hibackground", "*", &type, &xval)) -+			colors[SchemeNormHighlight][ColBg] = strdup(xval.addr); -+		else -+			colors[SchemeNormHighlight][ColBg] = strdup(colors[SchemeNorm][ColBg]); -+		if (XrmGetResource(xdb, "dmenu.hiforeground", "*", &type, &xval)) -+			colors[SchemeNormHighlight][ColFg] = strdup(xval.addr); -+		else -+			colors[SchemeNormHighlight][ColFg] = strdup(colors[SchemeNorm][ColFg]); -+ -+		XrmDestroyDatabase(xdb); -+	} -+} -+ - int - main(int argc, char *argv[]) - { -@@ -727,30 +1148,56 @@ 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], "-F"))   /* grabs keyboard before reading stdin */ -+			fuzzy = 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 (!strcmp(argv[i], "-r")) /* reject input which results in no match */ -+                        reject_no_match = 1; -+		else if (i + 1 == argc) - 			usage(); - 		/* these options take one argument */ - 		else if (!strcmp(argv[i], "-l"))   /* number of lines in vertical list */ - 			lines = atoi(argv[++i]); -+		else if (!strcmp(argv[i], "-h")) { /* minimum height of one menu line */ -+			lineheight = atoi(argv[++i]); -+			lineheight = MAX(lineheight, min_lineheight); -+		} - 		else if (!strcmp(argv[i], "-m")) - 			mon = atoi(argv[++i]); - 		else if (!strcmp(argv[i], "-p"))   /* adds prompt to left of input field */ - 			prompt = argv[++i]; - 		else if (!strcmp(argv[i], "-fn"))  /* font or font set */ --			fonts[0] = argv[++i]; -+			tempfonts = argv[++i]; - 		else if (!strcmp(argv[i], "-nb"))  /* normal background color */ --			colors[SchemeNorm][ColBg] = argv[++i]; -+			colortemp[0] = argv[++i]; - 		else if (!strcmp(argv[i], "-nf"))  /* normal foreground color */ --			colors[SchemeNorm][ColFg] = argv[++i]; -+			colortemp[1] = argv[++i]; - 		else if (!strcmp(argv[i], "-sb"))  /* selected background color */ --			colors[SchemeSel][ColBg] = argv[++i]; -+			colortemp[2] = argv[++i]; - 		else if (!strcmp(argv[i], "-sf"))  /* selected foreground color */ --			colors[SchemeSel][ColFg] = argv[++i]; -+			colortemp[3] = argv[++i]; -+                else if (!strcmp(argv[i], "-nhb")) /* normal hi background color */ -+                        colors[SchemeNormHighlight][ColBg] = argv[++i]; -+                else if (!strcmp(argv[i], "-nhf")) /* normal hi foreground color */ -+                        colors[SchemeNormHighlight][ColFg] = argv[++i]; -+                else if (!strcmp(argv[i], "-shb")) /* selected hi background color */ -+                        colors[SchemeSelHighlight][ColBg] = argv[++i]; -+                else if (!strcmp(argv[i], "-shf")) /* selected hi foreground color */ -+                        colors[SchemeSelHighlight][ColFg] = argv[++i]; - 		else if (!strcmp(argv[i], "-w"))   /* embedding window id */ - 			embed = argv[++i]; -+		else if (!strcmp(argv[i], "-d") || /* field separator */ -+			(separator_greedy = !strcmp(argv[i], "-D"))) { -+                        separator = argv[++i][0]; -+                        separator_reverse = argv[i][1] == '|'; -+                } else if (!strcmp(argv[i], "-bw")) -+			border_width = atoi(argv[++i]); /* border width */ - 		else - 			usage(); -  -@@ -766,8 +1213,23 @@ main(int argc, char *argv[]) - 		die("could not get embedding window attributes: 0x%lx", - 		    parentwin); - 	drw = drw_create(dpy, screen, root, wa.width, wa.height); --	if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) -+	readxresources(); -+	/* Now we check whether to override xresources with commandline parameters */ -+	if ( tempfonts ) -+	   fonts[0] = strdup(tempfonts); -+	if ( colortemp[0]) -+	   colors[SchemeNorm][ColBg] = strdup(colortemp[0]); -+	if ( colortemp[1]) -+	   colors[SchemeNorm][ColFg] = strdup(colortemp[1]); -+	if ( colortemp[2]) -+	   colors[SchemeSel][ColBg]  = strdup(colortemp[2]); -+	if ( colortemp[3]) -+	   colors[SchemeSel][ColFg]  = strdup(colortemp[3]); -+ -+	if (!drw_fontset_create(drw, (const char**)fonts, LENGTH(fonts))) - 		die("no fonts could be loaded."); -+ -+	free(fonts[0]); - 	lrpad = drw->fonts->h; -  - #ifdef __OpenBSD__ @@ -3,7 +3,7 @@  dmenu \- dynamic menu  .SH SYNOPSIS  .B dmenu -.RB [ \-bFfirvP ] +.RB [ \-bfirvP ]  .RB [ \-l  .IR lines ]  .RB [ \-h @@ -57,9 +57,6 @@ dmenu appears at the bottom of the screen.  .B \-c  dmenu appears centered on the screen.  .TP -.B \-F -dmenu uses fuzzy matching -.TP  .B \-f  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. @@ -24,8 +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 BOOL_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) @@ -36,7 +34,7 @@ enum { SchemeNorm, SchemeSel, SchemeNormHighlight, SchemeSelHighlight,  struct item {  	char *text; -        char *text_output; +	char *text_output;  	struct item *left, *right;  	int out;  	double distance; @@ -44,9 +42,8 @@ struct item {  static char text[BUFSIZ] = "";  static char *embed; -static char separator; -static int separator_greedy; -static int separator_reverse; +static char separator, separator_reverse; +static char * (*sepchr)(const char *, int);  static int bh, mw, mh;  static int inputw = 0, promptw, passwd = 0;  static int lrpad; /* sum of left and right padding */ @@ -66,7 +63,7 @@ static Drw *drw;  static Clr *scheme[SchemeLast];  /* Temporary arrays to allow overriding xresources values */ -static char *colortemp[4]; +static char *colortemp[8];  static char *tempfonts;  #include "config.h" @@ -74,6 +71,13 @@ static char *tempfonts;  static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;  static char *(*fstrstr)(const char *, const char *) = strstr; +static unsigned int +textw_clamp(const char *str, unsigned int n) +{ +	unsigned int w = drw_fontset_getwidth_clamp(drw, str, n) + lrpad; +	return MIN(w, n); +} +  static void  appenditem(struct item *item, struct item **list, struct item **last)  { @@ -98,10 +102,10 @@ calcoffsets(void)  		n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));  	/* calculate which items will begin the next page and previous page */  	for (i = 0, next = curr; next; next = next->right) -		if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n) +		if ((i += (lines > 0) ? bh : textw_clamp(next->text, n)) > n)  			break;  	for (i = 0, prev = curr; prev && prev->left; prev = prev->left) -		if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n) +		if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n)  			break;  } @@ -122,6 +126,9 @@ cleanup(void)  	XUngrabKey(dpy, AnyKey, AnyModifier, root);  	for (i = 0; i < SchemeLast; i++)  		free(scheme[i]); +	for (i = 0; items && items[i].text; ++i) +		free(separator_reverse ? items[i].text_output : items[i].text); +	free(items);  	drw_free(drw);  	XSync(dpy, False);  	XCloseDisplay(dpy); @@ -159,19 +166,17 @@ drawhighlights(struct item *item, int x, int y, int maxw)  	                   ? SchemeSelHighlight  	                   : SchemeNormHighlight]);  	for (i = 0, highlight = item->text; *highlight && text[i];) { -		if (!fstrncmp(&(*highlight), &text[i], 1)) { +		if (!fstrncmp(&text[i], highlight, 1)) { +			c = highlight[1]; +			highlight[1] = '\0'; +  			/* get indentation */ -			c = *highlight; -			*highlight = '\0';  			indent = TEXTW(item->text); -			*highlight = c;  			/* highlight character */ -			c = highlight[1]; -			highlight[1] = '\0';  			drw_text(  				drw, -				x + indent - (lrpad / 2), +				x + indent - lrpad,  				y,  				MIN(maxw - indent, TEXTW(highlight) - lrpad),  				bh, 0, highlight, 0 @@ -220,7 +225,7 @@ drawmenu(void)  	drw_setscheme(drw, scheme[SchemeNorm]);  	if (passwd) {  	        censort = ecalloc(1, sizeof(text)); -		memset(censort, '.', strlen(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); @@ -245,7 +250,7 @@ drawmenu(void)  		}  		x += w;  		for (item = curr; item != next; item = item->right) -			x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">"))); +			x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW(">")));  		if (next) {  			w = TEXTW(">");  			drw_setscheme(drw, scheme[SchemeNorm]); @@ -390,7 +395,7 @@ match(void)  	/* separate input text into tokens to be matched individually */  	for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " "))  		if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv))) -			die("cannot realloc %u bytes:", tokn * sizeof *tokv); +			die("cannot realloc %zu bytes:", tokn * sizeof *tokv);  	len = tokc ? strlen(tokv[0]) : 0;  	matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL; @@ -577,7 +582,7 @@ keypress(XKeyEvent *ev)  	switch(ksym) {  	default:  insert: -		if (!iscntrl(*buf)) +		if (!iscntrl((unsigned char)*buf))  			insert(buf, len);  		break;  	case XK_Delete: @@ -679,9 +684,9 @@ insert:  	case XK_Tab:  		if (!sel)  			return; -		strncpy(text, sel->text, sizeof text - 1); -		text[sizeof text - 1] = '\0'; -		cursor = strlen(text); +		cursor = strnlen(sel->text, sizeof text - 1); +		memcpy(text, sel->text, cursor); +		text[cursor] = '\0';  		match();  		break;  	} @@ -744,11 +749,8 @@ buttonpress(XEvent *e)  	}  	if (ev->button != Button1)  		return; -	/* disabled below, needs to be fixed */ -	/*  	if (ev->state & ~ControlMask)  		return; -	*/  	if (lines > 0) {  		/* vertical list: (ctrl)left-click on item */  		w = mw - x; @@ -807,40 +809,6 @@ buttonpress(XEvent *e)  }  static void -mousemove(XEvent *e) -{ -	struct item *item; -	XPointerMovedEvent *ev = &e->xmotion; -	int x = 0, y = 0, h = bh, w; - -	if (lines > 0) { -		w = mw - x; -		for (item = curr; item != next; item = item->right) { -			y += h; -			if (ev->y >= y && ev->y <= (y + h)) { -				sel = item; -				calcoffsets(); -				drawmenu(); -				return; -			} -		} -	} else if (matches) { -		x += inputw; -		w = TEXTW("<"); -		for (item = curr; item != next; item = item->right) { -			x += w; -			w = MIN(TEXTW(item->text), mw - x - TEXTW(">")); -			if (ev->x >= x && ev->x <= x + w) { -				sel = item; -				calcoffsets(); -				drawmenu(); -				return; -			} -		} -	} -} - -static void  paste(void)  {  	char *p, *q; @@ -861,26 +829,25 @@ paste(void)  static void  readstdin(void)  { -	char buf[sizeof text], *p; -	size_t i, imax = 0, size = 0; -	unsigned int tmpmax = 0; -	if(passwd){ -    	inputw = lines = 0; -    	return; -  	} +	char *p, *line = NULL; +	size_t i, junk, size = 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; fgets(buf, sizeof buf, stdin); i++) { +	for (i = 0; (len = getline(&line, &junk, stdin)) != -1; i++, line = NULL) {  		if (i + 1 >= size / sizeof *items)  			if (!(items = realloc(items, (size += BUFSIZ)))) -				die("cannot realloc %u bytes:", size); -		if ((p = strchr(buf, '\n'))) -			*p = '\0'; -		if (!(items[i].text = strdup(buf))) -			die("cannot strdup %u bytes:", strlen(buf) + 1); -		if (separator && (p = separator_greedy ? -		    strrchr(items[i].text, separator) : strchr(items[i].text, separator))) { +				die("cannot realloc %zu bytes:", size); +		if (line[len - 1] == '\n') +			line[len - 1] = '\0'; +		items[i].text = line; + +		if (separator && (p = sepchr(items[i].text, separator)) != NULL) {  			*p = '\0';  			items[i].text_output = ++p;  		} else { @@ -891,16 +858,11 @@ readstdin(void)  			items[i].text = items[i].text_output;  			items[i].text_output = p;  		} +  		items[i].out = 0; -		drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL); -		if (tmpmax > inputw) { -			inputw = tmpmax; -			imax = i; -		}  	}  	if (items)  		items[i].text = NULL; -	inputw = items ? TEXTW(items[imax].text) : 0;  	lines = MIN(lines, i);  } @@ -921,9 +883,6 @@ run(void)  		case ButtonPress:  			buttonpress(&ev);  			break; -                case MotionNotify: -                        mousemove(&ev); -                        break;  		case Expose:  			if (ev.xexpose.count == 0)  				drw_map(drw, win, 0, 0, mw, mh); @@ -1004,7 +963,7 @@ setup(void)  		/* no focused window is on screen, so use pointer location instead */  		if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du))  			for (i = 0; i < n; i++) -				if (BOOL_INTERSECT(x, y, 1, 1, info[i])) +				if (INTERSECT(x, y, 1, 1, info[i]) != 0)  					break;  		if (centered) { @@ -1035,14 +994,15 @@ setup(void)  			mw = wa.width;  		}  	} -	inputw = MIN(inputw, mw/3); +	promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; +	inputw = mw / 3; /* input width: ~33% of monitor width */  	match();  	/* create menu window */  	swa.override_redirect = True;  	swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;  	swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask | -                         ButtonPressMask | PointerMotionMask; +                         ButtonPressMask;  	win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width,  	                    CopyFromParent, CopyFromParent, CopyFromParent,  	                    CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); @@ -1075,11 +1035,10 @@ setup(void)  static void  usage(void)  { -	fputs("usage: dmenu [-bfirvP] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" -	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-bw width]\n" -	      "             [-nhb color] [-nhf color] [-shb color] [-shf color] [-w windowid]\n" -              "             [-d separator] [-D separator]\n", stderr); -	exit(1); +	die("usage: dmenu [-bfirvP] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" +	    "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n" +            "             [-nhb color] [-nhf color] [-shb color] [-shf color]\n" +	    "             [-d separator] [-D separator] [-h height]");  }  void @@ -1112,22 +1071,22 @@ readxresources(void) {  			colors[SchemeSel][ColFg] = strdup(xval.addr);  		else  			colors[SchemeSel][ColFg] = strdup(colors[SchemeSel][ColFg]); +		if (XrmGetResource(xdb, "dmenu.hibackground", "*", &type, &xval)) +			colors[SchemeNormHighlight][ColBg] = strdup(xval.addr); +		else +			colors[SchemeNormHighlight][ColBg] = strdup(colors[SchemeSel][ColFg]); +		if (XrmGetResource(xdb, "dmenu.hiforeground", "*", &type, &xval)) +			colors[SchemeNormHighlight][ColFg] = strdup(xval.addr); +		else +			colors[SchemeNormHighlight][ColFg] = strdup(colors[SchemeSel][ColFg]);  		if (XrmGetResource(xdb, "dmenu.selhibackground", "*", &type, &xval))  			colors[SchemeSelHighlight][ColBg] = strdup(xval.addr);  		else -			colors[SchemeSelHighlight][ColBg] = strdup(colors[SchemeSel][ColBg]); +			colors[SchemeSelHighlight][ColBg] = strdup(colors[SchemeSel][ColFg]);  		if (XrmGetResource(xdb, "dmenu.selhiforeground", "*", &type, &xval))  			colors[SchemeSelHighlight][ColFg] = strdup(xval.addr);  		else  			colors[SchemeSelHighlight][ColFg] = strdup(colors[SchemeSel][ColFg]); -		if (XrmGetResource(xdb, "dmenu.hibackground", "*", &type, &xval)) -			colors[SchemeNormHighlight][ColBg] = strdup(xval.addr); -		else -			colors[SchemeNormHighlight][ColBg] = strdup(colors[SchemeNorm][ColBg]); -		if (XrmGetResource(xdb, "dmenu.hiforeground", "*", &type, &xval)) -			colors[SchemeNormHighlight][ColFg] = strdup(xval.addr); -		else -			colors[SchemeNormHighlight][ColFg] = strdup(colors[SchemeNorm][ColFg]);  		XrmDestroyDatabase(xdb);  	} @@ -1148,14 +1107,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], "-F"))   /* grabs keyboard before reading stdin */ -			fuzzy = 1; +                else if (!strcmp(argv[i], "-F"))   /* toggles fuzzy matching */ +                        fuzzy = fuzzy ? 0 : 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 (!strcmp(argv[i], "-P"))   /* is the input a password */ +		} else if (!strcmp(argv[i], "-P")) /* is the input a password */  			passwd = 1;                  else if (!strcmp(argv[i], "-r")) /* reject input which results in no match */                          reject_no_match = 1; @@ -1182,22 +1141,24 @@ main(int argc, char *argv[])  			colortemp[2] = argv[++i];  		else if (!strcmp(argv[i], "-sf"))  /* selected foreground color */  			colortemp[3] = argv[++i]; -                else if (!strcmp(argv[i], "-nhb")) /* normal hi background color */ -                        colors[SchemeNormHighlight][ColBg] = argv[++i]; -                else if (!strcmp(argv[i], "-nhf")) /* normal hi foreground color */ -                        colors[SchemeNormHighlight][ColFg] = argv[++i]; -                else if (!strcmp(argv[i], "-shb")) /* selected hi background color */ -                        colors[SchemeSelHighlight][ColBg] = argv[++i]; -                else if (!strcmp(argv[i], "-shf")) /* selected hi foreground color */ -                        colors[SchemeSelHighlight][ColFg] = argv[++i]; +		else if (!strcmp(argv[i], "-nhb")) /* normal hi background color */ +			colortemp[4] = argv[++i]; +		else if (!strcmp(argv[i], "-nhf")) /* normal hi foreground color */ +			colortemp[5] = argv[++i]; +		else if (!strcmp(argv[i], "-shb")) /* selected hi background color */ +			colortemp[6] = argv[++i]; +		else if (!strcmp(argv[i], "-shf")) /* selected hi foreground color */ +			colortemp[7] = argv[++i];  		else if (!strcmp(argv[i], "-w"))   /* embedding window id */  			embed = argv[++i]; +                else if (!strcmp(argv[i], "-bw")) +                        border_width = atoi(argv[++i]); /* border width */  		else if (!strcmp(argv[i], "-d") || /* field separator */ -			(separator_greedy = !strcmp(argv[i], "-D"))) { -                        separator = argv[++i][0]; -                        separator_reverse = argv[i][1] == '|'; -                } else if (!strcmp(argv[i], "-bw")) -			border_width = atoi(argv[++i]); /* border width */ +		         !strcmp(argv[i], "-D")) { +			sepchr = argv[i][1] == 'D' ? strrchr : strchr; +			separator = argv[++i][0]; +			separator_reverse = argv[i][1] == '|'; +		}  		else  			usage(); @@ -1225,6 +1186,14 @@ main(int argc, char *argv[])  	   colors[SchemeSel][ColBg]  = strdup(colortemp[2]);  	if ( colortemp[3])  	   colors[SchemeSel][ColFg]  = strdup(colortemp[3]); +        if ( colortemp[4]) +           colors[SchemeNormHighlight][ColBg] = strdup(colortemp[4]); +        if ( colortemp[5]) +           colors[SchemeNormHighlight][ColFg] = strdup(colortemp[5]); +        if ( colortemp[6]) +           colors[SchemeSelHighlight][ColBg] = strdup(colortemp[6]); +        if ( colortemp[7]) +           colors[SchemeSelHighlight][ColFg] = strdup(colortemp[7]);  	if (!drw_fontset_create(drw, (const char**)fonts, LENGTH(fonts)))  		die("no fonts could be loaded."); @@ -133,19 +133,6 @@ 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; @@ -251,12 +238,10 @@ 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)  { -	char buf[1024]; -	int ty; -	unsigned int ew=0; +	int i, ty, ellipsis_x = 0; +	unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len;  	XftDraw *d = NULL;  	Fnt *usedfont, *curfont, *nextfont; -	size_t i, len;  	int utf8strlen, utf8charlen, render = x || y || w || h;  	long utf8codepoint = 0;  	const char *utf8str; @@ -264,13 +249,17 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp  	FcPattern *fcpattern;  	FcPattern *match;  	XftResult result; -	int charexists = 0; +	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; -	if (!drw || (render && !drw->scheme) || !text || !drw->fonts) +	if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)  		return 0;  	if (!render) { -		w = ~w; +		w = invert ? invert : ~invert;  	} else {  		XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);  		XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); @@ -282,8 +271,10 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp  	}  	usedfont = drw->fonts; +	if (!ellipsis_width && render) +		ellipsis_width = drw_fontset_getwidth(drw, "...");  	while (1) { -		utf8strlen = 0; +		ew = ellipsis_len = utf8strlen = 0;  		utf8str = text;  		nextfont = NULL;  		while (*text) { @@ -291,9 +282,27 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp  			for (curfont = drw->fonts; curfont; curfont = curfont->next) {  				charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);  				if (charexists) { -					if (curfont == usedfont) { +					drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL); +					if (ew + ellipsis_width <= w) { +						/* keep track where the ellipsis still fits */ +						ellipsis_x = x + ew; +						ellipsis_w = w - ew; +						ellipsis_len = utf8strlen; +					} + +					if (ew + tmpw > w) { +						overflow = 1; +						/* called from drw_fontset_getwidth_clamp(): +						 * it wants the width AFTER the overflow +						 */ +						if (!render) +							x += tmpw; +						else +							utf8strlen = ellipsis_len; +					} else if (curfont == usedfont) {  						utf8strlen += utf8charlen;  						text += utf8charlen; +						ew += tmpw;  					} else {  						nextfont = curfont;  					} @@ -301,36 +310,25 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp  				}  			} -			if (!charexists || nextfont) +			if (overflow || !charexists || nextfont)  				break;  			else  				charexists = 0;  		}  		if (utf8strlen) { -			drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL); -			/* shorten text if necessary */ -			for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--) -				drw_font_getexts(usedfont, utf8str, len, &ew, NULL); - -			if (len) { -				memcpy(buf, utf8str, len); -				buf[len] = '\0'; -				if (len < utf8strlen) -					for (i = len; i && i > len - 3; buf[--i] = '.') -						; /* NOP */ - -				if (render) { -					ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; -					XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], -					                  usedfont->xfont, x, ty, (XftChar8 *)buf, len); -				} -				x += ew; -				w -= ew; +			if (render) { +				ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; +				XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], +				                  usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen);  			} +			x += ew; +			w -= ew;  		} +		if (render && overflow) +			drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert); -		if (!*text) { +		if (!*text || overflow) {  			break;  		} else if (nextfont) {  			charexists = 0; @@ -340,6 +338,12 @@ 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; +			} +  			fccharset = FcCharSetCreate();  			FcCharSetAddChar(fccharset, utf8codepoint); @@ -351,7 +355,6 @@ 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); @@ -368,6 +371,8 @@ 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; +no_match:  					usedfont = drw->fonts;  				}  			} @@ -397,6 +402,15 @@ drw_fontset_getwidth(Drw *drw, const char *text)  	return drw_text(drw, 0, 0, 0, 0, 0, text, 0);  } +unsigned int +drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n) +{ +	unsigned int tmp = 0; +	if (drw && drw->fonts && text && n) +		tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n); +	return MIN(n, tmp); +} +  void  drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)  { @@ -35,6 +35,7 @@ void drw_free(Drw *drw);  Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount);  void drw_fontset_free(Fnt* set);  unsigned int drw_fontset_getwidth(Drw *drw, const char *text); +unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n);  void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);  /* Colorscheme abstraction */ diff --git a/patches/dmenu-center-20200111-8cd37e1.diff b/patches/dmenu-center-5.2.diff index af249a6..9401dc5 100644 --- a/patches/dmenu-center-20200111-8cd37e1.diff +++ b/patches/dmenu-center-5.2.diff @@ -1,14 +1,3 @@ -From 8cd37e1ab9e7cb025224aeb3543f1a5be8bceb93 Mon Sep 17 00:00:00 2001 -From: Nihal Jere <nihal@nihaljere.xyz> -Date: Sat, 11 Jan 2020 21:16:08 -0600 -Subject: [PATCH] center patch now has adjustable minimum width - ---- - config.def.h |  2 ++ - dmenu.1      |  3 +++ - dmenu.c      | 39 ++++++++++++++++++++++++++++++++------- - 3 files changed, 37 insertions(+), 7 deletions(-) -  diff --git a/config.def.h b/config.def.h  index 1edb647..88ef264 100644  --- a/config.def.h @@ -37,10 +26,10 @@ index 323f93c..c036baa 100644   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.  diff --git a/dmenu.c b/dmenu.c -index 65f25ce..041c7f8 100644 +index 27b7a30..427fb04 100644  --- a/dmenu.c  +++ b/dmenu.c -@@ -89,6 +89,15 @@ calcoffsets(void) +@@ -96,6 +96,15 @@ calcoffsets(void)   			break;   } @@ -56,7 +45,7 @@ index 65f25ce..041c7f8 100644   static void   cleanup(void)   { -@@ -611,6 +620,7 @@ setup(void) +@@ -636,6 +645,7 @@ setup(void)   	bh = drw->fonts->h + 2;   	lines = MAX(lines, 0);   	mh = (lines + 1) * bh; @@ -64,8 +53,8 @@ index 65f25ce..041c7f8 100644   #ifdef XINERAMA   	i = 0;   	if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { -@@ -637,9 +647,16 @@ setup(void) - 				if (INTERSECT(x, y, 1, 1, info[i])) +@@ -662,9 +672,16 @@ setup(void) + 				if (INTERSECT(x, y, 1, 1, info[i]) != 0)   					break;  -		x = info[i].x_org; @@ -84,7 +73,7 @@ index 65f25ce..041c7f8 100644   		XFree(info);   	} else   #endif -@@ -647,11 +664,17 @@ setup(void) +@@ -672,9 +689,16 @@ setup(void)   		if (!XGetWindowAttributes(dpy, parentwin, &wa))   			die("could not get embedding window attributes: 0x%lx",   			    parentwin); @@ -102,11 +91,9 @@ index 65f25ce..041c7f8 100644  +			mw = wa.width;  +		}   	} --	promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; - 	inputw = MIN(inputw, mw/3); - 	match(); -  -@@ -709,6 +732,8 @@ main(int argc, char *argv[]) + 	promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; + 	inputw = mw / 3; /* input width: ~33% of monitor width */ +@@ -733,6 +757,8 @@ main(int argc, char *argv[])   			topbar = 0;   		else if (!strcmp(argv[i], "-f"))   /* grabs keyboard before reading stdin */   			fast = 1; @@ -115,6 +102,3 @@ index 65f25ce..041c7f8 100644   		else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */   			fstrncmp = strncasecmp;   			fstrstr = cistrstr; ---  -2.24.1 - diff --git a/patches/dmenu-fuzzyhighlight-4.9.diff b/patches/dmenu-fuzzyhighlight-caseinsensitive-4.9.diff index 58d5c6f..026b3d2 100644 --- a/patches/dmenu-fuzzyhighlight-4.9.diff +++ b/patches/dmenu-fuzzyhighlight-caseinsensitive-4.9.diff @@ -1,10 +1,19 @@ -Author: Chris Noxz <chris@noxz.tech> -note: This patch is meant to be used together with fuzzymatch +From 2de2780bef245ae44d677abd20c589160f0d984b Mon Sep 17 00:00:00 2001 +From: Oleh Kopeykin <olehkopeykin@yandex.by> +Date: Sun, 5 Feb 2023 01:15:35 +0300 +Subject: [PATCH] Adds the fuzzyhighlight patch -diff -upN dmenu-4.9/config.def.h dmenu-4.9-fuzzyhighlight/config.def.h ---- dmenu-4.9/config.def.h	2019-02-02 13:55:02.000000000 +0100 -+++ dmenu-4.9-fuzzyhighlight/config.def.h	2020-04-04 10:26:36.990890854 +0200 -@@ -11,6 +11,8 @@ static const char *colors[SchemeLast][2] +--- + config.def.h |  2 ++ + dmenu.1      | 20 ++++++++++++++++++ + dmenu.c      | 57 +++++++++++++++++++++++++++++++++++++++++++++++++--- + 3 files changed, 76 insertions(+), 3 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 51612b9..0103bda 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -12,6 +12,8 @@ static const char *colors[SchemeLast][2] = {   	/*     fg         bg       */   	[SchemeNorm] = { "#bbbbbb", "#222222" },   	[SchemeSel] = { "#eeeeee", "#005577" }, @@ -13,9 +22,10 @@ diff -upN dmenu-4.9/config.def.h dmenu-4.9-fuzzyhighlight/config.def.h   	[SchemeOut] = { "#000000", "#00ffff" },   };   /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ -diff -upN dmenu-4.9/dmenu.1 dmenu-4.9-fuzzyhighlight/dmenu.1 ---- dmenu-4.9/dmenu.1	2019-02-02 13:55:02.000000000 +0100 -+++ dmenu-4.9-fuzzyhighlight/dmenu.1	2020-04-04 10:30:16.430054933 +0200 +diff --git a/dmenu.1 b/dmenu.1 +index 323f93c..472b179 100644 +--- a/dmenu.1 ++++ b/dmenu.1  @@ -20,6 +20,14 @@ dmenu \- dynamic menu   .IR color ]   .RB [ \-sf @@ -50,10 +60,11 @@ diff -upN dmenu-4.9/dmenu.1 dmenu-4.9-fuzzyhighlight/dmenu.1   .B \-v   prints version information to stdout, then exits.   .TP -diff -upN dmenu-4.9/dmenu.c dmenu-4.9-fuzzyhighlight/dmenu.c ---- dmenu-4.9/dmenu.c	2019-02-02 13:55:02.000000000 +0100 -+++ dmenu-4.9-fuzzyhighlight/dmenu.c	2020-04-04 10:27:43.888026309 +0200 -@@ -26,7 +26,9 @@ +diff --git a/dmenu.c b/dmenu.c +index 96ddc98..442d707 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -27,7 +27,9 @@   #define TEXTW(X)              (drw_fontset_getwidth(drw, (X)) + lrpad)   /* enums */ @@ -64,7 +75,7 @@ diff -upN dmenu-4.9/dmenu.c dmenu-4.9-fuzzyhighlight/dmenu.c   struct item {   	char *text; -@@ -113,9 +115,49 @@ cistrstr(const char *s, const char *sub) +@@ -115,9 +117,47 @@ cistrstr(const char *s, const char *sub)   	return NULL;   } @@ -82,19 +93,17 @@ diff -upN dmenu-4.9/dmenu.c dmenu-4.9-fuzzyhighlight/dmenu.c  +	                   ? SchemeSelHighlight  +	                   : SchemeNormHighlight]);  +	for (i = 0, highlight = item->text; *highlight && text[i];) { -+		if (*highlight == text[i]) { ++		if (!fstrncmp(&text[i], highlight, 1)) { ++			c = highlight[1]; ++			highlight[1] = '\0'; ++  +			/* get indentation */ -+			c = *highlight; -+			*highlight = '\0';  +			indent = TEXTW(item->text); -+			*highlight = c;  +  +			/* highlight character */ -+			c = highlight[1]; -+			highlight[1] = '\0';  +			drw_text(  +				drw, -+				x + indent - (lrpad / 2), ++				x + indent - lrpad,  +				y,  +				MIN(maxw - indent, TEXTW(highlight) - lrpad),  +				bh, 0, highlight, 0 @@ -114,7 +123,7 @@ diff -upN dmenu-4.9/dmenu.c dmenu-4.9-fuzzyhighlight/dmenu.c   	if (item == sel)   		drw_setscheme(drw, scheme[SchemeSel]);   	else if (item->out) -@@ -123,7 +165,9 @@ drawitem(struct item *item, int x, int y +@@ -125,7 +165,9 @@ drawitem(struct item *item, int x, int y, int w)   	else   		drw_setscheme(drw, scheme[SchemeNorm]); @@ -125,7 +134,7 @@ diff -upN dmenu-4.9/dmenu.c dmenu-4.9-fuzzyhighlight/dmenu.c   }   static void -@@ -683,7 +727,8 @@ static void +@@ -770,7 +812,8 @@ static void   usage(void)   {   	fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" @@ -135,7 +144,7 @@ diff -upN dmenu-4.9/dmenu.c dmenu-4.9-fuzzyhighlight/dmenu.c   	exit(1);   } -@@ -724,6 +769,14 @@ main(int argc, char *argv[]) +@@ -813,6 +856,14 @@ main(int argc, char *argv[])   			colors[SchemeSel][ColBg] = argv[++i];   		else if (!strcmp(argv[i], "-sf"))  /* selected foreground color */   			colors[SchemeSel][ColFg] = argv[++i]; @@ -150,3 +159,6 @@ diff -upN dmenu-4.9/dmenu.c dmenu-4.9-fuzzyhighlight/dmenu.c   		else if (!strcmp(argv[i], "-w"))   /* embedding window id */   			embed = argv[++i];   		else +--  +2.39.1 + diff --git a/patches/dmenu-lineheight-5.0.diff b/patches/dmenu-lineheight-5.2.diff index 3b0df3d..a5e8468 100644 --- a/patches/dmenu-lineheight-5.0.diff +++ b/patches/dmenu-lineheight-5.2.diff @@ -52,10 +52,10 @@ index 323f93c..f2a82b4 100644   dmenu is displayed on the monitor number supplied. Monitor numbers are starting   from 0.  diff --git a/dmenu.c b/dmenu.c -index 65f25ce..f2a4047 100644 +index e7be8af..82b204b 100644  --- a/dmenu.c  +++ b/dmenu.c -@@ -131,7 +131,7 @@ drawmenu(void) +@@ -148,7 +148,7 @@ drawmenu(void)   {   	unsigned int curpos;   	struct item *item; @@ -64,7 +64,7 @@ index 65f25ce..f2a4047 100644   	drw_setscheme(drw, scheme[SchemeNorm]);   	drw_rect(drw, 0, 0, mw, mh, 1, 1); -@@ -148,7 +148,7 @@ drawmenu(void) +@@ -165,7 +165,7 @@ drawmenu(void)   	curpos = TEXTW(text) - TEXTW(&text[cursor]);   	if ((curpos += lrpad / 2 - 1) < w) {   		drw_setscheme(drw, scheme[SchemeNorm]); @@ -73,7 +73,7 @@ index 65f25ce..f2a4047 100644   	}   	if (lines > 0) { -@@ -609,6 +609,7 @@ setup(void) +@@ -630,6 +630,7 @@ setup(void)   	/* calculate menu geometry */   	bh = drw->fonts->h + 2; @@ -81,16 +81,16 @@ index 65f25ce..f2a4047 100644   	lines = MAX(lines, 0);   	mh = (lines + 1) * bh;   #ifdef XINERAMA -@@ -689,7 +690,7 @@ setup(void) +@@ -710,7 +711,7 @@ setup(void)   static void   usage(void)   { --	fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" -+	fputs("usage: dmenu [-bfiv] [-l lines] [-h height] [-p prompt] [-fn font] [-m monitor]\n" - 	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); - 	exit(1); +-	die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" ++	die("usage: dmenu [-bfiv] [-l lines] [-h height] [-p prompt] [-fn font] [-m monitor]\n" + 	    "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]");   } -@@ -717,6 +718,10 @@ main(int argc, char *argv[]) +  +@@ -737,6 +738,10 @@ main(int argc, char *argv[])   		/* these options take one argument */   		else if (!strcmp(argv[i], "-l"))   /* number of lines in vertical list */   			lines = atoi(argv[++i]); @@ -102,5 +102,5 @@ index 65f25ce..f2a4047 100644   			mon = atoi(argv[++i]);   		else if (!strcmp(argv[i], "-p"))   /* adds prompt to left of input field */  --  -2.29.2 +2.38.1 diff --git a/patches/dmenu-mousesupport-5.1.diff b/patches/dmenu-mousesupport-5.2.diff index 49824ba..eaacea4 100644 --- a/patches/dmenu-mousesupport-5.1.diff +++ b/patches/dmenu-mousesupport-5.2.diff @@ -1,8 +1,8 @@  diff --git a/dmenu.c b/dmenu.c -index d95e6c6..75a79d0 100644 +index 7cf253b..d276a94 100644  --- a/dmenu.c  +++ b/dmenu.c -@@ -518,6 +518,119 @@ draw: +@@ -528,6 +528,119 @@ draw:   	drawmenu();   } @@ -122,7 +122,7 @@ index d95e6c6..75a79d0 100644   static void   paste(void)   { -@@ -579,6 +692,9 @@ run(void) +@@ -582,6 +695,9 @@ run(void)   				break;   			cleanup();   			exit(1); @@ -132,7 +132,7 @@ index d95e6c6..75a79d0 100644   		case Expose:   			if (ev.xexpose.count == 0)   				drw_map(drw, win, 0, 0, mw, mh); -@@ -676,7 +792,8 @@ setup(void) +@@ -679,7 +795,8 @@ setup(void)   	/* create menu window */   	swa.override_redirect = True;   	swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; diff --git a/patches/dmenu-mousesupporthoverbgcol-5.0.diff b/patches/dmenu-mousesupporthoverbgcol-5.0.diff deleted file mode 100644 index 1fb7d41..0000000 --- a/patches/dmenu-mousesupporthoverbgcol-5.0.diff +++ /dev/null @@ -1,184 +0,0 @@ -Only in .: config.h -diff -up ../dmenu-5.0/dmenu.c ./dmenu.c ---- ../dmenu-5.0/dmenu.c	Wed Sep  2 18:37:07 2020 -+++ ./dmenu.c	Wed Nov  4 15:25:27 2020 -@@ -501,6 +501,156 @@ draw: - } -  - static void -+buttonpress(XEvent *e) -+{ -+	struct item *item; -+	XButtonPressedEvent *ev = &e->xbutton; -+	int x = 0, y = 0, h = bh, w; -+ -+	if (ev->window != win) -+		return; -+ -+	/* right-click: exit */ -+	if (ev->button == Button3) -+		exit(1); -+ -+	if (prompt && *prompt) -+		x += promptw; -+ -+	/* input field */ -+	w = (lines > 0 || !matches) ? mw - x : inputw; -+ -+	/* left-click on input: clear input, -+	 * NOTE: if there is no left-arrow the space for < is reserved so -+	 *       add that to the input width */ -+	if (ev->button == Button1 && -+	   ((lines <= 0 && ev->x >= 0 && ev->x <= x + w + -+	   ((!prev || !curr->left) ? TEXTW("<") : 0)) || -+	   (lines > 0 && ev->y >= y && ev->y <= y + h))) { -+		insert(NULL, -cursor); -+		drawmenu(); -+		return; -+	} -+	/* middle-mouse click: paste selection */ -+	if (ev->button == Button2) { -+		XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, -+		                  utf8, utf8, win, CurrentTime); -+		drawmenu(); -+		return; -+	} -+	/* scroll up */ -+	if (ev->button == Button4 && prev) { -+		sel = curr = prev; -+		calcoffsets(); -+		drawmenu(); -+		return; -+	} -+	/* scroll down */ -+	if (ev->button == Button5 && next) { -+		sel = curr = next; -+		calcoffsets(); -+		drawmenu(); -+		return; -+	} -+	if (ev->button != Button1) -+		return; -+	/* disabled below, needs to be fixed */ -+	/* -+	if (ev->state & ~ControlMask) -+		return; -+	*/ -+	if (lines > 0) { -+		/* vertical list: (ctrl)left-click on item */ -+		w = mw - x; -+		for (item = curr; item != next; item = item->right) { -+			y += h; -+			if (ev->y >= y && ev->y <= (y + h)) { -+				puts(item->text); -+				if (!(ev->state & ControlMask)) -+					exit(0); -+				sel = item; -+				if (sel) { -+					sel->out = 1; -+					drawmenu(); -+				} -+				return; -+			} -+		} -+	} else if (matches) { -+		/* left-click on left arrow */ -+		x += inputw; -+		w = TEXTW("<"); -+		if (prev && curr->left) { -+			if (ev->x >= x && ev->x <= x + w) { -+				sel = curr = prev; -+				calcoffsets(); -+				drawmenu(); -+				return; -+			} -+		} -+		/* horizontal list: (ctrl)left-click on item */ -+		for (item = curr; item != next; item = item->right) { -+			x += w; -+			w = MIN(TEXTW(item->text), mw - x - TEXTW(">")); -+			if (ev->x >= x && ev->x <= x + w) { -+				puts(item->text); -+				if (!(ev->state & ControlMask)) -+					exit(0); -+				sel = item; -+				if (sel) { -+					sel->out = 1; -+					drawmenu(); -+				} -+				return; -+			} -+		} -+		/* left-click on right arrow */ -+		w = TEXTW(">"); -+		x = mw - w; -+		if (next && ev->x >= x && ev->x <= x + w) { -+			sel = curr = next; -+			calcoffsets(); -+			drawmenu(); -+			return; -+		} -+	} -+} -+ -+static void -+mousemove(XEvent *e) -+{ -+	struct item *item; -+	XPointerMovedEvent *ev = &e->xmotion; -+	int x = 0, y = 0, h = bh, w; -+ -+	if (lines > 0) { -+		w = mw - x; -+		for (item = curr; item != next; item = item->right) { -+			y += h; -+			if (ev->y >= y && ev->y <= (y + h)) { -+				sel = item; -+				calcoffsets(); -+				drawmenu(); -+				return; -+			} -+		} -+	} else if (matches) { -+		x += inputw; -+		w = TEXTW("<"); -+		for (item = curr; item != next; item = item->right) { -+			x += w; -+			w = MIN(TEXTW(item->text), mw - x - TEXTW(">")); -+			if (ev->x >= x && ev->x <= x + w) { -+				sel = item; -+				calcoffsets(); -+				drawmenu(); -+				return; -+			} -+		} -+	} -+} -+ -+static void - paste(void) - { - 	char *p, *q; -@@ -561,6 +711,12 @@ run(void) - 				break; - 			cleanup(); - 			exit(1); -+		case ButtonPress: -+			buttonpress(&ev); -+			break; -+		case MotionNotify: -+			mousemove(&ev); -+			break; - 		case Expose: - 			if (ev.xexpose.count == 0) - 				drw_map(drw, win, 0, 0, mw, mh); -@@ -658,7 +814,8 @@ setup(void) - 	/* create menu window */ - 	swa.override_redirect = True; - 	swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; --	swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; -+	swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask | -+	                 ButtonPressMask | PointerMotionMask; - 	win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0, - 	                    CopyFromParent, CopyFromParent, CopyFromParent, - 	                    CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); diff --git a/patches/dmenu-separator-20210904-d78ff08.diff b/patches/dmenu-separator-5.2.patch index be30420..09f41cb 100644 --- a/patches/dmenu-separator-20210904-d78ff08.diff +++ b/patches/dmenu-separator-5.2.patch @@ -1,3 +1,13 @@ +From db596234b244382e984228791e840190d82967ea Mon Sep 17 00:00:00 2001 +From: NRK <nrk@disroot.org> +Date: Fri, 3 Sep 2021 11:11:14 +0600 +Subject: [PATCH] patch: seperator + +--- + dmenu.1 | 12 ++++++++++++ + dmenu.c | 31 +++++++++++++++++++++++++++---- + 2 files changed, 39 insertions(+), 4 deletions(-) +  diff --git a/dmenu.1 b/dmenu.1  index 323f93c..d511148 100644  --- a/dmenu.1 @@ -29,10 +39,10 @@ index 323f93c..d511148 100644   dmenu is completely controlled by the keyboard.  Items are selected using the   arrow keys, page up, page down, home, and end.  diff --git a/dmenu.c b/dmenu.c -index 98507d9..82227c8 100644 +index 7cf253b..a8eb321 100644  --- a/dmenu.c  +++ b/dmenu.c -@@ -30,12 +30,16 @@ enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ +@@ -30,12 +30,15 @@ enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */   struct item {   	char *text; @@ -43,13 +53,21 @@ index 98507d9..82227c8 100644   static char text[BUFSIZ] = "";   static char *embed; -+static char separator; -+static int separator_greedy; -+static int separator_reverse; ++static char separator, separator_reverse; ++static char * (*sepchr)(const char *, int);   static int bh, mw, mh;   static int inputw = 0, promptw;   static int lrpad; /* sum of left and right padding */ -@@ -473,7 +477,7 @@ insert: +@@ -105,7 +108,7 @@ cleanup(void) + 	for (i = 0; i < SchemeLast; i++) + 		free(scheme[i]); + 	for (i = 0; items && items[i].text; ++i) +-		free(items[i].text); ++		free(separator_reverse ? items[i].text_output : items[i].text); + 	free(items); + 	drw_free(drw); + 	XSync(dpy, False); +@@ -490,7 +493,7 @@ insert:   		break;   	case XK_Return:   	case XK_KP_Enter: @@ -58,12 +76,21 @@ index 98507d9..82227c8 100644   		if (!(ev->state & ControlMask)) {   			cleanup();   			exit(0); -@@ -545,6 +549,18 @@ readstdin(void) - 			*p = '\0'; - 		if (!(items[i].text = strdup(buf))) - 			die("cannot strdup %u bytes:", strlen(buf) + 1); -+		if (separator && (p = separator_greedy ? -+		    strrchr(items[i].text, separator) : strchr(items[i].text, separator))) { +@@ -549,7 +552,7 @@ paste(void) + static void + readstdin(void) + { +-	char *line = NULL; ++	char *p, *line = NULL; + 	size_t i, junk, size = 0; + 	ssize_t len; +  +@@ -561,6 +564,19 @@ readstdin(void) + 		if (line[len - 1] == '\n') + 			line[len - 1] = '\0'; + 		items[i].text = line; ++ ++		if (separator && (p = sepchr(items[i].text, separator)) != NULL) {  +			*p = '\0';  +			items[i].text_output = ++p;  +		} else { @@ -74,28 +101,33 @@ index 98507d9..82227c8 100644  +			items[i].text = items[i].text_output;  +			items[i].text_output = p;  +		} ++   		items[i].out = 0; - 		drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL); - 		if (tmpmax > inputw) { -@@ -701,7 +717,8 @@ static void + 	} + 	if (items) +@@ -711,7 +727,8 @@ static void   usage(void)   { - 	fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" --	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); -+	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n" -+	      "             [-d separator] [-D separator]\n", stderr); - 	exit(1); + 	die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" +-	    "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]"); ++	    "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n" ++	    "             [-d separator] [-D separator]");   } -@@ -744,6 +761,11 @@ main(int argc, char *argv[]) + int +@@ -753,6 +770,12 @@ main(int argc, char *argv[])   			colors[SchemeSel][ColFg] = argv[++i];   		else if (!strcmp(argv[i], "-w"))   /* embedding window id */   			embed = argv[++i];  +		else if (!strcmp(argv[i], "-d") || /* field separator */ -+		         (separator_greedy = !strcmp(argv[i], "-D"))) { ++		         !strcmp(argv[i], "-D")) { ++			sepchr = argv[i][1] == 'D' ? strrchr : strchr;  +			separator = argv[++i][0];  +			separator_reverse = argv[i][1] == '|';  +		}   		else   			usage(); +--  +2.35.1 + @@ -6,18 +6,9 @@  #include "util.h" -void * -ecalloc(size_t nmemb, size_t size) -{ -	void *p; - -	if (!(p = calloc(nmemb, size))) -		die("calloc:"); -	return p; -} -  void -die(const char *fmt, ...) { +die(const char *fmt, ...) +{  	va_list ap;  	va_start(ap, fmt); @@ -33,3 +24,13 @@ die(const char *fmt, ...) {  	exit(1);  } + +void * +ecalloc(size_t nmemb, size_t size) +{ +	void *p; + +	if (!(p = calloc(nmemb, size))) +		die("calloc:"); +	return p; +}  | 
