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