diff options
| author | Aurélien Aptel <aurelien.aptel@gmail.com> | 2012-01-21 23:14:41 +0100 |
|---|---|---|
| committer | Aurélien Aptel <aurelien.aptel@gmail.com> | 2012-01-21 23:14:41 +0100 |
| commit | 896310e5928b6daab5f594acd9648ffe8233022e (patch) | |
| tree | 5f76ce8a7e3090c7e88edeb155f5e5755faebf4e | |
| parent | 13a8eeb810ccfdaefd58c52328dd0ec867e3ae8d (diff) | |
| download | st-896310e5928b6daab5f594acd9648ffe8233022e.tar.gz st-896310e5928b6daab5f594acd9648ffe8233022e.zip | |
copy dirty lines to screen, add select() timeout & min time between draw() calls.
* add a timeout value (SELECT_TIMEOUT) of 20ms in the select() call
* wait at least 20ms (DRAW_TIMEOUT) between draw() calls
* only copy dirty lines from the buffer to the screen
what draw() does:
* clears dirty lines in the buffer
* draws the longest same-attributes string of each
dirty line to the buffer with multiple xdraws() call
* copies the current dirty line from buffer to the screen with a single
xcopy() call
this changeset makes st run ~10x faster.
| -rw-r--r-- | st.c | 53 |
1 files changed, 44 insertions, 9 deletions
| @@ -13,8 +13,10 @@ | |||
| 13 | #include <sys/ioctl.h> | 13 | #include <sys/ioctl.h> |
| 14 | #include <sys/select.h> | 14 | #include <sys/select.h> |
| 15 | #include <sys/stat.h> | 15 | #include <sys/stat.h> |
| 16 | #include <sys/time.h> | ||
| 16 | #include <sys/types.h> | 17 | #include <sys/types.h> |
| 17 | #include <sys/wait.h> | 18 | #include <sys/wait.h> |
| 19 | #include <time.h> | ||
| 18 | #include <unistd.h> | 20 | #include <unistd.h> |
| 19 | #include <X11/Xatom.h> | 21 | #include <X11/Xatom.h> |
| 20 | #include <X11/Xlib.h> | 22 | #include <X11/Xlib.h> |
| @@ -22,9 +24,6 @@ | |||
| 22 | #include <X11/cursorfont.h> | 24 | #include <X11/cursorfont.h> |
| 23 | #include <X11/keysym.h> | 25 | #include <X11/keysym.h> |
| 24 | 26 | ||
| 25 | #include <sys/time.h> | ||
| 26 | #include <time.h> | ||
| 27 | |||
| 28 | #if defined(__linux) | 27 | #if defined(__linux) |
| 29 | #include <pty.h> | 28 | #include <pty.h> |
| 30 | #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) | 29 | #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) |
| @@ -50,6 +49,9 @@ | |||
| 50 | #define XK_NO_MOD UINT_MAX | 49 | #define XK_NO_MOD UINT_MAX |
| 51 | #define XK_ANY_MOD 0 | 50 | #define XK_ANY_MOD 0 |
| 52 | 51 | ||
| 52 | #define SELECT_TIMEOUT (20*1000) /* 20 ms */ | ||
| 53 | #define DRAW_TIMEOUT (20*1000) /* 20 ms */ | ||
| 54 | |||
| 53 | #define SERRNO strerror(errno) | 55 | #define SERRNO strerror(errno) |
| 54 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) | 56 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) |
| 55 | #define MAX(a, b) ((a) < (b) ? (b) : (a)) | 57 | #define MAX(a, b) ((a) < (b) ? (b) : (a)) |
| @@ -138,6 +140,7 @@ typedef struct { | |||
| 138 | int ch; /* char height */ | 140 | int ch; /* char height */ |
| 139 | int cw; /* char width */ | 141 | int cw; /* char width */ |
| 140 | char state; /* focus, redraw, visible */ | 142 | char state; /* focus, redraw, visible */ |
| 143 | struct timeval lastdraw; | ||
| 141 | } XWindow; | 144 | } XWindow; |
| 142 | 145 | ||
| 143 | typedef struct { | 146 | typedef struct { |
| @@ -179,6 +182,7 @@ static void drawregion(int, int, int, int); | |||
| 179 | static void execsh(void); | 182 | static void execsh(void); |
| 180 | static void sigchld(int); | 183 | static void sigchld(int); |
| 181 | static void run(void); | 184 | static void run(void); |
| 185 | static int last_draw_too_old(void); | ||
| 182 | 186 | ||
| 183 | static void csidump(void); | 187 | static void csidump(void); |
| 184 | static void csihandle(void); | 188 | static void csihandle(void); |
| @@ -214,6 +218,7 @@ static void ttywrite(const char *, size_t); | |||
| 214 | static void xdraws(char *, Glyph, int, int, int, int); | 218 | static void xdraws(char *, Glyph, int, int, int, int); |
| 215 | static void xhints(void); | 219 | static void xhints(void); |
| 216 | static void xclear(int, int, int, int); | 220 | static void xclear(int, int, int, int); |
| 221 | static void xcopy(int, int, int, int); | ||
| 217 | static void xdrawcursor(void); | 222 | static void xdrawcursor(void); |
| 218 | static void xinit(void); | 223 | static void xinit(void); |
| 219 | static void xloadcols(void); | 224 | static void xloadcols(void); |
| @@ -224,7 +229,7 @@ static void xresize(int, int); | |||
| 224 | static void expose(XEvent *); | 229 | static void expose(XEvent *); |
| 225 | static void visibility(XEvent *); | 230 | static void visibility(XEvent *); |
| 226 | static void unmap(XEvent *); | 231 | static void unmap(XEvent *); |
| 227 | static char* kmap(KeySym, unsigned int state); | 232 | static char* kmap(KeySym, unsigned int); |
| 228 | static void kpress(XEvent *); | 233 | static void kpress(XEvent *); |
| 229 | static void cmessage(XEvent *); | 234 | static void cmessage(XEvent *); |
| 230 | static void resize(XEvent *); | 235 | static void resize(XEvent *); |
| @@ -1786,6 +1791,14 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { | |||
| 1786 | XDrawLine(xw.dpy, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1); | 1791 | XDrawLine(xw.dpy, xw.buf, dc.gc, winx, winy+1, winx+width-1, winy+1); |
| 1787 | } | 1792 | } |
| 1788 | 1793 | ||
| 1794 | /* copy buffer pixmap to screen pixmap */ | ||
| 1795 | void | ||
| 1796 | xcopy(int x, int y, int cols, int rows) { | ||
| 1797 | int src_x = x*xw.cw, src_y = y*xw.ch, src_w = cols*xw.cw, src_h = rows*xw.ch; | ||
| 1798 | int dst_x = BORDER+src_x, dst_y = BORDER+src_y; | ||
| 1799 | XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, src_x, src_y, src_w, src_h, dst_x, dst_y); | ||
| 1800 | } | ||
| 1801 | |||
| 1789 | void | 1802 | void |
| 1790 | xdrawcursor(void) { | 1803 | xdrawcursor(void) { |
| 1791 | static int oldx = 0; | 1804 | static int oldx = 0; |
| @@ -1805,7 +1818,9 @@ xdrawcursor(void) { | |||
| 1805 | xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, oldy, 1, sl); | 1818 | xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, oldy, 1, sl); |
| 1806 | } else | 1819 | } else |
| 1807 | xclear(oldx, oldy, oldx, oldy); | 1820 | xclear(oldx, oldy, oldx, oldy); |
| 1808 | 1821 | ||
| 1822 | xcopy(oldx, oldy, 1, 1); | ||
| 1823 | |||
| 1809 | /* draw the new one */ | 1824 | /* draw the new one */ |
| 1810 | if(!(term.c.state & CURSOR_HIDE) && (xw.state & WIN_FOCUSED)) { | 1825 | if(!(term.c.state & CURSOR_HIDE) && (xw.state & WIN_FOCUSED)) { |
| 1811 | sl = utf8size(g.c); | 1826 | sl = utf8size(g.c); |
| @@ -1814,11 +1829,14 @@ xdrawcursor(void) { | |||
| 1814 | xdraws(g.c, g, term.c.x, term.c.y, 1, sl); | 1829 | xdraws(g.c, g, term.c.x, term.c.y, 1, sl); |
| 1815 | oldx = term.c.x, oldy = term.c.y; | 1830 | oldx = term.c.x, oldy = term.c.y; |
| 1816 | } | 1831 | } |
| 1832 | |||
| 1833 | xcopy(term.c.x, term.c.y, 1, 1); | ||
| 1817 | } | 1834 | } |
| 1818 | 1835 | ||
| 1819 | void | 1836 | void |
| 1820 | draw() { | 1837 | draw() { |
| 1821 | drawregion(0, 0, term.col, term.row); | 1838 | drawregion(0, 0, term.col, term.row); |
| 1839 | gettimeofday(&xw.lastdraw, NULL); | ||
| 1822 | } | 1840 | } |
| 1823 | 1841 | ||
| 1824 | void | 1842 | void |
| @@ -1859,9 +1877,9 @@ drawregion(int x1, int y1, int x2, int y2) { | |||
| 1859 | } | 1877 | } |
| 1860 | if(ib > 0) | 1878 | if(ib > 0) |
| 1861 | xdraws(buf, base, ox, y, ic, ib); | 1879 | xdraws(buf, base, ox, y, ic, ib); |
| 1880 | xcopy(0, y, term.col, 1); | ||
| 1862 | } | 1881 | } |
| 1863 | xdrawcursor(); | 1882 | xdrawcursor(); |
| 1864 | XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, x1*xw.cw, y1*xw.ch, x2*xw.cw, y2*xw.ch, BORDER, BORDER); | ||
| 1865 | } | 1883 | } |
| 1866 | 1884 | ||
| 1867 | void | 1885 | void |
| @@ -2006,25 +2024,42 @@ resize(XEvent *e) { | |||
| 2006 | xresize(col, row); | 2024 | xresize(col, row); |
| 2007 | } | 2025 | } |
| 2008 | 2026 | ||
| 2027 | int | ||
| 2028 | last_draw_too_old(void) { | ||
| 2029 | struct timeval now; | ||
| 2030 | gettimeofday(&now, NULL); | ||
| 2031 | return TIMEDIFF(now, xw.lastdraw) >= PRINT_TIMEOUT/1000; | ||
| 2032 | } | ||
| 2033 | |||
| 2009 | void | 2034 | void |
| 2010 | run(void) { | 2035 | run(void) { |
| 2011 | XEvent ev; | 2036 | XEvent ev; |
| 2012 | fd_set rfd; | 2037 | fd_set rfd; |
| 2013 | int xfd = XConnectionNumber(xw.dpy); | 2038 | int xfd = XConnectionNumber(xw.dpy); |
| 2014 | 2039 | struct timeval timeout = {0}; | |
| 2040 | int stuff_to_print = 0; | ||
| 2041 | |||
| 2015 | for(;;) { | 2042 | for(;;) { |
| 2016 | FD_ZERO(&rfd); | 2043 | FD_ZERO(&rfd); |
| 2017 | FD_SET(cmdfd, &rfd); | 2044 | FD_SET(cmdfd, &rfd); |
| 2018 | FD_SET(xfd, &rfd); | 2045 | FD_SET(xfd, &rfd); |
| 2019 | if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL) < 0) { | 2046 | timeout.tv_sec = 0; |
| 2047 | timeout.tv_usec = SELECT_TIMEOUT; | ||
| 2048 | if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, &timeout) < 0) { | ||
| 2020 | if(errno == EINTR) | 2049 | if(errno == EINTR) |
| 2021 | continue; | 2050 | continue; |
| 2022 | die("select failed: %s\n", SERRNO); | 2051 | die("select failed: %s\n", SERRNO); |
| 2023 | } | 2052 | } |
| 2024 | if(FD_ISSET(cmdfd, &rfd)) { | 2053 | if(FD_ISSET(cmdfd, &rfd)) { |
| 2025 | ttyread(); | 2054 | ttyread(); |
| 2055 | stuff_to_print = 1; | ||
| 2056 | } | ||
| 2057 | |||
| 2058 | if(stuff_to_print && last_draw_too_old()) { | ||
| 2059 | stuff_to_print = 0; | ||
| 2026 | draw(); | 2060 | draw(); |
| 2027 | } | 2061 | } |
| 2062 | |||
| 2028 | while(XPending(xw.dpy)) { | 2063 | while(XPending(xw.dpy)) { |
| 2029 | XNextEvent(xw.dpy, &ev); | 2064 | XNextEvent(xw.dpy, &ev); |
| 2030 | if(XFilterEvent(&ev, xw.win)) | 2065 | if(XFilterEvent(&ev, xw.win)) |
| @@ -2050,7 +2085,7 @@ main(int argc, char *argv[]) { | |||
| 2050 | case 'w': | 2085 | case 'w': |
| 2051 | if(++i < argc) opt_embed = argv[i]; | 2086 | if(++i < argc) opt_embed = argv[i]; |
| 2052 | break; | 2087 | break; |
| 2053 | case 'e': | 2088 | case 'e': |
| 2054 | /* eat every remaining arguments */ | 2089 | /* eat every remaining arguments */ |
| 2055 | if(++i < argc) opt_cmd = &argv[i]; | 2090 | if(++i < argc) opt_cmd = &argv[i]; |
| 2056 | goto run; | 2091 | goto run; |
