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
