This serie of patches try fix the problem of the timeout in main loop, which
causes st wakeup each 20 ms even thare is noting to do.

Please send comments and suggestion.

Best regards.
>From 48aac423ea93820f8a406da3f4e53c8ce4bcb2a6 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <[email protected]>
Date: Fri, 14 Sep 2012 21:09:51 +0200
Subject:  Call XdbeQueryExtension before of calling any Xdbe
 function

XdbeQueryExtension() tells to the caller if the Xdbe extension is present in
the X server, so it should be called for sanity. But like is said in
XdbeQueryExtension(3):

	No other Xdbe functions may be called before this function.  If a
	client violates this rule, the effects of all subsequent Xdbe calls
	that it makes are undefined.

it is mandatory call this function.
---
 st.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 2e1ac67..b013bca 100644
--- a/st.c
+++ b/st.c
@@ -1970,7 +1970,7 @@ xinit(void) {
 	XSetWindowAttributes attrs;
 	Cursor cursor;
 	Window parent;
-	int sw, sh;
+	int sw, sh, major, minor;
 
 	if(!(xw.dpy = XOpenDisplay(NULL)))
 		die("Can't open display\n");
@@ -2021,9 +2021,10 @@ xinit(void) {
 			CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
 			| CWColormap,
 			&attrs);
+	if(!XdbeQueryExtension(xw.dpy, &major, &minor))
+		die("Xdbe extension is not present\n");
 	xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, XdbeCopied);
 
-
 	/* input methods */
 	xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
 	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
-- 
1.7.10.4

>From 56695b6abf41b1d3b7880666d959b7dadef741da Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <[email protected]>
Date: Sat, 15 Sep 2012 12:03:37 +0200
Subject:  Call XSync in redraw

It is necessary call to XSync if you want a good tput flash, because in
other way you can not be sure that white screen will be shown.
---
 st.c |    1 +
 1 file changed, 1 insertion(+)

diff --git a/st.c b/st.c
index b013bca..f4ad23d 100644
--- a/st.c
+++ b/st.c
@@ -2150,6 +2150,7 @@ redraw(void) {
 	struct timespec tv = {0, REDRAW_TIMEOUT * 1000};
 	tfulldirt();
 	draw();
+	XSync(xw.dpy, False); /* necessary for a good tput flash */
 	nanosleep(&tv, NULL);
 }
 
-- 
1.7.10.4

>From 124fe0dd1575401437093d1f6396ca7655ca5680 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <[email protected]>
Date: Sat, 15 Sep 2012 20:55:27 +0200
Subject:  Remove timeout in the main loop

The main loop waits until there is some data to read in file descriptors of
the X server or the pseudo tty. But it uses a timeout in select(), which
causes that st awake each 20 ms, even it doesn't have something to do. This
patch removes this problem removing the timeout, which is not needed.
---
 TODO |    1 -
 st.c |   27 +++------------------------
 2 files changed, 3 insertions(+), 25 deletions(-)

diff --git a/TODO b/TODO
index 1996137..c77c105 100644
--- a/TODO
+++ b/TODO
@@ -15,7 +15,6 @@ code & interface
 
 * clean selection code
 * clean and complete terminfo entry
-* remove the timeouts in the main loop
 
 bugs
 ----
diff --git a/st.c b/st.c
index f4ad23d..d7ca875 100644
--- a/st.c
+++ b/st.c
@@ -53,8 +53,6 @@
 #define XK_NO_MOD     UINT_MAX
 #define XK_ANY_MOD    0
 
-#define SELECT_TIMEOUT (20*1000) /* 20 ms */
-#define DRAW_TIMEOUT  (20*1000) /* 20 ms */
 #define REDRAW_TIMEOUT (80*1000) /* 80 ms */
 
 #define SERRNO strerror(errno)
@@ -205,7 +203,6 @@ typedef struct {
 	int ch; /* char height */
 	int cw; /* char width  */
 	char state; /* focus, redraw, visible */
-	struct timeval lastdraw;
 } XWindow;
 
 typedef struct {
@@ -250,7 +247,6 @@ static void drawregion(int, int, int, int);
 static void execsh(void);
 static void sigchld(int);
 static void run(void);
-static bool last_draw_too_old(void);
 
 static void csidump(void);
 static void csihandle(void);
@@ -2158,7 +2154,6 @@ void
 draw() {
 	drawregion(0, 0, term.col, term.row);
 	xcopy();
-	gettimeofday(&xw.lastdraw, NULL);
 }
 
 void
@@ -2345,41 +2340,25 @@ resize(XEvent *e) {
 	ttyresize(col, row);
 }
 
-bool
-last_draw_too_old(void) {
-	struct timeval now;
-	gettimeofday(&now, NULL);
-	return TIMEDIFF(now, xw.lastdraw) >= DRAW_TIMEOUT/1000;
-}
-
 void
 run(void) {
 	XEvent ev;
 	fd_set rfd;
 	int xfd = XConnectionNumber(xw.dpy);
-	struct timeval timeout = {0};
-	bool stuff_to_print = 0;
 
 	for(;;) {
 		FD_ZERO(&rfd);
 		FD_SET(cmdfd, &rfd);
 		FD_SET(xfd, &rfd);
-		timeout.tv_sec  = 0;
-		timeout.tv_usec = SELECT_TIMEOUT;
-		if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, &timeout) < 0) {
+		if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL) < 0) {
 			if(errno == EINTR)
 				continue;
 			die("select failed: %s\n", SERRNO);
 		}
-		if(FD_ISSET(cmdfd, &rfd)) {
+		if(FD_ISSET(cmdfd, &rfd))
 			ttyread();
-			stuff_to_print = 1;
-		}
 
-		if(stuff_to_print && last_draw_too_old()) {
-			stuff_to_print = 0;
-			draw();
-		}
+		draw();
 
 		while(XPending(xw.dpy)) {
 			XNextEvent(xw.dpy, &ev);
-- 
1.7.10.4

>From 347fa32bdb76500d14b7ceb5401a1e8b349c32ce Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <[email protected]>
Date: Sat, 15 Sep 2012 21:13:41 +0200
Subject:  Render only once in each main loop iteration

draw() runs over all lines of the screen and renders only the dirty lines,
this avoids render lines which are not modified since last draw() call. In
this moment the main loop is something like:

     - Wait something to read from file descriptors
     - Read from pseudo tty
     - Call draw() for rending
     - Read X events

This cause the problem that all the X events that have to update the screen
have to call draw() (because draw() is called before of X events handling),
so you can have multiples renderings in only one iteration, that will waste
a lot of resources.

This patch change the main loop to:

     - Wait something to read from file descriptors
     - Read from pseudo tty
     - Read X events
     - Call draw() for rending

So X events don't have to worry about rendering, because draw() is called
after them.

The only place where draw is called outside of the main loop is in redraw(),
but it is necessary for getting a good tput flash.
---
 st.c |   29 ++++++-----------------------
 1 file changed, 6 insertions(+), 23 deletions(-)

diff --git a/st.c b/st.c
index d7ca875..397f6a6 100644
--- a/st.c
+++ b/st.c
@@ -288,7 +288,6 @@ static void ttywrite(const char *, size_t);
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
 static void xclear(int, int, int, int);
-static void xcopy(void);
 static void xdrawcursor(void);
 static void xinit(void);
 static void xloadcols(void);
@@ -635,7 +634,6 @@ void selclear(XEvent *e) {
 		return;
 	sel.bx = -1;
 	tsetdirt(sel.b.y, sel.e.y);
-	draw();
 }
 
 void
@@ -685,8 +683,6 @@ xsetsel(char *str) {
 
 	clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
 	XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
-
-	XFlush(xw.dpy);
 }
 
 void
@@ -729,7 +725,6 @@ brelease(XEvent *e) {
 	}
 	memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval));
 	gettimeofday(&sel.tclick1, NULL);
-	draw();
 }
 
 void
@@ -746,7 +741,6 @@ bmotion(XEvent *e) {
 			int starty = MIN(oldey, sel.ey);
 			int endy = MAX(oldey, sel.ey);
 			tsetdirt(starty, endy);
-			draw();
 		}
 	}
 }
@@ -2091,13 +2085,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 		XDrawLine(xw.dpy, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1);
 }
 
-/* copy buffer pixmap to screen pixmap */
-void
-xcopy() {
-	XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
-	XdbeSwapBuffers(xw.dpy, swpinfo, 1);
-}
-
 void
 xdrawcursor(void) {
 	static int oldx = 0;
@@ -2118,8 +2105,6 @@ xdrawcursor(void) {
 	} else
 		xclear(oldx, oldy, oldx, oldy);
 
-	xcopy();
-
 	/* draw the new one */
 	if(!(term.c.state & CURSOR_HIDE)) {
 		if(!(xw.state & WIN_FOCUSED))
@@ -2132,8 +2117,6 @@ xdrawcursor(void) {
 		xdraws(g.c, g, term.c.x, term.c.y, 1, sl);
 		oldx = term.c.x, oldy = term.c.y;
 	}
-
-	xcopy();
 }
 
 void
@@ -2152,8 +2135,10 @@ redraw(void) {
 
 void
 draw() {
+	XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
+
 	drawregion(0, 0, term.col, term.row);
-	xcopy();
+	XdbeSwapBuffers(xw.dpy, swpinfo, 1);
 }
 
 void
@@ -2208,7 +2193,6 @@ expose(XEvent *ev) {
 		if(!e->count)
 			xw.state &= ~WIN_REDRAW;
 	}
-	xcopy();
 }
 
 void
@@ -2241,7 +2225,6 @@ focus(XEvent *ev) {
 		xseturgency(0);
 	} else
 		xw.state &= ~WIN_FOCUSED;
-	draw();
 }
 
 char*
@@ -2317,7 +2300,6 @@ cmessage(XEvent *e) {
 		} else if(e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
 			xw.state &= ~WIN_FOCUSED;
 		}
-		draw();
 	}
 }
 
@@ -2358,8 +2340,6 @@ run(void) {
 		if(FD_ISSET(cmdfd, &rfd))
 			ttyread();
 
-		draw();
-
 		while(XPending(xw.dpy)) {
 			XNextEvent(xw.dpy, &ev);
 			if(XFilterEvent(&ev, xw.win))
@@ -2367,6 +2347,9 @@ run(void) {
 			if(handler[ev.type])
 				(handler[ev.type])(&ev);
 		}
+
+		draw();
+		XFlush(xw.dpy);
 	}
 }
 
-- 
1.7.10.4

>From 2186b3717a52c06c34d5927fad4b1fbfb5bf3568 Mon Sep 17 00:00:00 2001
From: "Roberto E. Vargas Caballero" <[email protected]>
Date: Sun, 16 Sep 2012 09:19:45 +0200
Subject:  Fix selection bug

After the commit named "Remove timeout in the main loop", selection is not
working in the proper way. After selecting something, press mouse button in
a line outside of selection causes an incorrect highlight. This patch fix
the problem forcing a draw after the press event, but this is only a fast
hack. Real solution means rewriting selection code.
---
 st.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/st.c b/st.c
index 397f6a6..12d6665 100644
--- a/st.c
+++ b/st.c
@@ -561,8 +561,11 @@ bpress(XEvent *e) {
 	if(IS_SET(MODE_MOUSE))
 		mousereport(e);
 	else if(e->xbutton.button == Button1) {
-		if(sel.bx != -1)
+		if(sel.bx != -1) {
+			sel.bx = -1;
 			tsetdirt(sel.b.y, sel.e.y);
+			draw();
+		}
 		sel.mode = 1;
 		sel.ex = sel.bx = X2COL(e->xbutton.x);
 		sel.ey = sel.by = Y2ROW(e->xbutton.y);
-- 
1.7.10.4

Reply via email to