dmenu-nonblockingstdincontrol-4.9.diff - sites - public wiki contents of suckless.org
(HTM) git clone git://git.suckless.org/sites
(DIR) Log
(DIR) Files
(DIR) Refs
---
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