Postpone redraws

This solves a performance problem in debug mode.

But overall the has been simplified, with some renames taking place.
This commit is contained in:
Přemysl Eric Janouch 2016-10-04 23:39:32 +02:00
parent 07e3aafd84
commit 515d11114b
Signed by: p
GPG Key ID: B715679E3A361BE6
1 changed files with 68 additions and 58 deletions

126
nncmpp.c
View File

@ -240,12 +240,14 @@ static struct app_context
// Emulated widgets: // Emulated widgets:
int top_height; ///< Height of the top part int header_height; ///< Height of the header
int controls_offset; ///< Offset to player controls or -1 int controls_offset; ///< Offset to player controls or -1
int gauge_offset; ///< Offset to the gauge or -1 int gauge_offset; ///< Offset to the gauge or -1
int gauge_width; ///< Width of the gauge, if present int gauge_width; ///< Width of the gauge, if present
struct poller_idle refresh_event; ///< Refresh the screen
// Terminal: // Terminal:
termo_t *tk; ///< termo handle termo_t *tk; ///< termo handle
@ -662,6 +664,15 @@ row_buffer_flush (struct row_buffer *self)
// --- Rendering --------------------------------------------------------------- // --- Rendering ---------------------------------------------------------------
// TODO: rewrite this so that it's fine-grained but not complicated
static void
app_invalidate (void)
{
poller_idle_set (&g_ctx.refresh_event);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/// Write the given UTF-8 string padded with spaces. /// Write the given UTF-8 string padded with spaces.
/// @param[in] attrs Text attributes for the text, including padding. /// @param[in] attrs Text attributes for the text, including padding.
static void static void
@ -684,7 +695,7 @@ app_write_line (const char *str, chtype attrs)
static void static void
app_next_row (chtype attrs) app_next_row (chtype attrs)
{ {
mvwhline (stdscr, g_ctx.top_height++, 0, ' ' | attrs, COLS); mvwhline (stdscr, g_ctx.header_height++, 0, ' ' | attrs, COLS);
} }
// We typically write here to a single buffer serving the entire line // We typically write here to a single buffer serving the entire line
@ -700,7 +711,7 @@ app_flush_buffer (struct row_buffer *buf, chtype attrs)
} }
static void static void
app_redraw_song_info (void) app_draw_song_info (void)
{ {
// The map doesn't need to be initialized at all, so we need to check // The map doesn't need to be initialized at all, so we need to check
struct str_map *map = &g_ctx.song_info; struct str_map *map = &g_ctx.song_info;
@ -794,10 +805,10 @@ app_write_gauge (struct row_buffer *buf, float ratio, int width)
} }
static void static void
app_redraw_status (void) app_draw_status (void)
{ {
if (g_ctx.state != PLAYER_STOPPED) if (g_ctx.state != PLAYER_STOPPED)
app_redraw_song_info (); app_draw_song_info ();
// XXX: can we get rid of this and still make it look acceptable? // XXX: can we get rid of this and still make it look acceptable?
chtype a_normal = APP_ATTR (HEADER); chtype a_normal = APP_ATTR (HEADER);
@ -861,15 +872,15 @@ app_redraw_status (void)
row_buffer_append (&buf, volume, a_normal); row_buffer_append (&buf, volume, a_normal);
free (volume); free (volume);
} }
g_ctx.controls_offset = g_ctx.top_height; g_ctx.controls_offset = g_ctx.header_height;
app_flush_buffer (&buf, a_normal); app_flush_buffer (&buf, a_normal);
} }
static void static void
app_redraw_top (void) app_draw_header (void)
{ {
// TODO: when it changes from the previous value, fix the selection // TODO: call app_fix_view_range() if it changes from the previous value
g_ctx.top_height = 0; g_ctx.header_height = 0;
g_ctx.controls_offset = -1; g_ctx.controls_offset = -1;
g_ctx.gauge_offset = -1; g_ctx.gauge_offset = -1;
@ -878,7 +889,7 @@ app_redraw_top (void)
switch (g_ctx.client.state) switch (g_ctx.client.state)
{ {
case MPD_CONNECTED: case MPD_CONNECTED:
app_redraw_status (); app_draw_status ();
break; break;
case MPD_CONNECTING: case MPD_CONNECTING:
app_next_row (APP_ATTR (HEADER)); app_next_row (APP_ATTR (HEADER));
@ -907,18 +918,17 @@ app_redraw_top (void)
iter == g_ctx.active_tab ? a_active : a_normal); iter == g_ctx.active_tab ? a_active : a_normal);
} }
app_flush_buffer (&buf, a_normal); app_flush_buffer (&buf, a_normal);
refresh ();
} }
static int static int
app_visible_items (void) app_visible_items (void)
{ {
// This may eventually include a header bar and/or a status bar // This may eventually include a header bar and/or a status bar
return MAX (0, LINES - g_ctx.top_height); return MAX (0, LINES - g_ctx.header_height);
} }
static void static void
app_redraw_scrollbar (void) app_draw_scrollbar (void)
{ {
// This assumes that we can write to the one-before-last column, // This assumes that we can write to the one-before-last column,
// i.e. that it's not covered by any double-wide character (and that // i.e. that it's not covered by any double-wide character (and that
@ -939,7 +949,7 @@ app_redraw_scrollbar (void)
for (int row = 0; row < visible_items; row++) for (int row = 0; row < visible_items; row++)
{ {
move (g_ctx.top_height + row, COLS - 1); move (g_ctx.header_height + row, COLS - 1);
if (row < start || row > start + length + 1) if (row < start || row > start + length + 1)
addch (' ' | APP_ATTR (SCROLLBAR)); addch (' ' | APP_ATTR (SCROLLBAR));
else else
@ -974,7 +984,7 @@ app_redraw_scrollbar (void)
if (row == start) c = partials[start_part]; if (row == start) c = partials[start_part];
if (row == end) c = partials[end_part]; if (row == end) c = partials[end_part];
move (g_ctx.top_height + row, COLS - 1); move (g_ctx.header_height + row, COLS - 1);
struct row_buffer buf; struct row_buffer buf;
row_buffer_init (&buf); row_buffer_init (&buf);
@ -985,16 +995,16 @@ app_redraw_scrollbar (void)
} }
static void static void
app_redraw_view (void) app_draw_view (void)
{ {
move (g_ctx.top_height, 0); move (g_ctx.header_height, 0);
clrtobot (); clrtobot ();
struct tab *tab = g_ctx.active_tab; struct tab *tab = g_ctx.active_tab;
bool want_scrollbar = (int) tab->item_count > app_visible_items (); bool want_scrollbar = (int) tab->item_count > app_visible_items ();
int view_width = COLS - want_scrollbar; int view_width = COLS - want_scrollbar;
int to_show = MIN (LINES - g_ctx.top_height, int to_show = MIN (LINES - g_ctx.header_height,
(int) tab->item_count - tab->item_top); (int) tab->item_count - tab->item_top);
for (int row = 0; row < to_show; row++) for (int row = 0; row < to_show; row++)
{ {
@ -1004,7 +1014,7 @@ app_redraw_view (void)
row_attrs = APP_ATTR (SELECTION); row_attrs = APP_ATTR (SELECTION);
attrset (row_attrs); attrset (row_attrs);
mvwhline (stdscr, g_ctx.top_height + row, 0, ' ', COLS); mvwhline (stdscr, g_ctx.header_height + row, 0, ' ', COLS);
struct row_buffer buf; struct row_buffer buf;
row_buffer_init (&buf); row_buffer_init (&buf);
@ -1025,16 +1035,19 @@ app_redraw_view (void)
attrset (0); attrset (0);
if (want_scrollbar) if (want_scrollbar)
app_redraw_scrollbar (); app_draw_scrollbar ();
refresh ();
} }
static void static void
app_redraw (void) app_on_refresh (void *user_data)
{ {
app_redraw_top (); (void) user_data;
app_redraw_view (); poller_idle_reset (&g_ctx.refresh_event);
app_draw_header ();
app_draw_view ();
refresh ();
} }
// --- Actions ----------------------------------------------------------------- // --- Actions -----------------------------------------------------------------
@ -1047,6 +1060,7 @@ app_fix_view_range (void)
if (tab->item_top < 0) if (tab->item_top < 0)
{ {
tab->item_top = 0; tab->item_top = 0;
app_invalidate ();
return false; return false;
} }
@ -1058,6 +1072,7 @@ app_fix_view_range (void)
if (tab->item_top > max_item_top) if (tab->item_top > max_item_top)
{ {
tab->item_top = max_item_top; tab->item_top = max_item_top;
app_invalidate ();
return false; return false;
} }
return true; return true;
@ -1068,6 +1083,7 @@ static bool
app_scroll (int n) app_scroll (int n)
{ {
g_ctx.active_tab->item_top += n; g_ctx.active_tab->item_top += n;
app_invalidate ();
return app_fix_view_range (); return app_fix_view_range ();
} }
@ -1098,12 +1114,19 @@ app_move_selection (int diff)
bool result = tab->item_selected != fixed; bool result = tab->item_selected != fixed;
tab->item_selected = fixed; tab->item_selected = fixed;
app_invalidate ();
app_ensure_selection_visible (); app_ensure_selection_visible ();
app_redraw_view ();
return result; return result;
} }
static void
app_switch_tab (struct tab *tab)
{
g_ctx.active_tab = tab;
app_invalidate ();
}
static bool static bool
app_goto_tab (int tab_index) app_goto_tab (int tab_index)
{ {
@ -1111,8 +1134,7 @@ app_goto_tab (int tab_index)
LIST_FOR_EACH (struct tab, iter, g_ctx.tabs) LIST_FOR_EACH (struct tab, iter, g_ctx.tabs)
if (i++ == tab_index) if (i++ == tab_index)
{ {
g_ctx.active_tab = iter; app_switch_tab (iter);
app_redraw ();
return true; return true;
} }
return false; return false;
@ -1185,7 +1207,7 @@ app_process_user_action (enum user_action action)
return false; return false;
case USER_ACTION_REDRAW: case USER_ACTION_REDRAW:
clear (); clear ();
app_redraw (); app_invalidate ();
return true; return true;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1232,11 +1254,9 @@ app_process_user_action (enum user_action action)
// XXX: these should rather be parametrized // XXX: these should rather be parametrized
case USER_ACTION_SCROLL_UP: case USER_ACTION_SCROLL_UP:
app_scroll (-3); app_scroll (-3);
app_redraw_view ();
return true; return true;
case USER_ACTION_SCROLL_DOWN: case USER_ACTION_SCROLL_DOWN:
app_scroll (3); app_scroll (3);
app_redraw_view ();
return true; return true;
case USER_ACTION_GOTO_TOP: case USER_ACTION_GOTO_TOP:
@ -1244,7 +1264,6 @@ app_process_user_action (enum user_action action)
{ {
g_ctx.active_tab->item_selected = 0; g_ctx.active_tab->item_selected = 0;
app_ensure_selection_visible (); app_ensure_selection_visible ();
app_redraw_view ();
} }
return true; return true;
case USER_ACTION_GOTO_BOTTOM: case USER_ACTION_GOTO_BOTTOM:
@ -1253,7 +1272,6 @@ app_process_user_action (enum user_action action)
g_ctx.active_tab->item_selected = g_ctx.active_tab->item_selected =
(int) g_ctx.active_tab->item_count - 1; (int) g_ctx.active_tab->item_count - 1;
app_ensure_selection_visible (); app_ensure_selection_visible ();
app_redraw_view ();
} }
return true; return true;
@ -1265,12 +1283,12 @@ app_process_user_action (enum user_action action)
return true; return true;
case USER_ACTION_GOTO_PAGE_PREVIOUS: case USER_ACTION_GOTO_PAGE_PREVIOUS:
app_scroll ((int) g_ctx.top_height - LINES); app_scroll ((int) g_ctx.header_height - LINES);
app_move_selection ((int) g_ctx.top_height - LINES); app_move_selection ((int) g_ctx.header_height - LINES);
return true; return true;
case USER_ACTION_GOTO_PAGE_NEXT: case USER_ACTION_GOTO_PAGE_NEXT:
app_scroll (LINES - (int) g_ctx.top_height); app_scroll (LINES - (int) g_ctx.header_height);
app_move_selection (LINES - (int) g_ctx.top_height); app_move_selection (LINES - (int) g_ctx.header_height);
return true; return true;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1322,14 +1340,13 @@ app_process_left_mouse_click (int line, int column)
return; return;
} }
} }
else if (line == g_ctx.top_height - 1) else if (line == g_ctx.header_height - 1)
{ {
struct tab *winner = NULL; struct tab *winner = NULL;
int indent = strlen (APP_TITLE); int indent = strlen (APP_TITLE);
if (column < indent) if (column < indent)
{ {
g_ctx.active_tab = g_ctx.help_tab; app_switch_tab (g_ctx.help_tab);
app_redraw ();
return; return;
} }
for (struct tab *iter = g_ctx.tabs; !winner && iter; iter = iter->next) for (struct tab *iter = g_ctx.tabs; !winner && iter; iter = iter->next)
@ -1338,15 +1355,12 @@ app_process_left_mouse_click (int line, int column)
winner = iter; winner = iter;
} }
if (winner) if (winner)
{ app_switch_tab (winner);
g_ctx.active_tab = winner;
app_redraw ();
}
} }
else else
{ {
struct tab *tab = g_ctx.active_tab; struct tab *tab = g_ctx.active_tab;
int row_index = line - g_ctx.top_height; int row_index = line - g_ctx.header_height;
if (row_index < 0 if (row_index < 0
|| row_index >= (int) tab->item_count - tab->item_top) || row_index >= (int) tab->item_count - tab->item_top)
return; return;
@ -1361,7 +1375,7 @@ app_process_left_mouse_click (int line, int column)
} }
else else
tab->item_selected = row_index + tab->item_top; tab->item_selected = row_index + tab->item_top;
app_redraw_view (); app_invalidate ();
} }
} }
@ -1622,7 +1636,7 @@ mpd_on_info_response (const struct mpd_response *response,
g_ctx.volume = tmp; g_ctx.volume = tmp;
g_ctx.song_info = map; g_ctx.song_info = map;
app_redraw (); app_invalidate ();
} }
static void static void
@ -1637,8 +1651,7 @@ mpd_on_tick (void *user_data)
g_ctx.elapsed_since += elapsed_sec * 1000; g_ctx.elapsed_since += elapsed_sec * 1000;
poller_timer_set (&g_ctx.elapsed_event, 1000 - elapsed_msec); poller_timer_set (&g_ctx.elapsed_event, 1000 - elapsed_msec);
// TODO: try to be more efficient in the redrawing procedures app_invalidate ();
app_redraw ();
} }
static void static void
@ -1895,7 +1908,7 @@ debug_tab_push (const char *message, chtype attrs)
item->attrs = attrs; item->attrs = attrs;
item->timestamp = clock_msec (CLOCK_REALTIME); item->timestamp = clock_msec (CLOCK_REALTIME);
app_redraw_view (); app_invalidate ();
} }
static struct tab * static struct tab *
@ -1990,14 +2003,8 @@ app_on_signal_pipe_readable (const struct pollfd *fd, void *user_data)
if (g_winch_received) if (g_winch_received)
{ {
update_curses_terminal_size (); update_curses_terminal_size ();
app_redraw_top ();
app_fix_view_range (); app_fix_view_range ();
#if SELECTION_SHOULD_BE_VISIBLE_AFTER_RESIZE app_invalidate ();
// First we had to make the assumptions of this valid
app_ensure_selection_visible ();
#endif
app_redraw_view ();
g_winch_received = false; g_winch_received = false;
} }
@ -2062,6 +2069,9 @@ app_init_poller_events (void)
poller_timer_init (&g_ctx.elapsed_event, &g_ctx.poller); poller_timer_init (&g_ctx.elapsed_event, &g_ctx.poller);
g_ctx.elapsed_event.dispatcher = mpd_on_tick; g_ctx.elapsed_event.dispatcher = mpd_on_tick;
poller_idle_init (&g_ctx.refresh_event, &g_ctx.poller);
g_ctx.refresh_event.dispatcher = app_on_refresh;
} }
int int
@ -2130,10 +2140,10 @@ main (int argc, char *argv[])
g_ctx.help_tab = help_tab_create (); g_ctx.help_tab = help_tab_create ();
g_ctx.active_tab = g_ctx.help_tab; g_ctx.active_tab = g_ctx.help_tab;
app_redraw ();
signals_setup_handlers (); signals_setup_handlers ();
app_init_poller_events (); app_init_poller_events ();
app_invalidate ();
g_ctx.polling = true; g_ctx.polling = true;
while (g_ctx.polling) while (g_ctx.polling)