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