diff options
| author | zachir <zachir@librem.one> | 2022-05-17 12:04:42 -0500 | 
|---|---|---|
| committer | zachir <zachir@librem.one> | 2022-05-17 12:04:42 -0500 | 
| commit | ea51498bfdc1eae6129905f5c4ce44c36b233fe8 (patch) | |
| tree | d3ad5c91dd6a25b2c8a638e6104b08be6e4a7243 | |
| parent | da847c69d538d38e975bbeeec2b76084d8245850 (diff) | |
have patch not create config.h
| -rw-r--r-- | dmenu-zir-5.0.diff | 1049 | 
1 files changed, 806 insertions, 243 deletions
diff --git a/dmenu-zir-5.0.diff b/dmenu-zir-5.0.diff index 351140e..a7ba6b0 100644 --- a/dmenu-zir-5.0.diff +++ b/dmenu-zir-5.0.diff @@ -1,69 +1,134 @@  diff --git a/config.def.h b/config.def.h -index 1edb647..2140b85 100644 +index 1edb647..24cbb58 100644  --- a/config.def.h  +++ b/config.def.h -@@ -3,18 +3,21 @@ +@@ -2,22 +2,43 @@ + /* 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     */ ++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[] = { -+static char *fonts[] = { - 	"monospace:size=10" + static const char *fonts[] = { +-	"monospace:size=10" ++	"monospace:size=10", ++        "mononoki Nerd Font:size=12",   };   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] = { ++static const char *colors[SchemeLast][10] = {   	/*     fg         bg       */ - 	[SchemeNorm] = { "#bbbbbb", "#222222" }, - 	[SchemeSel] = { "#eeeeee", "#005577" }, -+	[SchemeSelHighlight] = { "#ffc978", "#005577" }, -+	[SchemeNormHighlight] = { "#ffc978", "#222222" }, - 	[SchemeOut] = { "#000000", "#00ffff" }, +-	[SchemeNorm] = { "#bbbbbb", "#222222" }, +-	[SchemeSel] = { "#eeeeee", "#005577" }, +-	[SchemeOut] = { "#000000", "#00ffff" }, ++        [SchemeNorm] = { "#bbbbbb", "#222222", "#222222" }, ++        [SchemeSel] = { "#eeeeee", "#005577", "#005577" }, ++        [SchemeNormHighlight] = { "#ffc978", "#222222", "#222222" }, ++        [SchemeSelHighlight] = { "#ffc978", "#005577", "#005577" }, ++        [SchemeOut] = { "#000000", "#00ffff", "#00ffff" }, ++        [SchemeHighlight] = {"#f1fa8c", "#596377", "#3E485B"}, ++        [SchemeHover] = {"#ffffff", "#353D4B", "#3E485B"}, ++        [SchemeGreen] = {"#ffffff", "#52E067", "#41b252"}, ++        [SchemeRed] = {"#ffffff", "#e05252", "#c24343"}, ++        [SchemeYellow] = {"#ffffff", "#e0c452", "#bca33f"}, ++        [SchemeBlue] = {"#ffffff", "#5280e0", "#3a62b3"}, ++        [SchemePurple] = {"#ffffff", "#9952e0", "#7439b0"},   };   /* -l option; if nonzero, dmenu uses vertical list with given number of lines */   static unsigned int lines      = 0; -+static unsigned int lineheight = 0;         /* -h option; minimum height of a menu line     */ ++static unsigned int lineheight = 0; /* -h option; minimum height of a menu line */ ++static unsigned int min_lineheight = 8; ++static int sely = 0; ++static int commented = 0; ++static int animated = 0;   /*    * Characters not considered part of a word while deleting words -diff --git a/config.h b/config.h -new file mode 100644 -index 0000000..8bd9346 ---- /dev/null -+++ b/config.h -@@ -0,0 +1,27 @@ -+/* See LICENSE file for copyright and license details. */ -+/* Default settings; can be overriden by command line. */ +  * for example: " /?\"&[]" +  */ + static const char worddelimiters[] = " ";  + -+static int topbar = 1;                      /* -b  option; if 0, dmenu appears at bottom     */ -+/* -fn option overrides fonts[0]; default X11 font or font set */ -+static char *fonts[] = { -+	"mononoki Nerd Font Mono:size=10", -+        "JoyPixels: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", "#ff0000" }, -+}; -+/* -l option; if nonzero, dmenu uses vertical list with given number of lines */ -+static unsigned int lines      = 0; -+static unsigned int lineheight = 0;         /* -h option; minimum height of a menu line     */ -+ -+/* -+ * 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 05d5a3e..cbb87eb 100644 +--- a/config.mk ++++ b/config.mk +@@ -20,11 +20,11 @@ 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) +-CFLAGS   = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS) ++CFLAGS   = -std=c99 -pedantic -Wall -O3 -march=native $(INCS) $(CPPFLAGS) + LDFLAGS  = $(LIBS) +  + # compiler and linker  diff --git a/dmenu.1 b/dmenu.1 -index 323f93c..7ef34d2 100644 +index 323f93c..36926c2 100644  --- a/dmenu.1  +++ b/dmenu.1 -@@ -50,6 +50,9 @@ dmenu matches menu items case insensitively. +@@ -3,9 +3,11 @@ + dmenu \- dynamic menu + .SH SYNOPSIS + .B dmenu +-.RB [ \-bfiv ] ++.RB [ \-bfsrvP ] + .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,16 +54,28 @@ 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. + .TP +-.B \-i +-dmenu matches menu items case insensitively. ++.B \-s ++dmenu matches menu items case sensitively. ++.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 @@ -73,275 +138,773 @@ index 323f93c..7ef34d2 100644   .BI \-m " monitor"   dmenu is displayed on the monitor number supplied. Monitor numbers are starting   from 0. +@@ -75,11 +101,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 65f25ce..9a1f14b 100644 +index 65f25ce..0f4d6b4 100644  --- a/dmenu.c  +++ b/dmenu.c -@@ -15,18 +15,19 @@ - #include <X11/extensions/Xinerama.h> - #endif - #include <X11/Xft/Xft.h> -+#include <X11/Xresource.h> -  - #include "drw.h" - #include "util.h" -  +@@ -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> +@@ -22,23 +23,49 @@   /* macros */   #define INTERSECT(x,y,w,h,r)  (MAX(0, MIN((x)+(w),(r).x_org+(r).width)  - MAX((x),(r).x_org)) \ --                             * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) +                              * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) ++#define INTERSECTBOOL(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, SchemeOut, SchemeNormHighlight, SchemeSelHighlight, SchemeLast }; /* color schemes */ ++enum { ++  SchemeNorm, ++  SchemeFade, ++  SchemeHighlight, ++  SchemeHover, ++  SchemeSel, ++  SchemeNormHighlight, ++  SchemeSelHighlight, ++  SchemeOut, ++  SchemeGreen, ++  SchemeYellow, ++  SchemeBlue, ++  SchemePurple, ++  SchemeRed, ++  SchemeLast ++}; /* color schemes */   struct item {   	char *text; -@@ -53,6 +54,10 @@ static XIC xic; - static Drw *drw; - static Clr *scheme[SchemeLast]; ++	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 dmx = 0; /* put dmenu at this x offset */ ++static int dmy = 0; /* put dmenu at this y offset (measured from the bottom if topbar is 0) */ ++static unsigned int dmw = 0; /* make dmenu this wide */ ++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; +@@ -55,8 +82,9 @@ 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; -@@ -113,6 +118,42 @@ cistrstr(const char *s, const char *sub) +-static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; +-static char *(*fstrstr)(const char *, const char *) = strstr; ++static char * cistrstr(const char *s, const char *sub); ++static int (*fstrncmp)(const char *, const char *, size_t) = strncasecmp; ++static char *(*fstrstr)(const char *, const char *) = cistrstr; +  + static void + appenditem(struct item *item, struct item **list, struct item **last) +@@ -89,6 +117,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) + { +@@ -113,17 +150,160 @@ cistrstr(const char *s, const char *sub)   	return NULL;   } +-static int +-drawitem(struct item *item, int x, int y, int w)  +static void  +drawhighlights(struct item *item, int x, int y, int maxw) -+{ -+	char restorechar, tokens[sizeof text], *highlight,  *token; -+	int indentx, highlightlen; + { +-	if (item == sel) +-		drw_setscheme(drw, scheme[SchemeSel]); +-	else if (item->out) +-		drw_setscheme(drw, scheme[SchemeOut]); +-	else +-		drw_setscheme(drw, scheme[SchemeNorm]); ++  int i, indent; ++  char *highlight; ++  char c;  + -+	drw_setscheme(drw, scheme[item == sel ? SchemeSelHighlight : SchemeNormHighlight]); -+	strcpy(tokens, text); -+	for (token = strtok(tokens, " "); token; token = strtok(NULL, " ")) { -+		highlight = fstrstr(item->text, token); -+		while (highlight) { -+			// Move item str end, calc width for highlight indent, & restore -+			highlightlen = highlight - item->text; -+			restorechar = *highlight; -+			item->text[highlightlen] = '\0'; -+			indentx = TEXTW(item->text); -+			item->text[highlightlen] = restorechar; ++  if (!(strlen(item->text) && strlen(text))) ++          return;  + -+			// Move highlight str end, draw highlight, & restore -+			restorechar = highlight[strlen(token)]; -+			highlight[strlen(token)] = '\0'; -+			drw_text( -+				drw, -+				x + indentx - (lrpad / 2) - 1, -+				y, -+				MIN(maxw - indentx, TEXTW(highlight) - lrpad), -+				bh, 0, highlight, 0 -+			); -+			highlight[strlen(token)] = restorechar; ++  drw_setscheme(drw, scheme[item == sel ++                     ? SchemeSelHighlight ++                     : SchemeNormHighlight]);  + -+			if (strlen(highlight) - strlen(token) < strlen(token)) break; -+			highlight = fstrstr(highlight + strlen(token), token); -+		} -+	} -+} ++  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;  + - static int - drawitem(struct item *item, int x, int y, int w) - { -@@ -123,7 +164,9 @@ drawitem(struct item *item, int x, int y, int w) - 	else - 		drw_setscheme(drw, scheme[SchemeNorm]); ++                  /* 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++; ++  } ++}  -	return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); -+	int r = drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); -+	drawhighlights(item, x, y, w); -+	return r; ++static int ++drawitem(struct item *item, int x, int y, int w) { ++  int r; ++  int iscomment = 0; ++  if (item->text[0] == '>') { ++    if (item->text[1] == '>') { ++      iscomment = 3; ++      switch (item->text[2]) { ++      case 'r': ++        drw_setscheme(drw, scheme[SchemeRed]); ++        break; ++      case 'g': ++        drw_setscheme(drw, scheme[SchemeGreen]); ++        break; ++      case 'y': ++        drw_setscheme(drw, scheme[SchemeYellow]); ++        break; ++      case 'b': ++        drw_setscheme(drw, scheme[SchemeBlue]); ++        break; ++      case 'p': ++        drw_setscheme(drw, scheme[SchemePurple]); ++        break; ++      case 'h': ++        drw_setscheme(drw, scheme[SchemeHighlight]); ++        break; ++      case 's': ++        drw_setscheme(drw, scheme[SchemeSel]); ++        break; ++      default: ++        iscomment = 1; ++        drw_setscheme(drw, scheme[SchemeNorm]); ++        break; ++      } ++    } else { ++      drw_setscheme(drw, scheme[SchemeNorm]); ++      iscomment = 1; ++    } ++ ++  } else if (item->text[0] == ':') { ++    iscomment = 2; ++    if (item == sel) { ++      switch (item->text[1]) { ++      case 'r': ++        drw_setscheme(drw, scheme[SchemeRed]); ++        break; ++      case 'g': ++        drw_setscheme(drw, scheme[SchemeGreen]); ++        break; ++      case 'y': ++        drw_setscheme(drw, scheme[SchemeYellow]); ++        break; ++      case 'b': ++        drw_setscheme(drw, scheme[SchemeBlue]); ++        break; ++      case 'p': ++        drw_setscheme(drw, scheme[SchemePurple]); ++        break; ++      case 'h': ++        drw_setscheme(drw, scheme[SchemeHighlight]); ++        break; ++      case 's': ++        drw_setscheme(drw, scheme[SchemeSel]); ++        break; ++      default: ++        drw_setscheme(drw, scheme[SchemeSel]); ++        iscomment = 0; ++        break; ++      } ++    } else { ++      drw_setscheme(drw, scheme[SchemeNorm]); ++    } ++  } else { ++    if (item == sel) ++      drw_setscheme(drw, scheme[SchemeSel]); ++    else if (item->out) ++      drw_setscheme(drw, scheme[SchemeOut]); ++    else ++      drw_setscheme(drw, scheme[SchemeNorm]); ++  } ++ ++  int temppadding; ++  temppadding = 0; ++  if (iscomment == 2) { ++    if (item->text[2] == ' ') { ++      temppadding = drw->fonts->h * 3; ++      animated = 1; ++      char dest[1000]; ++      strcpy(dest, item->text); ++      dest[6] = '\0'; ++      drw_text(drw, x, y, temppadding, lineheight, temppadding / 2.6, dest + 3, 0); ++      iscomment = 6; ++      drw_setscheme(drw, sel == item ? scheme[SchemeHover] : scheme[SchemeNorm]); ++    } ++  } ++ ++  char *output; ++  if (commented) { ++    static char onestr[2]; ++    onestr[0] = item->text[0]; ++    onestr[1] = '\0'; ++    output = onestr; ++  } else { ++    output = item->text; ++  } ++ ++  if (item == sel) ++    sely = y; ++  r = drw_text( ++      drw, x + ((iscomment == 6) ? temppadding : 0), y, ++      commented ? bh : (w - ((iscomment == 6) ? temppadding : 0)), bh, ++      commented ? (bh - drw_fontset_getwidth(drw, (output))) / 2 : lrpad / 2, ++      output + iscomment, 0); ++  drawhighlights(item, x, y, w); ++  return r;   }   static void -@@ -131,7 +174,7 @@ drawmenu(void) +@@ -131,7 +311,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); -@@ -148,7 +191,7 @@ drawmenu(void) +@@ -143,12 +324,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); ++		drw_rect(drw, x + curpos, 2 + (bh - fh) / 2, 2, fh - 4, 1, 0);   	}   	if (lines > 0) { -@@ -556,11 +599,11 @@ run(void) - 		if (XFilterEvent(&ev, win)) - 			continue; - 		switch(ev.type) { --		case DestroyNotify: --			if (ev.xdestroywindow.window != win) --				break; --			cleanup(); --			exit(1); -+                case DestroyNotify: -+                        if (ev.xdestroywindow.window != win) -+                                break; -+                        cleanup(); -+                        exit(1); - 		case Expose: - 			if (ev.xexpose.count == 0) - 				drw_map(drw, win, 0, 0, mw, mh); -@@ -601,14 +644,20 @@ 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); +@@ -210,9 +396,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); ++		}  +	} -+	for (j = 0; j < SchemeOut; ++j) { -+		for (i = 0; i < 2; ++i) -+			free(colors[j][i]); ++ ++	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; - 	clip = XInternAtom(dpy, "CLIPBOARD",   False); - 	utf8 = XInternAtom(dpy, "UTF8_STRING", False); +@@ -269,12 +540,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 +@@ -464,7 +749,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); +@@ -500,6 +785,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) + { +@@ -524,6 +922,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++) { +@@ -534,6 +937,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) { ++			char *tmp = items[i].text; ++			items[i].text = items[i].text_output; ++			items[i].text_output = tmp; ++		} + 		items[i].out = 0; + 		drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL); + 		if (tmpmax > inputw) { +@@ -561,6 +976,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); +@@ -609,8 +1027,10 @@ setup(void)   	/* calculate menu geometry */   	bh = drw->fonts->h + 2;  +	bh = MAX(bh,lineheight);	/* make a menu line AT LEAST 'lineheight' tall */   	lines = MAX(lines, 0);   	mh = (lines + 1) * bh; ++	promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;   #ifdef XINERAMA -@@ -664,10 +713,9 @@ setup(void) + 	i = 0; + 	if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { +@@ -634,12 +1054,18 @@ 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 (INTERSECTBOOL(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,21 +1073,29 @@ 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 = dmx; ++                        y = topbar ? dmy : 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; ++	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); -- - 	/* input methods */ --	if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL) --		die("XOpenIM failed: could not open input device"); -+        if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL) -+                die("XOpenIM failed: could not open input device"); - 	xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, - 	                XNClientWindow, win, XNFocusWindow, win, NULL); -@@ -690,10 +738,46 @@ static void +@@ -689,8 +1123,10 @@ setup(void) + static void   usage(void)   { - 	fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" -+	      "             [-h height]\n" - 	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); +-	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 [-bfsrvP] [-l lines] [-h height] [-p prompt] [-fn font] [-m monitor]\n" ++              "             [-x xoffset] [-y yoffset] [-z width] [-nb color] [-nf color] [-sb color] [-sf color]\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]); -+ -+		XrmDestroyDatabase(xdb); -+	} -+} -+ - int - main(int argc, char *argv[]) - { -@@ -722,15 +806,19 @@ 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], "-h")) { /* minimum height of one menu line */ +@@ -709,14 +1145,32 @@ 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], "-i")) { /* case-insensitive item matching */ +-			fstrncmp = strncasecmp; +-			fstrstr = cistrstr; +-		} else if (i + 1 == argc) ++                else if (!strcmp(argv[i], "-F"))   /* is not fuzzy search */ ++                        fuzzy = 0; ++                else if (!strcmp(argv[i], "-c"))   /* centers dmenu on screen */ ++                        centered = 1; ++		else if (!strcmp(argv[i], "-s")) { /* case-sensitive item matching */ ++			fstrncmp = strncmp; ++			fstrstr = strstr; ++                } else if (!strcmp(argv[i], "-r")) /* reject input which results in no match */ ++                        reject_no_match = 1; ++                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 */ + 			lines = atoi(argv[++i]); ++                else if (!strcmp(argv[i], "-x")) /* window x offset */ ++                        dmx = atoi(argv[++i]); ++                else if (!strcmp(argv[i], "-y")) /* window x offset */ ++                        dmy = atoi(argv[++i]); ++                else if (!strcmp(argv[i], "-z")) /* window x offset */ ++                        dmw = atoi(argv[++i]); ++		else if (!strcmp(argv[i], "-h")) { /* minimum height of one menu line */  +			lineheight = atoi(argv[++i]); -+			lineheight = MAX(lineheight,8); /* reasonable default in case of value too small/negative */ ++			lineheight = MAX(lineheight, min_lineheight);  +		} - 		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], "-m")) + 			mon = atoi(argv[++i]); + 		else if (!strcmp(argv[i], "-p"))   /* adds prompt to left of input field */ +@@ -731,8 +1185,23 @@ main(int argc, char *argv[]) + 			colors[SchemeSel][ColBg] = argv[++i];   		else if (!strcmp(argv[i], "-sf"))  /* selected foreground color */ --			colors[SchemeSel][ColFg] = argv[++i]; -+			colortemp[3]= argv[++i]; + 			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 if (!strcmp(argv[i], "-bw"))  /* border width */ ++                        border_width = atoi(argv[++i]); ++		else if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "-D")) { /* field separator */ ++			separator_reverse = (*(argv[i+1]+1) == '|'); ++			separator_greedy = !strcmp(argv[i], "-D"); ++			separator = *argv[++i]; ++		}   		else -@@ -748,8 +836,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))) + 			usage(); +  +@@ -752,6 +1221,9 @@ main(int argc, char *argv[])   		die("no fonts could be loaded."); -+ -+	free(fonts[0]);   	lrpad = drw->fonts->h; ++    if (lineheight == -1) ++        lineheight = drw->fonts->h * 2.5; ++   #ifdef __OpenBSD__ -diff --git a/drw.c b/drw.c -index 4cdbcbe..6927c41 100644 ---- a/drw.c -+++ b/drw.c -@@ -95,7 +95,7 @@ drw_free(Drw *drw) - { - 	XFreePixmap(drw->dpy, drw->drawable); - 	XFreeGC(drw->dpy, drw->gc); --	drw_fontset_free(drw->fonts); -+        drw_fontset_free(drw->fonts); - 	free(drw); - } -  + 	if (pledge("stdio rpath", NULL) == -1) + 		die("pledge");  | 
