On Mon, Nov 29, 2010 at 2:44 AM, Connor Lane Smith <[email protected]> wrote:
> Great, it's a lot cleaner this way. One problem with this approach,
> though, is that if data is written to stdin it isn't displayed until
> the next X event. This is likely fine for your use case, and
> dmenu_run, but perhaps not for other cases. To fix that we'd have to
> select between stdin and XConnectionNumber(dc->dpy).
Here is a patch that implements this idea (still available on my
bitbucket repo). It actually makes dmenu pretty slow to read stdin.
comments/fix are welcome.
diff -r a79e4a9cb167 dmenu.c
--- a/dmenu.c Sat Nov 20 09:25:08 2010 +0000
+++ b/dmenu.c Mon Nov 29 23:47:52 2010 +0100
@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <sys/select.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
@@ -34,6 +35,7 @@
static size_t nextrune(int incr);
static void paste(void);
static void readstdin(void);
+static void readXEvent(void);
static void run(void);
static void setup(void);
static void usage(void);
@@ -54,11 +56,13 @@
static unsigned long normcol[ColLast];
static unsigned long selcol[ColLast];
static Atom utf8;
+static Bool eof = False;
static Bool topbar = True;
static DC *dc;
static Item *items = NULL;
static Item *matches, *sel;
static Item *prev, *curr, *next;
+static Item **end = &items;
static Window root, win;
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
@@ -102,7 +106,6 @@
dc = initdc();
initfont(dc, font);
- readstdin();
setup();
run();
@@ -433,9 +436,10 @@
void
readstdin(void) {
char buf[sizeof text], *p;
- Item *item, **end;
+ Item *item;
- for(end = &items; fgets(buf, sizeof buf, stdin); *end = item, end = &item->next) {
+ eof = eof || !fgets(buf, sizeof buf, stdin);
+ if (!eof) {
if((p = strchr(buf, '\n')))
*p = '\0';
if(!(item = malloc(sizeof *item)))
@@ -444,14 +448,17 @@
eprintf("cannot strdup %u bytes\n", strlen(buf)+1);
item->next = item->left = item->right = NULL;
inputw = MAX(inputw, textw(dc, item->text));
+ *end = item;
+ end = &item->next;
+ match();
}
}
void
-run(void) {
+readXEvent(void) {
XEvent ev;
- while(!XNextEvent(dc->dpy, &ev))
+ if(!XNextEvent(dc->dpy, &ev))
switch(ev.type) {
case Expose:
if(ev.xexpose.count == 0)
@@ -472,6 +479,32 @@
}
void
+run(void) {
+ fd_set fds;
+ int x11_fd, n, nfds;
+ struct timeval tv;
+
+ x11_fd = XConnectionNumber(dc->dpy);
+ nfds = MAX(STDIN_FILENO, x11_fd) + 1;
+ while(1) {
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ FD_ZERO(&fds);
+ FD_SET(STDIN_FILENO, &fds);
+ FD_SET(x11_fd, &fds);
+ n = select(nfds, &fds, NULL, NULL, &tv);
+ if(n < 0)
+ eprintf("cannot select\n");
+ if(n > 0) {
+ if (FD_ISSET(STDIN_FILENO, &fds))
+ readstdin();
+ if (FD_ISSET(x11_fd, &fds))
+ readXEvent();
+ }
+ }
+}
+
+void
setup(void) {
int x, y, screen;
XSetWindowAttributes wa;
@@ -531,7 +564,7 @@
promptw = prompt ? textw(dc, prompt) : 0;
XMapRaised(dc->dpy, win);
text[0] = '\0';
- match();
+ drawmenu();
}
void