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);
}