Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-12-07 Thread Christophe-Marie Duquesne
The following patch does what I proposed. 'seq 1 100 | ./dmenu'
just feels as fast as the vanilla dmenu. After each select(), the file
descriptors are read until there is no data left on them (and match()
is called only once all the data in stdin has been read).

Cheers,
Christophe-Marie
diff -r 2b9683c50723 dmenu.c
--- a/dmenu.c	Wed Dec 01 20:25:10 2010 +
+++ b/dmenu.c	Tue Dec 07 14:31:01 2010 +0100
@@ -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
@@ -34,6 +36,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);
@@ -59,6 +62,7 @@
 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,9 @@
 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) {
+	while (fgets(buf, sizeof buf, stdin)) {
 		if((p = strchr(buf, '\n')))
 			*p = '\0';
 		if(!(item = malloc(sizeof *item)))
@@ -444,14 +447,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))
+	while(XPending(dc-dpy)  !XNextEvent(dc-dpy, ev))
 		switch(ev.type) {
 		case Expose:
 			if(ev.xexpose.count == 0)
@@ -472,6 +478,35 @@
 }
 
 void
+run(void) {
+	fd_set fds;
+	int x11_fd, n, nfds, flags;
+	struct timeval tv;
+
+	flags = fcntl(STDIN_FILENO, F_GETFL);
+	flags |= O_NONBLOCK;
+	fcntl(STDIN_FILENO, F_SETFL, flags);
+
+	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);
+		if (!feof(stdin))
+			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 (FD_ISSET(STDIN_FILENO, fds))
+			readstdin();
+		if (FD_ISSET(x11_fd, fds))
+			readXEvent();
+	}
+}
+
+void
 setup(void) {
 	int x, y, screen;
 	XSetWindowAttributes wa;
@@ -531,7 +566,7 @@
 	promptw = prompt ? textw(dc, prompt) : 0;
 	XMapRaised(dc-dpy, win);
 	text[0] = '\0';
-	match();
+	drawmenu();
 }
 
 void


Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-12-07 Thread Christophe-Marie Duquesne
This patch includes a small correction I forgot to put in the previous
patch. There is no need to specify a timeval to wait for (select
should block until some data arrives either on stdin or on the x11
file descriptor, as recommended by the select() man page).
diff -r 2b9683c50723 dmenu.c
--- a/dmenu.c	Wed Dec 01 20:25:10 2010 +
+++ b/dmenu.c	Tue Dec 07 17:32:54 2010 +0100
@@ -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
@@ -34,6 +36,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);
@@ -59,6 +62,7 @@
 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,9 @@
 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) {
+	while (fgets(buf, sizeof buf, stdin)) {
 		if((p = strchr(buf, '\n')))
 			*p = '\0';
 		if(!(item = malloc(sizeof *item)))
@@ -444,14 +447,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))
+	while(XPending(dc-dpy)  !XNextEvent(dc-dpy, ev))
 		switch(ev.type) {
 		case Expose:
 			if(ev.xexpose.count == 0)
@@ -472,6 +478,32 @@
 }
 
 void
+run(void) {
+	fd_set fds;
+	int x11_fd, n, nfds, flags;
+
+	flags = fcntl(STDIN_FILENO, F_GETFL);
+	flags |= O_NONBLOCK;
+	fcntl(STDIN_FILENO, F_SETFL, flags);
+
+	x11_fd = XConnectionNumber(dc-dpy);
+	nfds = MAX(STDIN_FILENO, x11_fd) + 1;
+	while(1) {
+		FD_ZERO(fds);
+		if (!feof(stdin))
+			FD_SET(STDIN_FILENO, fds);
+		FD_SET(x11_fd, fds);
+		n = select(nfds, fds, NULL, NULL, NULL);
+		if(n  0)
+			eprintf(cannot select\n);
+		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 +563,7 @@
 	promptw = prompt ? textw(dc, prompt) : 0;
 	XMapRaised(dc-dpy, win);
 	text[0] = '\0';
-	match();
+	drawmenu();
 }
 
 void


Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-12-01 Thread Christophe-Marie Duquesne
On Wed, Dec 1, 2010 at 2:34 AM, Ramil Farkhshatov ra...@gmx.co.uk wrote:
 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.


Would it make sense to call match() only when there is nothing left to
read on stdin (in your example, that would be when readstdin() returns
0)?



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-12-01 Thread Ramil Farkhshatov
Christophe-Marie Duquesne chm.duque...@gmail.com wrote:

 On Wed, Dec 1, 2010 at 2:34 AM, Ramil Farkhshatov ra...@gmx.co.uk wrote:
  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.

 Would it make sense to call match() only when there is nothing left to
 read on stdin (in your example, that would be when readstdin() returns
 0)?

If dmenu starts matching after exhausting of data then it will not
differ in behaviour from synchronous vanilla version. The condition may
be something like: 

(time_since_last_match_ms  threshold_ms 
|| items_since_last_match  threshold_nitems
|| data_exhausted)



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-12-01 Thread Christophe-Marie Duquesne
On Wed, Dec 1, 2010 at 12:12 PM, Ramil Farkhshatov ra...@gmx.co.uk wrote:
 Christophe-Marie Duquesne chm.duque...@gmail.com wrote:
 If dmenu starts matching after exhausting of data then it will not
 differ in behaviour from synchronous vanilla version.

Except it won't block if it does not read EOF, which was more or less
the initial goal, wasn't it? This way, if data arrives on stdin, it is
read as fast as possible (blocking the user from typing stuff
meanwhile, but minimizing the time needed for reading) and if there is
no data left to read, dmenu will read X events. If there is not too
much data to read (in a case like a google_suggest script, which feeds
10 lines to stdin at each stroke) this should feel instantaneous.



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-12-01 Thread Ramil Farkhshatov
Ramil Farkhshatov ra...@gmx.co.uk wrote:

 The condition may  be something like: 

 (time_since_last_match_ms  threshold_ms 
 || items_since_last_match  threshold_nitems
 || data_exhausted)

Stupid me. We can just match added single item.



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-30 Thread Ramil Farkhshatov
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 = 

Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-29 Thread Christophe-Marie Duquesne
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).

Yes, this would be even better.

 I've also attached a slightly neater version of your patch, plus a bugfix.

Thank you!



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-29 Thread Christophe-Marie Duquesne
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.
diff -r a79e4a9cb167 dmenu.c
--- a/dmenu.c	Sat Nov 20 09:25:08 2010 +
+++ 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


Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-28 Thread Christophe-Marie Duquesne
Hi,

I rewrote my proposal with select(). Now readstdin() will return if it
cannot read data from stdin during more than 1 u_sec. It will set the
static flag 'eof' to 1 if it has read the end of file character. This
way while eof is 0, you know you should call readstdin() again.

Attached is a patch that you can also pull from
https://bitbucket.org/chmduquesne/dmenu
diff -r a79e4a9cb167 dmenu.c
--- a/dmenu.c	Sat Nov 20 09:25:08 2010 +
+++ b/dmenu.c	Mon Nov 29 01:14:46 2010 +0100
@@ -10,6 +10,8 @@
 #ifdef XINERAMA
 #include X11/extensions/Xinerama.h
 #endif
+#include sys/time.h
+#include sys/types.h
 #include draw.h
 
 #define INRECT(x,y,rx,ry,rw,rh) ((x) = (rx)  (x)  (rx)+(rw)  (y) = (ry)  (y)  (ry)+(rh))
@@ -44,6 +46,7 @@
 static int lines = 0;
 static int monitor = -1;
 static int promptw;
+static int eof = 0;
 static size_t cursor = 0;
 static const char *font = NULL;
 static const char *prompt = NULL;
@@ -59,6 +62,7 @@
 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;
@@ -432,26 +436,44 @@
 
 void
 readstdin(void) {
+	fd_set rfds;
+	struct timeval tv;
+	int canread;
 	char buf[sizeof text], *p;
-	Item *item, **end;
+	Item *item;
 
-	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));
-	}
+	do {
+		tv.tv_sec = 0;
+		tv.tv_usec = 1;
+		FD_ZERO(rfds);
+		FD_SET(0, rfds);
+		canread = select(1, rfds, NULL, NULL, tv);
+		if(canread == -1)
+			perror(select());
+		if(canread) {
+			eof = (fgets(buf, sizeof buf, stdin) == NULL);
+			if(!eof) {
+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));
+
+*end = item;
+end = item-next;
+			}
+		}
+	} while(canread  !eof);
 }
 
 void
 run(void) {
 	XEvent ev;
 
-	while(!XNextEvent(dc-dpy, ev))
+	while(!XNextEvent(dc-dpy, ev)) {
 		switch(ev.type) {
 		case Expose:
 			if(ev.xexpose.count == 0)
@@ -469,6 +491,9 @@
 XRaiseWindow(dc-dpy, win);
 			break;
 		}
+		if (!eof)
+			readstdin();
+	}
 }
 
 void


Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-28 Thread Connor Lane Smith
Hey,

On 29 November 2010 00:17, Christophe-Marie Duquesne
chm.duque...@gmail.com wrote:
 I rewrote my proposal with select(). Now readstdin() will return if it
 cannot read data from stdin during more than 1 u_sec. It will set the
 static flag 'eof' to 1 if it has read the end of file character. This
 way while eof is 0, you know you should call readstdin() again.

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).

I've also attached a slightly neater version of your patch, plus a bugfix.

Thanks,
cls
diff -r a79e4a9cb167 dmenu.c
--- a/dmenu.c	Sat Nov 20 09:25:08 2010 +
+++ b/dmenu.c	Mon Nov 29 01:40:44 2010 +
@@ -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
@@ -54,11 +55,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 +105,6 @@
 
 	dc = initdc();
 	initfont(dc, font);
-	readstdin();
 	setup();
 	run();
 
@@ -433,9 +435,20 @@
 void
 readstdin(void) {
 	char buf[sizeof text], *p;
-	Item *item, **end;
+	fd_set fds;
+	int n;
+	struct timeval tv;
+	Item *item;
 
-	for(end = items; fgets(buf, sizeof buf, stdin); *end = item, end = item-next) {
+	while(!eof) {
+		tv.tv_sec = 0;
+		tv.tv_usec = 1;
+		FD_ZERO(fds);
+		FD_SET(STDIN_FILENO, fds);
+		if((n = select(1, fds, NULL, NULL, tv))  0)
+			eprintf(cannot select stdin\n);
+		if(n == 0 || (eof = !fgets(buf, sizeof buf, stdin)))
+			break;
 		if((p = strchr(buf, '\n')))
 			*p = '\0';
 		if(!(item = malloc(sizeof *item)))
@@ -444,6 +457,9 @@
 			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();
 	}
 }
 
@@ -451,7 +467,7 @@
 run(void) {
 	XEvent ev;
 
-	while(!XNextEvent(dc-dpy, ev))
+	while(!XNextEvent(dc-dpy, ev)) {
 		switch(ev.type) {
 		case Expose:
 			if(ev.xexpose.count == 0)
@@ -469,6 +485,8 @@
 XRaiseWindow(dc-dpy, win);
 			break;
 		}
+		readstdin();
+	}
 }
 
 void
@@ -531,7 +549,7 @@
 	promptw = prompt ? textw(dc, prompt) : 0;
 	XMapRaised(dc-dpy, win);
 	text[0] = '\0';
-	match();
+	drawmenu();
 }
 
 void


Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-26 Thread Dieter Plaetinck
On Fri, 26 Nov 2010 14:38:10 +0100
Christophe-Marie Duquesne chm.duque...@gmail.com wrote:

 Hi there,
 
 I wanted a menu that would allow me to select entries both from the
 uzbl history and from google suggest 'as you type' (like in firefox).
 While dmenu allows selecting entries in a static list (like uzbl
 history) easily, modifying this list and providing hints to google
 suggest did not seem to be possible. Since I did not see any other way
 to do that, I wrote a patch to dmenu. It adds 2 features:
 
 1) if invoked with the option -s (-s for stream) dmenu will output
 selected entry on every keystroke (so you can feed a tool with the
 current entry).
 2) in order to avoid waiting for the input stream to finish before
 allowing the user for select entries (and so that you can continue
 feeding it from stdin while you type),  dmenu reads stdin in a thread.
 
 The idea is to feed dmenu with hints deduced from its stdout. As an
 example, here is how this can be used:
 
 #!/bin/bash
 
 socat UNIX-LISTEN:/tmp/dmenu_suggest - | dmenu -s | tee /tmp/results
 | \ while read line; do echo $line | ./google_suggest; done | \
 socat - UNIX-CONNECT:/tmp/dmenu_suggest
 
 tail -n1 /tmp/results  rm /tmp/results
 
 google_suggest is a python script I wrote. It reads search terms from
 stdin and outputs suggestions from google suggest API (I have attached
 it).
 
 If you are interested, you can pull my dmenu patch from
 https://bitbucket.org/chmduquesne/dmenu. Although the script above
 works correctly on my machine, the patch breaks dmenu in other
 situations. I would be interested if the persons who find this idea
 interesting would be kind enough to provide some constructive advices
 about the way to do that, e.g. if you see any cleaner method or if you
 have suggestions for doing that in a better way without patching
 dmenu. Advices like don't do that or stop rewriting firefox will
 probably not help.

Cool.  I've been pondering this feature before.
Because if feeding dmenu stdin is time-consuming (i have some sorts
and whatnot when reading my most often invoked entries) the delay
caused by dmenu waiting for stdin input to be complete is noticeable.

I would prefer if it works like this:
- when you invoke dmenu, it immediately appears, and user can start
typing input. as soon as dmenu is started, it starts reading stdin,
however fast or slow it goes until EOF.
- anytime anything happens (user changes his query or new line is
  read on stdin) the search results are updated in realtime accordingly.

I think the code/algorithms to realize this must be pretty complicated
for it to work nicely (high performance).. But your patches seem
trivial, so did I miss something?

Also, what do you do if the user types something, you feed google
suggest results to stdin, and then the user erases the line and types
something completely different?  the old suggestions are still in
dmenu's datastructure so they can still appear in the search result?

And how exactly do you make sure the suggestions are shown for the
corresponding query?  I would expect you would prefix the suggestions
with the query, but don't see anything like that in your python code.

Dieter



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-26 Thread Connor Lane Smith
Hey,

On 26 November 2010 14:04, Dieter Plaetinck die...@plaetinck.be wrote:
 I would prefer if it works like this:
 - when you invoke dmenu, it immediately appears, and user can start
 typing input. as soon as dmenu is started, it starts reading stdin,
 however fast or slow it goes until EOF.
 - anytime anything happens (user changes his query or new line is
  read on stdin) the search results are updated in realtime accordingly.

 I think the code/algorithms to realize this must be pretty complicated
 for it to work nicely (high performance).. But your patches seem
 trivial, so did I miss something?

No, to do this would be trivial. It's just that certain suckless
people are rather aggressive to the idea of using pthreads for
anything.

On 26 November 2010 13:38, Christophe-Marie Duquesne
chm.duque...@gmail.com wrote:
 1) if invoked with the option -s (-s for stream) dmenu will output
 selected entry on every keystroke (so you can feed a tool with the
 current entry).
 2) in order to avoid waiting for the input stream to finish before
 allowing the user for select entries (and so that you can continue
 feeding it from stdin while you type),  dmenu reads stdin in a thread.

The first aspect of your patch, the incremental output, already
exists.[1] The threaded input is neat, and I am perfectly willing to
add it into dmenu proper. Though I expect others will not share that
willingness.

[1]: http://tools.suckless.org/dmenu/patches/incremental

Thanks,
cls



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-26 Thread Troels Henriksen
Connor Lane Smith c...@lubutu.com writes:

 Hey,

 On 26 November 2010 14:04, Dieter Plaetinck die...@plaetinck.be wrote:
 I would prefer if it works like this:
 - when you invoke dmenu, it immediately appears, and user can start
 typing input. as soon as dmenu is started, it starts reading stdin,
 however fast or slow it goes until EOF.
 - anytime anything happens (user changes his query or new line is
  read on stdin) the search results are updated in realtime accordingly.

 I think the code/algorithms to realize this must be pretty complicated
 for it to work nicely (high performance).. But your patches seem
 trivial, so did I miss something?

 No, to do this would be trivial. It's just that certain suckless
 people are rather aggressive to the idea of using pthreads for
 anything.

If threads are the problem, you could do this with select() easily
enough.  I think people object to the complexity, however.  (I don't -
especially when the alternative is to loose out on a very useful feature
that cannot be implemented in a simpler way.)

-- 
\  Troels
/\ Henriksen



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-26 Thread Anselm R Garbe
On 26 November 2010 15:43, Connor Lane Smith c...@lubutu.com wrote:
 On 26 November 2010 14:04, Dieter Plaetinck die...@plaetinck.be wrote:
 I would prefer if it works like this:
 - when you invoke dmenu, it immediately appears, and user can start
 typing input. as soon as dmenu is started, it starts reading stdin,
 however fast or slow it goes until EOF.
 - anytime anything happens (user changes his query or new line is
  read on stdin) the search results are updated in realtime accordingly.

 I think the code/algorithms to realize this must be pretty complicated
 for it to work nicely (high performance).. But your patches seem
 trivial, so did I miss something?

 No, to do this would be trivial. It's just that certain suckless
 people are rather aggressive to the idea of using pthreads for
 anything.

Well the question is if the bottleneck is the input writer or dmenu
reading the input. The problems I remember from the past where all
related to the input writer (for example dmenu_path taking some time
to create it's output) but not dmenu creating the input item list. If
the latter is a problem now I would like to hear how many input items
are read and what the time penalty is to process them in dmenu, before
considering putting the read into a worker thread.

Cheers,
Anselm



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-26 Thread Connor Lane Smith
On 26 November 2010 15:27, Anselm R Garbe garb...@gmail.com wrote:
 Well the question is if the bottleneck is the input writer or dmenu
 reading the input. The problems I remember from the past where all
 related to the input writer (for example dmenu_path taking some time
 to create it's output) but not dmenu creating the input item list.

That's fair. We could do some testing to see whether dmenu reading a
*lot* of data from a pipe is noticeably slow, or whether it's just
dmenu_path's sorting (which obviously we can't do anything about).

cls



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-26 Thread Christophe-Marie Duquesne
On Fri, Nov 26, 2010 at 3:04 PM, Dieter Plaetinck die...@plaetinck.be wrote:
 the delay caused by dmenu waiting for stdin input to be complete
 is noticeable.

Actually, while performance also matters, the thread thing is not
primarily a matter of fast processing. It is just that if you wait for
the input to finish before allowing the user to interact, you miss the
point of allowing feeding additional entries to this input from the
suggestions (since these suggestions can only happen once user can
interact).

On Fri, Nov 26, 2010 at 3:43 PM, Connor Lane Smith c...@lubutu.com wrote:
 No, to do this would be trivial. It's just that certain suckless
 people are rather aggressive to the idea of using pthreads for
 anything.

I was more or less aware of this but did not see any other options.
@Troels: I did not know select(), but I am going to read about it.

 The first aspect of your patch, the incremental output, already
 exists.

Thank you, I did not know about it.

 The threaded input is neat, and I am perfectly willing to
 add it into dmenu proper. Though I expect others will not share that
 willingness.

It isn't. I experimented a crash when messing with it, so expect to find bugs.



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-26 Thread Connor Lane Smith
On 26 November 2010 15:30, Connor Lane Smith c...@lubutu.com wrote:
 That's fair. We could do some testing to see whether dmenu reading a
 *lot* of data from a pipe is noticeably slow, or whether it's just
 dmenu_path's sorting (which obviously we can't do anything about).

That said, if the source of the pipe prints items incrementally
(because it doesn't have to sort, for example) it would speed up dmenu
significantly, even though dmenu is not the source of the block. In
that respect threading could be useful.

Running `find | dmenu` would take an age to bring up dmenu with the
current model, but with threading it would appear instantly and then
start to be populated. (readstdin would need to make calls to
drawmenu).

cls



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-26 Thread Anselm R Garbe
On 26 November 2010 16:30, Connor Lane Smith c...@lubutu.com wrote:
 On 26 November 2010 15:27, Anselm R Garbe garb...@gmail.com wrote:
 Well the question is if the bottleneck is the input writer or dmenu
 reading the input. The problems I remember from the past where all
 related to the input writer (for example dmenu_path taking some time
 to create it's output) but not dmenu creating the input item list.

 That's fair. We could do some testing to see whether dmenu reading a
 *lot* of data from a pipe is noticeably slow, or whether it's just
 dmenu_path's sorting (which obviously we can't do anything about).

With vanilla dmenu

seq 10 | dmenu

works instantaneously for me. I see some 2s lack if I increase to seq
100 | dmenu though.
But is 1M items a usual scenario? I kind of doubt that and the 2s
penalty doesn't sound too bad imho.

Cheers,
Anselm



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-26 Thread Connor Lane Smith
On 26 November 2010 15:33, Christophe-Marie Duquesne
chm.duque...@gmail.com wrote:
  The threaded input is neat, and I am perfectly willing to
  add it into dmenu proper. Though I expect others will not share that
  willingness.

 It isn't. I experimented a crash when messing with it, so expect to find bugs.

I meant 'neat' in the sense of 'cool'... If we were to integrate it we
would definitely do a thorough debugging beforehand. Though it does
occur to me that we may need to use locking. Which ... suddenly makes
the whole idea look a lot less quick and easy.

On 26 November 2010 15:36, Anselm R Garbe garb...@gmail.com wrote:
 works instantaneously for me. I see some 2s lack if I increase to seq
 100 | dmenu though.
 But is 1M items a usual scenario? I kind of doubt that and the 2s
 penalty doesn't sound too bad imho.

Yeah, that seems pretty fast, though obviously seq is a very fast
process: my second response was a stronger argument. But having
remembered locking, I'm a lot less eager to do this. .

cls



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-26 Thread Anselm R Garbe
On 26 November 2010 16:33, Christophe-Marie Duquesne
chm.duque...@gmail.com wrote:
 On Fri, Nov 26, 2010 at 3:04 PM, Dieter Plaetinck die...@plaetinck.be wrote:
 the delay caused by dmenu waiting for stdin input to be complete
 is noticeable.

 Actually, while performance also matters, the thread thing is not
 primarily a matter of fast processing. It is just that if you wait for
 the input to finish before allowing the user to interact, you miss the
 point of allowing feeding additional entries to this input from the
 suggestions (since these suggestions can only happen once user can
 interact).

Ok that's a better reason for it.

 On Fri, Nov 26, 2010 at 3:43 PM, Connor Lane Smith c...@lubutu.com wrote:
 No, to do this would be trivial. It's just that certain suckless
 people are rather aggressive to the idea of using pthreads for
 anything.

 I was more or less aware of this but did not see any other options.
 @Troels: I did not know select(), but I am going to read about it.

 The first aspect of your patch, the incremental output, already
 exists.

 Thank you, I did not know about it.

 The threaded input is neat, and I am perfectly willing to
 add it into dmenu proper. Though I expect others will not share that
 willingness.

 It isn't. I experimented a crash when messing with it, so expect to find bugs.

I guess those crashes are related to concurrent accesses to the same
data structure. In the end the thread would need to work on a copy and
the items propagation would need to be protected by a mutex. Hence
things will become a bit ugly.

I don't think the select() approach would increase the readability a
lot, but at least it would implicitly disallow concurrent accesses to
items.

I think overall the threaded version should be favored, for now as a
patch I would say.

Cheers,
Anselm



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-26 Thread Anselm R Garbe
On Fri, Nov 26, 2010 at 04:42:36PM +0100, Christophe-Marie Duquesne wrote:
 On Fri, Nov 26, 2010 at 4:36 PM, Anselm R Garbe garb...@gmail.com wrote:
  With vanilla dmenu
 
  seq 10 | dmenu
 
  works instantaneously for me. I see some 2s lack if I increase to seq
  100 | dmenu though.
  But is 1M items a usual scenario? I kind of doubt that and the 2s
  penalty doesn't sound too bad imho.
 
 Again, this is not a matter of performance. Hints can be provided only
 once the user can interact. If you read, _then_ allow user
 interaction, you cannot add hints since you don't read anymore. You
 have to allow interaction _while_ still reading if you want to feed
 dmenu with hints from what is currently being typed.

Ok, but for this scenario select() would be a better candidate, as you can also
block input processing from the X server until your incremental input has been
read and you can avoid synchronising with some ugly mutex.

-Anselm



Re: [dev] [hack] Having dmenu provide hints about current selected entry

2010-11-26 Thread Dieter Plaetinck
On Fri, 26 Nov 2010 16:33:51 +0100
Christophe-Marie Duquesne chm.duque...@gmail.com wrote:

 On Fri, Nov 26, 2010 at 3:04 PM, Dieter Plaetinck
 die...@plaetinck.be wrote:
  the delay caused by dmenu waiting for stdin input to be complete
  is noticeable.
 
 Actually, while performance also matters, the thread thing is not
 primarily a matter of fast processing. It is just that if you wait for
 the input to finish before allowing the user to interact, you miss the
 point of allowing feeding additional entries to this input from the
 suggestions (since these suggestions can only happen once user can
 interact).

Yes, I just wanted to explain my use case, which is different then
yours.
Anselm questioned earlier whether the writer (dmenu_path and whatnot)
or the reader (dmenu) is the slow one, as far as i've seen it's always
the writer.  But that doesn't change my point at all. I just want to be
able to start typing asap, the input writer is usually fast enough to
catch up before I'm done typing anyway.  But I don't like to needlessly
wait before dmenu appears.  Again, this is the concern in my use case,
which is different then yours.

Dieter