gui: Speed up window refresh.
authorAndre Noll <maan@systemlinux.org>
Mon, 6 Jan 2014 20:12:38 +0000 (20:12 +0000)
committerAndre Noll <maan@systemlinux.org>
Sun, 4 May 2014 13:48:55 +0000 (15:48 +0200)
We had way too many calls to wrefresh() which copies the named
window to the physical terminal screen. This slows down the display
considerably, especially on slow machines.

It is more efficient to perform the copy only once per scheduler
iteration. So this commit adds a flag "needs_update" to struct
gui_window, and all callers to wrefresh() are changed to call
refresh_window() instead. This new function is much cheaper since it
only turns on the needs_update flag but does nothing else.

In input_post_select() we check which windows have the flag set and
repaint those windows using wnoutrefresh() and then doupdate(). This
two-step approach is described in the curs_refresh(3X) man page as
more efficient then calling wrefresh() for each window separately
since it avoids alternating calls to wnoutrefresh() and doupdate().

gui.c

diff --git a/gui.c b/gui.c
index 8d84e46..4f536c5 100644 (file)
--- a/gui.c
+++ b/gui.c
@@ -32,6 +32,7 @@ static char *stat_content[NUM_STAT_ITEMS];
 
 static struct gui_window {
        WINDOW *win;
+       bool needs_update;
 } top, bot, sb, in, sep;
 
 #define RINGBUFFER_SIZE 512
@@ -296,6 +297,17 @@ static int align_str(WINDOW* win, char *str, unsigned int len,
        return 1;
 }
 
+static void refresh_window(struct gui_window *gw)
+{
+       gw->needs_update = true;
+}
+
+static bool window_update_needed(void)
+{
+       return top.needs_update || bot.needs_update || sb.needs_update ||
+               in.needs_update || sep.needs_update;
+}
+
 __printf_2_3 static void print_in_bar(int color, const char *fmt,...)
 {
        char *msg;
@@ -310,7 +322,7 @@ __printf_2_3 static void print_in_bar(int color, const char *fmt,...)
        wmove(in.win, 0, 0);
        align_str(in.win, msg, get_num_cols(&in), LEFT);
        free(msg);
-       wrefresh(in.win);
+       refresh_window(&in);
 }
 
 static void print_status_bar(void)
@@ -406,7 +418,7 @@ static void redraw_bot_win(void)
                waddstr(bot.win, rbe->msg);
        }
 out:
-       wrefresh(bot.win);
+       refresh_window(&bot);
 }
 
 static void rb_add_entry(int color, char *msg)
@@ -453,7 +465,7 @@ __printf_2_3 static void outputf(int color, const char* fmt,...)
        xvasprintf(&msg, fmt, ap);
        va_end(ap);
        rb_add_entry(color, msg);
-       wrefresh(bot.win);
+       refresh_window(&bot);
 }
 
 static int add_output_line(char *line, void *data)
@@ -480,7 +492,7 @@ static __printf_2_3 void curses_log(int ll, const char *fmt,...)
                if (bytes > 0 && msg[bytes - 1] == '\n')
                        msg[bytes - 1] = '\0'; /* cut trailing newline */
                rb_add_entry(color, msg);
-               wrefresh(bot.win);
+               refresh_window(&bot);
        } else if (exec_pid <= 0) /* no external command running */
                vfprintf(stderr, fmt, ap);
        va_end(ap);
@@ -522,11 +534,10 @@ static void print_stat_item(int i)
                return;
        tmp = make_message("%s%s%s", d.prefix, c, d.postfix);
        wmove(top.win, d.y * top_lines / 100, d.x * COLS / 100);
-       wrefresh(top.win);
        wattron(top.win, COLOR_PAIR(i + 1));
        align_str(top.win, tmp, d.len * COLS / 100, d.align);
        free(tmp);
-       wrefresh(top.win);
+       refresh_window(&top);
 }
 
 static int update_item(int item_num, char *buf)
@@ -959,7 +970,7 @@ static int exec_post_select(struct sched *s, struct task *t)
                ct->cbo[i] = for_each_line(ct->flags[i], ct->command_buf[i],
                        ct->cbo[i], add_output_line, &i);
                if (sz != ct->cbo[i]) { /* at least one line found */
-                       wrefresh(bot.win);
+                       refresh_window(&bot);
                        ct->flags[i] = 0;
                }
                if (ret < 0 || exec_pid == 0) {
@@ -986,6 +997,8 @@ static void input_pre_select(struct sched *s, __a_unused struct task *t)
 {
        if (exec_status() != EXEC_XCMD)
                para_fd_set(STDIN_FILENO, &s->rfds, &s->max_fileno);
+       if (window_update_needed())
+               sched_min_delay(s);
 }
 
 /* read from command pipe and print data to bot window */
@@ -1084,6 +1097,21 @@ static int input_post_select(__a_unused struct sched *s, __a_unused struct task
 
        if (exs == EXEC_XCMD)
                return 0;
+       if (window_update_needed()) {
+               if (top.needs_update)
+                       assert(wnoutrefresh(top.win) == OK);
+               if (bot.needs_update)
+                       assert(wnoutrefresh(bot.win) == OK);
+               if (sep.needs_update)
+                       assert(wnoutrefresh(sep.win) == OK);
+               if (sb.needs_update)
+                       assert(wnoutrefresh(sb.win) == OK);
+               if (in.needs_update)
+                       assert(wnoutrefresh(in.win) == OK);
+               doupdate();
+               top.needs_update = bot.needs_update = sb.needs_update =
+                       in.needs_update = sep.needs_update = false;
+       }
        ret = wgetch(top.win);
        if (ret == ERR || ret == KEY_RESIZE)
                return 0;
@@ -1201,7 +1229,7 @@ static void com_scroll_down(void)
        wmove(bot.win, bot_lines - rbe_lines, 0);
        wattron(bot.win, COLOR_PAIR(rbe->color));
        waddstr(bot.win, rbe->msg);
-       wrefresh(bot.win);
+       refresh_window(&bot);
        print_scroll_msg();
 }
 
@@ -1238,7 +1266,7 @@ static void com_scroll_up(void)
                        break;
                i--;
        }
-       wrefresh(bot.win);
+       refresh_window(&bot);
        print_scroll_msg();
        return;
 err_out: