Hey all,

I updated the non-blocking and incremental patches to current tip; attached.

I was planning to write an extension patch as well, which would allow
you to say e.g. 'dmenu -xf dmenu_files' and then run a separate
program (such as file completion) when you hit, say, ^X^F, but I
haven't managed to finish that yet.

Thanks,
cls
diff -r 56ee9af6dcea dmenu.c
--- a/dmenu.c	Sat Nov 19 21:31:18 2011 +0100
+++ b/dmenu.c	Mon Nov 21 21:09:58 2011 +0100
@@ -1,10 +1,12 @@
 /* See LICENSE file for copyright and license details. */
 #include <ctype.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <strings.h>
 #include <unistd.h>
+#include <sys/select.h>
 #include <X11/Xlib.h>
 #include <X11/Xatom.h>
 #include <X11/Xutil.h>
@@ -21,6 +23,7 @@
 typedef struct Item Item;
 struct Item {
 	char *text;
+	Item *next;
 	Item *left, *right;
 };
 
@@ -34,6 +37,7 @@
 static void match(void);
 static size_t nextrune(int inc);
 static void paste(void);
+static void readevent(void);
 static void readstdin(void);
 static void run(void);
 static void setup(void);
@@ -43,6 +47,7 @@
 static int bh, mw, mh;
 static int inputw, promptw;
 static size_t cursor = 0;
+static const char *maxstr;
 static const char *font = NULL;
 static const char *prompt = NULL;
 static const char *normbgcolor = "#222222";
@@ -66,7 +71,6 @@
 
 int
 main(int argc, char *argv[]) {
-	Bool fast = False;
 	int i;
 
 	for(i = 1; i < argc; i++)
@@ -77,8 +81,6 @@
 		}
 		else if(!strcmp(argv[i], "-b"))   /* appears at the bottom of the screen */
 			topbar = False;
-		else if(!strcmp(argv[i], "-f"))   /* grabs keyboard before reading stdin */
-			fast = True;
 		else if(!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
 			fstrncmp = strncasecmp;
 			fstrstr = cistrstr;
@@ -105,15 +107,7 @@
 
 	dc = initdc();
 	initfont(dc, font);
-
-	if(fast) {
-		grabkeyboard();
-		readstdin();
-	}
-	else {
-		readstdin();
-		grabkeyboard();
-	}
+	grabkeyboard();
 	setup();
 	run();
 
@@ -205,6 +199,7 @@
 			drawtext(dc, ">", normcol);
 	}
 	mapdc(dc, win, mw, mh);
+	XFlush(dc->dpy);
 }
 
 void
@@ -396,7 +391,7 @@
 	len = tokc ? strlen(tokv[0]) : 0;
 
 	matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
-	for(item = items; item && item->text; item++) {
+	for(item = items; item; item = item->next) {
 		for(i = 0; i < tokc; i++)
 			if(!fstrstr(item->text, tokv[i]))
 				break;
@@ -457,33 +452,10 @@
 }
 
 void
-readstdin(void) {
-	char buf[sizeof text], *p, *maxstr = NULL;
-	size_t i, max = 0, size = 0;
-
-	/* read each line from stdin and add it to the item list */
-	for(i = 0; fgets(buf, sizeof buf, stdin); i++) {
-		if(i+1 >= size / sizeof *items)
-			if(!(items = realloc(items, (size += BUFSIZ))))
-				eprintf("cannot realloc %u bytes:", size);
-		if((p = strchr(buf, '\n')))
-			*p = '\0';
-		if(!(items[i].text = strdup(buf)))
-			eprintf("cannot strdup %u bytes:", strlen(buf)+1);
-		if(strlen(items[i].text) > max)
-			max = strlen(maxstr = items[i].text);
-	}
-	if(items)
-		items[i].text = NULL;
-	inputw = maxstr ? textw(dc, maxstr) : 0;
-	lines = MIN(lines, i);
-}
-
-void
-run(void) {
+readevent(void) {
 	XEvent ev;
 
-	while(!XNextEvent(dc->dpy, &ev)) {
+	while(XPending(dc->dpy) && !XNextEvent(dc->dpy, &ev)) {
 		if(XFilterEvent(&ev, win))
 			continue;
 		switch(ev.type) {
@@ -507,6 +479,57 @@
 }
 
 void
+readstdin(void) {
+	static size_t max = 0;
+	static Item **end = &items;
+
+	char buf[sizeof text], *p;
+	Item *item;
+
+	/* read each line from stdin and add it to the item list */
+	while(fgets(buf, sizeof buf, stdin)) {
+		if(!(item = malloc(sizeof *item)))
+			eprintf("cannot malloc %u bytes:", sizeof *item);
+		if((p = strchr(buf, '\n')))
+			*p = '\0';
+		if(!(item->text = strdup(buf)))
+			eprintf("cannot strdup %u bytes:", strlen(buf)+1);
+		if(strlen(item->text) > max) {
+			max = strlen(maxstr = item->text);
+			inputw = textw(dc, maxstr);
+		}
+		*end = item;
+		end = &item->next;
+		item->next = NULL;
+	}
+	match();
+	drawmenu();
+}
+
+void
+run(void) {
+	fd_set fds;
+	int flags, xfd = XConnectionNumber(dc->dpy);
+
+	if((flags = fcntl(STDIN_FILENO, F_GETFL)) == -1)
+		eprintf("cannot get stdin control flags:");
+	if(fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK) == -1)
+		eprintf("cannot set stdin control flags:");
+	for(;;) {
+		FD_ZERO(&fds);
+		FD_SET(xfd, &fds);
+		if(!feof(stdin))
+			FD_SET(STDIN_FILENO, &fds);
+		if(select(MAX(STDIN_FILENO, xfd) + 1, &fds, NULL, NULL, NULL) == -1)
+			eprintf("cannot multiplex input:");
+		if(FD_ISSET(xfd, &fds))
+			readevent();
+		if(FD_ISSET(STDIN_FILENO, &fds))
+			readstdin();
+	}
+}
+
+void
 setup(void) {
 	int x, y, screen = DefaultScreen(dc->dpy);
 	Window root = RootWindow(dc->dpy, screen);
diff -r 56ee9af6dcea config.mk
--- a/config.mk	Sat Nov 19 21:31:18 2011 +0100
+++ b/config.mk	Mon Nov 21 21:17:44 2011 +0100
@@ -17,7 +17,7 @@
 LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS}
 
 # flags
-CPPFLAGS = -D_BSD_SOURCE -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
+CPPFLAGS = -D_BSD_SOURCE -D_POSIX_SOURCE -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
 CFLAGS   = -ansi -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
 LDFLAGS  = -s ${LIBS}
 
diff -r 56ee9af6dcea dmenu.c
--- a/dmenu.c	Sat Nov 19 21:31:18 2011 +0100
+++ b/dmenu.c	Mon Nov 21 21:17:44 2011 +0100
@@ -55,6 +55,7 @@
 static Atom clip, utf8;
 static Bool topbar = True;
 static DC *dc;
+static FILE *incfp = NULL;
 static Item *items = NULL;
 static Item *matches, *matchend;
 static Item *prev, *curr, *next, *sel;
@@ -90,6 +91,8 @@
 			lines = atoi(argv[++i]);
 		else if(!strcmp(argv[i], "-p"))   /* adds prompt to left of input field */
 			prompt = argv[++i];
+		else if(!strcmp(argv[i], "-r"))   /* incremental output on given descriptor */
+			incfp = fdopen(atoi(argv[++i]), "w");
 		else if(!strcmp(argv[i], "-fn"))  /* font or font set */
 			font = argv[++i];
 		else if(!strcmp(argv[i], "-nb"))  /* normal background color */
@@ -388,6 +391,8 @@
 	size_t len;
 	Item *item, *lprefix, *lsubstr, *prefixend, *substrend;
 
+	if(incfp)
+		fprintf(incfp, "%s\n", text);
 	strcpy(buf, text);
 	/* separate input text into tokens to be matched individually */
 	for(s = strtok(buf, " "); s; tokv[tokc-1] = s, s = strtok(NULL, " "))
@@ -594,7 +599,7 @@
 
 void
 usage(void) {
-	fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font]\n"
+	fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-r fd] [-fn font]\n"
 	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-v]\n", stderr);
 	exit(EXIT_FAILURE);
 }

Reply via email to