summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--config.def.h15
-rw-r--r--config.h34
-rw-r--r--config.mk7
-rw-r--r--dmenu-5.1.diff3199
-rw-r--r--dmenu.151
-rw-r--r--dmenu.c570
-rw-r--r--drw.c102
-rw-r--r--drw.h1
-rw-r--r--patches/dmenu-borderoption-20200217-bf60a1e.diff46
-rw-r--r--patches/dmenu-center-20200111-8cd37e1.diff120
-rw-r--r--patches/dmenu-fuzzyhighlight-4.9.diff152
-rw-r--r--patches/dmenu-fuzzymatch-4.9.diff163
-rw-r--r--patches/dmenu-lineheight-5.0.diff106
-rw-r--r--patches/dmenu-mousesupport-5.1.diff144
-rw-r--r--patches/dmenu-mousesupporthoverbgcol-5.0.diff184
-rw-r--r--patches/dmenu-password-5.0.diff103
-rw-r--r--patches/dmenu-rejectnomatch-4.7.diff82
-rw-r--r--patches/dmenu-separator-20210904-d78ff08.diff101
-rw-r--r--patches/dmenu-xresources-4.9.diff126
-rw-r--r--util.c23
21 files changed, 133 insertions, 5199 deletions
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..1edb647 100644
--- a/config.def.h
+++ b/config.def.h
@@ -2,33 +2,22 @@
/* 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[] = {
+static const char *fonts[] = {
"monospace:size=10"
};
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" },
- [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.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;
diff --git a/config.mk b/config.mk
index 56427e7..566348b 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
# dmenu version
-VERSION = 5.1
+VERSION = 5.2
# paths
PREFIX = /usr/local
@@ -17,14 +17,15 @@ FREETYPELIBS = -lfontconfig -lXft
FREETYPEINC = /usr/include/freetype2
# OpenBSD (uncomment)
#FREETYPEINC = $(X11INC)/freetype2
+#MANPREFIX = ${PREFIX}/man
# includes and libs
INCS = -I$(X11INC) -I$(FREETYPEINC)
-LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lm
+LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS)
# flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS)
-CFLAGS = -std=c99 -pedantic -Wall -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__
diff --git a/dmenu.1 b/dmenu.1
index 1602793..323f93c 100644
--- a/dmenu.1
+++ b/dmenu.1
@@ -3,11 +3,9 @@
dmenu \- dynamic menu
.SH SYNOPSIS
.B dmenu
-.RB [ \-bFfirvP ]
+.RB [ \-bfiv ]
.RB [ \-l
.IR lines ]
-.RB [ \-h
-.IR height ]
.RB [ \-m
.IR monitor ]
.RB [ \-p
@@ -22,20 +20,8 @@ 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
@@ -54,12 +40,6 @@ 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.
@@ -67,18 +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
-.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.
@@ -104,31 +75,11 @@ 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 d304e3a..7cf253b 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -1,7 +1,6 @@
/* 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>
@@ -16,7 +15,6 @@
#include <X11/extensions/Xinerama.h>
#endif
#include <X11/Xft/Xft.h>
-#include <X11/Xresource.h>
#include "drw.h"
#include "util.h"
@@ -24,33 +22,23 @@
/* 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, SchemeNormHighlight, SchemeSelHighlight,
- SchemeOut, SchemeLast }; /* color schemes */
-
+enum { SchemeNorm, SchemeSel, 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, passwd = 0;
+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;
@@ -65,15 +53,18 @@ 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;
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,22 +89,13 @@ 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;
}
-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)
{
@@ -122,6 +104,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(items[i].text);
+ free(items);
drw_free(drw);
XSync(dpy, False);
XCloseDisplay(dpy);
@@ -145,49 +130,9 @@ 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)
@@ -195,9 +140,7 @@ drawitem(struct item *item, int x, int y, int w)
else
drw_setscheme(drw, scheme[SchemeNorm]);
- r = drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0);
- drawhighlights(item, x, y, w);
- return r;
+ return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0);
}
static void
@@ -205,8 +148,7 @@ drawmenu(void)
{
unsigned int curpos;
struct item *item;
- int x = 0, y = 0, fh = drw->fonts->h, w;
- char *censort;
+ int x = 0, y = 0, w;
drw_setscheme(drw, scheme[SchemeNorm]);
drw_rect(drw, 0, 0, mw, mh, 1, 1);
@@ -218,17 +160,12 @@ drawmenu(void)
/* draw input field */
w = (lines > 0 || !matches) ? mw - x : inputw;
drw_setscheme(drw, scheme[SchemeNorm]);
- 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);
+ 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 + (bh - fh) / 2, 2, fh - 4, 1, 0);
+ drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0);
}
if (lines > 0) {
@@ -245,7 +182,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]);
@@ -290,94 +227,9 @@ 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;
@@ -390,7 +242,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;
@@ -434,26 +286,12 @@ 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
@@ -577,7 +415,7 @@ keypress(XKeyEvent *ev)
switch(ksym) {
default:
insert:
- if (!iscntrl(*buf))
+ if (!iscntrl((unsigned char)*buf))
insert(buf, len);
break;
case XK_Delete:
@@ -652,7 +490,7 @@ insert:
break;
case XK_Return:
case XK_KP_Enter:
- puts((sel && !(ev->state & ShiftMask)) ? sel->text_output : text);
+ puts((sel && !(ev->state & ShiftMask)) ? sel->text : text);
if (!(ev->state & ControlMask)) {
cleanup();
exit(0);
@@ -679,9 +517,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;
}
@@ -691,156 +529,6 @@ 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;
@@ -861,46 +549,22 @@ 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 *line = NULL;
+ size_t i, junk, size = 0;
+ ssize_t len;
/* 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))) {
- *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;
- }
+ die("cannot realloc %zu bytes:", size);
+ if (line[len - 1] == '\n')
+ line[len - 1] = '\0';
+ items[i].text = line;
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);
}
@@ -918,12 +582,6 @@ 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);
@@ -964,23 +622,16 @@ setup(void)
int a, di, n, area = 0;
#endif
/* init appearance */
- 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]);
- }
+ for (j = 0; j < SchemeLast; j++)
+ scheme[j] = drw_scm_create(drw, colors[j], 2);
clip = XInternAtom(dpy, "CLIPBOARD", False);
utf8 = XInternAtom(dpy, "UTF8_STRING", False);
/* 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))) {
@@ -1004,19 +655,12 @@ 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) {
- 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;
- }
-
+ x = info[i].x_org;
+ y = info[i].y_org + (topbar ? 0 : info[i].height - mh);
+ mw = info[i].width;
XFree(info);
} else
#endif
@@ -1024,30 +668,21 @@ setup(void)
if (!XGetWindowAttributes(dpy, parentwin, &wa))
die("could not get embedding window attributes: 0x%lx",
parentwin);
-
- 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;
- }
+ x = 0;
+ y = topbar ? 0 : wa.height - mh;
+ 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;
- win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width,
+ swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
+ win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
CopyFromParent, CopyFromParent, CopyFromParent,
CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
- if (border_width)
- XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel);
XSetClassHint(dpy, win, &ch);
@@ -1075,62 +710,8 @@ 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);
-}
-
-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);
- }
+ die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
+ " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]");
}
int
@@ -1148,56 +729,30 @@ 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 (!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)
+ } 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 */
- tempfonts = argv[++i];
+ fonts[0] = argv[++i];
else if (!strcmp(argv[i], "-nb")) /* normal background color */
- colortemp[0] = argv[++i];
+ colors[SchemeNorm][ColBg] = argv[++i];
else if (!strcmp(argv[i], "-nf")) /* normal foreground color */
- colortemp[1] = argv[++i];
+ colors[SchemeNorm][ColFg] = argv[++i];
else if (!strcmp(argv[i], "-sb")) /* selected background color */
- colortemp[2] = argv[++i];
+ colors[SchemeSel][ColBg] = 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];
+ 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 if (!strcmp(argv[i], "-bw"))
- border_width = atoi(argv[++i]); /* border width */
else
usage();
@@ -1213,23 +768,8 @@ 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);
- 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)))
+ if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
die("no fonts could be loaded.");
-
- free(fonts[0]);
lrpad = drw->fonts->h;
#ifdef __OpenBSD__
diff --git a/drw.c b/drw.c
index db9284c..a58a2b4 100644
--- a/drw.c
+++ b/drw.c
@@ -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)
{
diff --git a/drw.h b/drw.h
index 4c67419..fd7631b 100644
--- a/drw.h
+++ b/drw.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-borderoption-20200217-bf60a1e.diff b/patches/dmenu-borderoption-20200217-bf60a1e.diff
deleted file mode 100644
index b9b5726..0000000
--- a/patches/dmenu-borderoption-20200217-bf60a1e.diff
+++ /dev/null
@@ -1,46 +0,0 @@
-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
deleted file mode 100644
index af249a6..0000000
--- a/patches/dmenu-center-20200111-8cd37e1.diff
+++ /dev/null
@@ -1,120 +0,0 @@
-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
deleted file mode 100644
index 58d5c6f..0000000
--- a/patches/dmenu-fuzzyhighlight-4.9.diff
+++ /dev/null
@@ -1,152 +0,0 @@
-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
deleted file mode 100644
index 9fd206d..0000000
--- a/patches/dmenu-fuzzymatch-4.9.diff
+++ /dev/null
@@ -1,163 +0,0 @@
-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
deleted file mode 100644
index 3b0df3d..0000000
--- a/patches/dmenu-lineheight-5.0.diff
+++ /dev/null
@@ -1,106 +0,0 @@
-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
deleted file mode 100644
index 49824ba..0000000
--- a/patches/dmenu-mousesupport-5.1.diff
+++ /dev/null
@@ -1,144 +0,0 @@
-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
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-password-5.0.diff b/patches/dmenu-password-5.0.diff
deleted file mode 100644
index 7a187b9..0000000
--- a/patches/dmenu-password-5.0.diff
+++ /dev/null
@@ -1,103 +0,0 @@
-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
deleted file mode 100644
index 329ab1d..0000000
--- a/patches/dmenu-rejectnomatch-4.7.diff
+++ /dev/null
@@ -1,82 +0,0 @@
-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
deleted file mode 100644
index be30420..0000000
--- a/patches/dmenu-separator-20210904-d78ff08.diff
+++ /dev/null
@@ -1,101 +0,0 @@
-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
deleted file mode 100644
index 267fb0a..0000000
--- a/patches/dmenu-xresources-4.9.diff
+++ /dev/null
@@ -1,126 +0,0 @@
-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/util.c b/util.c
index fe044fc..96b82c9 100644
--- a/util.c
+++ b/util.c
@@ -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;
+}