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