sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | 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