Christophe-Marie Duquesne <chm.duque...@gmail.com> wrote:

> On Mon, Nov 29, 2010 at 2:44 AM, Connor Lane Smith <c...@lubutu.com> 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.

Attached patch against dmenu-4.2.1 is based on yours but with some
changes.

It reads stdin by blocks not by line that is noticeably reduces number
of invokes of readstdin() and whole select() machinery.
And it doesn't run match() on each item, that increases speed and
reduces cpu usage. But conditions to run match() must be reconsidered:
in this patch it is called once a second.
>From 57071c903d82ab9f7ea5184e2b974ce3e5d2ab21 Mon Sep 17 00:00:00 2001
From: Ramil Farkhshatov <ra...@gmx.co.uk>
Date: Wed, 1 Dec 2010 04:25:25 +0300
Subject: [PATCH] Added asynchronous.

---
 dmenu.c |   96 +++++++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 79 insertions(+), 17 deletions(-)

diff --git a/dmenu.c b/dmenu.c
index a24dfe3..d50604d 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -4,6 +4,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <fcntl.h>
+#include <sys/select.h>
 #include <X11/Xlib.h>
 #include <X11/Xatom.h>
 #include <X11/Xutil.h>
@@ -33,7 +35,8 @@ static void keypress(XKeyEvent *ev);
 static void match(void);
 static size_t nextrune(int incr);
 static void paste(void);
-static void readstdin(void);
+static int readstdin(void);
+static void readXEvent(void);
 static void run(void);
 static void setup(void);
 static void usage(void);
@@ -59,6 +62,7 @@ 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 @@ main(int argc, char *argv[]) {
 
        dc = initdc();
        initfont(dc, font);
-       readstdin();
        setup();
        run();
 
@@ -431,27 +434,59 @@ paste(void) {
 }
 
 void
+add_item(const char *buf) {
+       static time_t tm, prev_tm = 0;
+       Item *item;
+
+       if (!(item = malloc(sizeof *item)))
+               eprintf("cannot malloc %u bytes\n", sizeof *item);
+       if (!(item->text = strdup(buf)))
+               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;
+
+       /*
+         We don't want to call match on every new item.
+         It makes asynchronous dmenu very slow and cpu consuming.
+       */
+       tm = time(0);
+       if (tm - prev_tm > 1)
+               match();
+       prev_tm = tm;
+}
+
+int
 readstdin(void) {
-       char buf[sizeof text], *p;
-       Item *item, **end;
-
-       for(end = &items; fgets(buf, sizeof buf, stdin); *end = item, end = 
&item->next) {
-               if((p = strchr(buf, '\n')))
-                       *p = '\0';
-               if(!(item = malloc(sizeof *item)))
-                       eprintf("cannot malloc %u bytes\n", sizeof *item);
-               if(!(item->text = strdup(buf)))
-                       eprintf("cannot strdup %u bytes\n", strlen(buf)+1);
-               item->next = item->left = item->right = NULL;
-               inputw = MAX(inputw, textw(dc, item->text));
+       static char buf[BUFSIZ];
+       static int off = 0;
+       int n, start, i;
+       char *p;
+
+       n = read(0, buf + off, sizeof(buf) - off);
+       if (!n)
+               return 0;
+       start = 0;
+       for (i = off; i < n + off; ++i) {
+               if (buf[i] == '\n') {
+               if (i > start) {
+                       buf[i] = 0;
+                       add_item(buf + start);
+               }
+               start = i + 1;
+               }
        }
+       memmove(buf, buf + start, off + n - start);
+       off = off + n - start;
+       return 1;
 }
 
 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 +507,33 @@ run(void) {
 }
 
 void
+run(void) {
+       fd_set fds;
+       int x11_fd, n, nfds, flags, do_stdin = 1;
+
+  flags = fcntl(0, F_GETFL);
+  flags |= O_NONBLOCK;
+  fcntl(0, F_SETFL, flags);
+       x11_fd = XConnectionNumber(dc->dpy);
+       nfds = MAX(STDIN_FILENO, x11_fd) + 1;
+       while(1) {
+               FD_ZERO(&fds);
+    if (do_stdin)
+      FD_SET(STDIN_FILENO, &fds);
+               FD_SET(x11_fd, &fds);
+               n = select(nfds, &fds, NULL, NULL, 0);
+               if(n < 0)
+                       eprintf("cannot select\n");
+               if(n > 0) {
+                       if (FD_ISSET(STDIN_FILENO, &fds))
+                               do_stdin = readstdin();
+                       if (FD_ISSET(x11_fd, &fds))
+                               readXEvent();
+               }
+       }
+}
+
+void
 setup(void) {
        int x, y, screen;
        XSetWindowAttributes wa;
@@ -531,7 +593,7 @@ setup(void) {
        promptw = prompt ? textw(dc, prompt) : 0;
        XMapRaised(dc->dpy, win);
        text[0] = '\0';
-       match();
+       drawmenu();
 }
 
 void
-- 
1.7.3.2

Reply via email to