sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

dmenu-nonblockingstdin-20160702-3c91eed.diff (6044B)


      1 diff --git a/dmenu.1 b/dmenu.1
      2 index d3ab805..00958cf 100644
      3 --- a/dmenu.1
      4 +++ b/dmenu.1
      5 @@ -4,7 +4,6 @@ dmenu \- dynamic menu
      6  .SH SYNOPSIS
      7  .B dmenu
      8  .RB [ \-b ]
      9 -.RB [ \-f ]
     10  .RB [ \-i ]
     11  .RB [ \-l
     12  .RB [ \-m
     13 @@ -41,10 +40,6 @@ which lists programs in the user's $PATH and runs the result in their $SHELL.
     14  .B \-b
     15  dmenu appears at the bottom of the screen.
     16  .TP
     17 -.B \-f
     18 -dmenu grabs the keyboard before reading stdin.  This is faster, but will lock up
     19 -X until stdin reaches end\-of\-file.
     20 -.TP
     21  .B \-i
     22  dmenu matches menu items case insensitively.
     23  .TP
     24 diff --git a/dmenu.c b/dmenu.c
     25 index e926eca..dc81ef2 100644
     26 --- a/dmenu.c
     27 +++ b/dmenu.c
     28 @@ -1,12 +1,15 @@
     29  /* See LICENSE file for copyright and license details. */
     30  #include <ctype.h>
     31 +#include <fcntl.h>
     32  #include <locale.h>
     33  #include <stdio.h>
     34  #include <stdlib.h>
     35  #include <string.h>
     36  #include <strings.h>
     37  #include <time.h>
     38 +#include <unistd.h>
     39  
     40 +#include <sys/select.h>
     41  #include <X11/Xlib.h>
     42  #include <X11/Xatom.h>
     43  #include <X11/Xutil.h>
     44 @@ -30,6 +33,7 @@ enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */
     45  struct item {
     46  	char *text;
     47  	struct item *left, *right;
     48 +	struct item *next;
     49  	int out;
     50  };
     51  
     52 @@ -172,6 +176,7 @@ drawmenu(void)
     53  		}
     54  	}
     55  	drw_map(drw, win, 0, 0, mw, mh);
     56 +	XFlush(dpy);
     57  }
     58  
     59  static void
     60 @@ -200,6 +205,7 @@ match(void)
     61  	int i, tokc = 0;
     62  	size_t len, textsize;
     63  	struct item *item, *lprefix, *lsubstr, *prefixend, *substrend;
     64 +	int preserve = 0;
     65  
     66  	strcpy(buf, text);
     67  	/* separate input text into tokens to be matched individually */
     68 @@ -210,19 +216,24 @@ match(void)
     69  
     70  	matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
     71  	textsize = strlen(text);
     72 -	for (item = items; item && item->text; item++) {
     73 +
     74 +	for (item = items; item; item = item->next) {
     75  		for (i = 0; i < tokc; i++)
     76  			if (!fstrstr(item->text, tokv[i]))
     77  				break;
     78  		if (i != tokc) /* not all tokens match */
     79  			continue;
     80  		/* exact matches go first, then prefixes, then substrings */
     81 -		if (!tokc || !fstrncmp(text, item->text, textsize))
     82 +		if (!tokc || !fstrncmp(text, item->text, textsize)) {
     83  			appenditem(item, &matches, &matchend);
     84 -		else if (!fstrncmp(tokv[0], item->text, len))
     85 +			if (sel == item) preserve = 1;
     86 +		} else if (!fstrncmp(tokv[0], item->text, len)) {
     87  			appenditem(item, &lprefix, &prefixend);
     88 -		else
     89 +			if (sel == item) preserve = 1;
     90 +		} else {
     91  			appenditem(item, &lsubstr, &substrend);
     92 +			if (sel == item) preserve = 1;
     93 +		}
     94  	}
     95  	if (lprefix) {
     96  		if (matches) {
     97 @@ -240,7 +251,9 @@ match(void)
     98  			matches = lsubstr;
     99  		matchend = substrend;
    100  	}
    101 -	curr = sel = matches;
    102 +	if (!preserve)
    103 +		curr = sel = matches;
    104 +
    105  	calcoffsets();
    106  }
    107  
    108 @@ -456,36 +469,7 @@ paste(void)
    109  }
    110  
    111  static void
    112 -readstdin(void)
    113 -{
    114 -	char buf[sizeof text], *p;
    115 -	size_t i, imax = 0, size = 0;
    116 -	unsigned int tmpmax = 0;
    117 -
    118 -	/* read each line from stdin and add it to the item list */
    119 -	for (i = 0; fgets(buf, sizeof buf, stdin); i++) {
    120 -		if (i + 1 >= size / sizeof *items)
    121 -			if (!(items = realloc(items, (size += BUFSIZ))))
    122 -				die("cannot realloc %u bytes:", size);
    123 -		if ((p = strchr(buf, '\n')))
    124 -			*p = '\0';
    125 -		if (!(items[i].text = strdup(buf)))
    126 -			die("cannot strdup %u bytes:", strlen(buf) + 1);
    127 -		items[i].out = 0;
    128 -		drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL);
    129 -		if (tmpmax > inputw) {
    130 -			inputw = tmpmax;
    131 -			imax = i;
    132 -		}
    133 -	}
    134 -	if (items)
    135 -		items[i].text = NULL;
    136 -	inputw = items ? TEXTW(items[imax].text) : 0;
    137 -	lines = MIN(lines, i);
    138 -}
    139 -
    140 -static void
    141 -run(void)
    142 +readevent(void)
    143  {
    144  	XEvent ev;
    145  
    146 @@ -513,6 +497,60 @@ run(void)
    147  }
    148  
    149  static void
    150 +readstdin(void)
    151 +{
    152 +	static size_t max = 0;
    153 +	static struct item **end = &items;
    154 +
    155 +	char buf[sizeof text], *p, *maxstr;
    156 +	struct item *item;
    157 +
    158 +	/* read each line from stdin and add it to the item list */
    159 +	while (fgets(buf, sizeof buf, stdin)) {
    160 +		if (!(item = malloc(sizeof *item)))
    161 +			die("cannot malloc %u bytes:", sizeof *item);
    162 +		if ((p = strchr(buf, '\n')))
    163 +			*p = '\0';
    164 +		if (!(item->text = strdup(buf)))
    165 +			die("cannot strdup %u bytes:", strlen(buf)+1);
    166 +		if (strlen(item->text) > max) {
    167 +			max = strlen(maxstr = item->text);
    168 +			inputw = maxstr ? TEXTW(maxstr) : 0;
    169 +		}
    170 +		*end = item;
    171 +		end = &item->next;
    172 +		item->next = NULL;
    173 +		item->out = 0;
    174 +	}
    175 +	match();
    176 +	drawmenu();
    177 +}
    178 +
    179 +static void
    180 +run(void)
    181 +{
    182 +	fd_set fds;
    183 +	int flags, xfd = XConnectionNumber(dpy);
    184 +
    185 +	if ((flags = fcntl(0, F_GETFL)) == -1)
    186 +		die("cannot get stdin control flags:");
    187 +	if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1)
    188 +		die("cannot set stdin control flags:");
    189 +	for (;;) {
    190 +		FD_ZERO(&fds);
    191 +		FD_SET(xfd, &fds);
    192 +		if (!feof(stdin))
    193 +			FD_SET(0, &fds);
    194 +		if (select(xfd + 1, &fds, NULL, NULL, NULL) == -1)
    195 +			die("cannot multiplex input:");
    196 +		if (FD_ISSET(xfd, &fds))
    197 +			readevent();
    198 +		if (FD_ISSET(0, &fds))
    199 +			readstdin();
    200 +	}
    201 +}
    202 +
    203 +static void
    204  setup(void)
    205  {
    206  	int x, y;
    207 @@ -600,7 +638,7 @@ setup(void)
    208  static void
    209  usage(void)
    210  {
    211 -	fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
    212 +	fputs("usage: dmenu [-b] [-i] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
    213  	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-v]\n", stderr);
    214  	exit(1);
    215  }
    216 @@ -608,7 +646,7 @@ usage(void)
    217  int
    218  main(int argc, char *argv[])
    219  {
    220 -	int i, fast = 0;
    221 +	int i;
    222  
    223  	for (i = 1; i < argc; i++)
    224  		/* these options take no arguments */
    225 @@ -617,8 +655,6 @@ main(int argc, char *argv[])
    226  			exit(0);
    227  		} else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */
    228  			topbar = 0;
    229 -		else if (!strcmp(argv[i], "-f"))   /* grabs keyboard before reading stdin */
    230 -			fast = 1;
    231  		else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
    232  			fstrncmp = strncasecmp;
    233  			fstrstr = cistrstr;
    234 @@ -657,13 +693,7 @@ main(int argc, char *argv[])
    235  		die("no fonts could be loaded.\n");
    236  	lrpad = drw->fonts->h;
    237  
    238 -	if (fast) {
    239 -		grabkeyboard();
    240 -		readstdin();
    241 -	} else {
    242 -		readstdin();
    243 -		grabkeyboard();
    244 -	}
    245 +	grabkeyboard();
    246  	setup();
    247  	run();
    248