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:
parent
07e3aafd84
commit
515d11114b
126
nncmpp.c
126
nncmpp.c
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue