Rearrange code

I need to update tabs from MPD message handlers.
This commit is contained in:
Přemysl Eric Janouch 2016-10-05 01:12:31 +02:00
parent 319d0faffa
commit a59f0b237e
Signed by: p
GPG Key ID: B715679E3A361BE6
1 changed files with 199 additions and 203 deletions

402
nncmpp.c
View File

@ -1467,69 +1467,152 @@ app_process_termo_event (termo_key_t *event)
return true;
}
// --- Signals -----------------------------------------------------------------
// --- Info tab ----------------------------------------------------------------
static int g_signal_pipe[2]; ///< A pipe used to signal... signals
/// Program termination has been requested by a signal
static volatile sig_atomic_t g_termination_requested;
/// The window has changed in size
static volatile sig_atomic_t g_winch_received;
// TODO: either find something else to put in here or remove the wrapper struct
static struct
{
struct tab super; ///< Parent class
}
g_info_tab;
static void
signals_postpone_handling (char id)
info_tab_on_item_draw (struct tab *self, unsigned item_index,
struct row_buffer *buffer, int width)
{
int original_errno = errno;
if (write (g_signal_pipe[1], &id, 1) == -1)
soft_assert (errno == EAGAIN);
errno = original_errno;
(void) self;
(void) width;
// TODO
}
static struct tab *
info_tab_create (void)
{
struct tab *super = &g_info_tab.super;
tab_init (super, "Info");
super->on_item_draw = info_tab_on_item_draw;
super->item_count = 0;
super->item_selected = 0;
return super;
}
// --- Help tab ----------------------------------------------------------------
// TODO: either find something else to put in here or remove the wrapper struct
static struct
{
struct tab super; ///< Parent class
}
g_help_tab;
static void
help_tab_on_item_draw (struct tab *self, unsigned item_index,
struct row_buffer *buffer, int width)
{
(void) self;
(void) width;
// TODO: group them the other way around for clarity
hard_assert (item_index < N_ELEMENTS (g_default_bindings));
struct binding *binding = &g_default_bindings[item_index];
char *text = xstrdup_printf ("%-12s %s",
binding->key, g_user_actions[binding->action].description);
row_buffer_append (buffer, text, 0);
free (text);
}
static struct tab *
help_tab_create (void)
{
struct tab *super = &g_help_tab.super;
tab_init (super, "Help");
super->on_item_draw = help_tab_on_item_draw;
super->item_count = N_ELEMENTS (g_default_bindings);
super->item_selected = 0;
return super;
}
// --- Debug tab ---------------------------------------------------------------
struct debug_item
{
char *text; ///< Logged line
int64_t timestamp; ///< Timestamp
chtype attrs; ///< Line attributes
};
static struct
{
struct tab super; ///< Parent class
struct debug_item *items; ///< Items
size_t items_alloc; ///< How many items are allocated
bool active; ///< The tab is present
}
g_debug_tab;
static void
debug_tab_on_item_draw (struct tab *self, unsigned item_index,
struct row_buffer *buffer, int width)
{
(void) self;
hard_assert (item_index <= g_debug_tab.super.item_count);
struct debug_item *item = &g_debug_tab.items[item_index];
char buf[16];
struct tm tm;
time_t when = item->timestamp / 1000;
strftime (buf, sizeof buf, "%T", localtime_r (&when, &tm));
char *prefix = xstrdup_printf
("%s.%03d", buf, (int) (item->timestamp % 1000));
row_buffer_append (buffer, prefix, 0);
free (prefix);
row_buffer_append (buffer, " ", item->attrs);
row_buffer_append (buffer, item->text, item->attrs);
// We override the formatting including colors -- do it for the whole line
if (buffer->total_width > width)
row_buffer_ellipsis (buffer, width, item->attrs);
while (buffer->total_width < width)
row_buffer_append (buffer, " ", item->attrs);
}
static void
signals_superhandler (int signum)
debug_tab_push (const char *message, chtype attrs)
{
switch (signum)
// TODO: uh... aren't we rather going to write our own abstraction?
if (g_debug_tab.items_alloc <= g_debug_tab.super.item_count)
{
case SIGWINCH:
g_winch_received = true;
signals_postpone_handling ('w');
break;
case SIGINT:
case SIGTERM:
g_termination_requested = true;
signals_postpone_handling ('t');
break;
default:
hard_assert (!"unhandled signal");
g_debug_tab.items = xreallocarray (g_debug_tab.items,
sizeof *g_debug_tab.items, (g_debug_tab.items_alloc <<= 1));
}
// TODO: there should be a better, more efficient mechanism for this
struct debug_item *item =
&g_debug_tab.items[g_debug_tab.super.item_count++];
item->text = xstrdup (message);
item->attrs = attrs;
item->timestamp = clock_msec (CLOCK_REALTIME);
app_invalidate ();
}
static void
signals_setup_handlers (void)
static struct tab *
debug_tab_create (void)
{
if (pipe (g_signal_pipe) == -1)
exit_fatal ("%s: %s", "pipe", strerror (errno));
g_debug_tab.items = xcalloc
((g_debug_tab.items_alloc = 16), sizeof *g_debug_tab.items);
g_debug_tab.active = true;
set_cloexec (g_signal_pipe[0]);
set_cloexec (g_signal_pipe[1]);
// So that the pipe cannot overflow; it would make write() block within
// the signal handler, which is something we really don't want to happen.
// The same holds true for read().
set_blocking (g_signal_pipe[0], false);
set_blocking (g_signal_pipe[1], false);
signal (SIGPIPE, SIG_IGN);
struct sigaction sa;
sa.sa_flags = SA_RESTART;
sa.sa_handler = signals_superhandler;
sigemptyset (&sa.sa_mask);
if (sigaction (SIGWINCH, &sa, NULL) == -1
|| sigaction (SIGINT, &sa, NULL) == -1
|| sigaction (SIGTERM, &sa, NULL) == -1)
exit_fatal ("sigaction: %s", strerror (errno));
struct tab *super = &g_debug_tab.super;
tab_init (super, "Debug");
super->on_item_draw = debug_tab_on_item_draw;
super->item_count = 0;
super->item_selected = 0;
return super;
}
// --- MPD interface -----------------------------------------------------------
@ -1735,7 +1818,25 @@ mpd_on_failure (void *user_data)
mpd_queue_reconnect ();
}
static void mpd_on_io_hook (void *user_data, bool outgoing, const char *line);
static void
mpd_on_io_hook (void *user_data, bool outgoing, const char *line)
{
(void) user_data;
struct str s;
str_init (&s);
if (outgoing)
{
str_append_printf (&s, "<< %s", line);
debug_tab_push (s.str, APP_ATTR (OUTGOING));
}
else
{
str_append_printf (&s, ">> %s", line);
debug_tab_push (s.str, APP_ATTR (INCOMING));
}
str_free (&s);
}
static void
app_on_reconnect (void *user_data)
@ -1780,174 +1881,69 @@ app_on_reconnect (void *user_data)
free (address);
}
// --- Help tab ----------------------------------------------------------------
// --- Signals -----------------------------------------------------------------
// TODO: either find something else to put in here or remove the wrapper struct
static struct
{
struct tab super; ///< Parent class
}
g_help_tab;
static int g_signal_pipe[2]; ///< A pipe used to signal... signals
/// Program termination has been requested by a signal
static volatile sig_atomic_t g_termination_requested;
/// The window has changed in size
static volatile sig_atomic_t g_winch_received;
static void
help_tab_on_item_draw (struct tab *self, unsigned item_index,
struct row_buffer *buffer, int width)
signals_postpone_handling (char id)
{
(void) self;
(void) width;
// TODO: group them the other way around for clarity
hard_assert (item_index < N_ELEMENTS (g_default_bindings));
struct binding *binding = &g_default_bindings[item_index];
char *text = xstrdup_printf ("%-12s %s",
binding->key, g_user_actions[binding->action].description);
row_buffer_append (buffer, text, 0);
free (text);
}
static struct tab *
help_tab_create (void)
{
struct tab *super = &g_help_tab.super;
tab_init (super, "Help");
super->on_item_draw = help_tab_on_item_draw;
super->item_count = N_ELEMENTS (g_default_bindings);
super->item_selected = 0;
return super;
}
// --- Info tab ----------------------------------------------------------------
// TODO: either find something else to put in here or remove the wrapper struct
static struct
{
struct tab super; ///< Parent class
}
g_info_tab;
static void
info_tab_on_item_draw (struct tab *self, unsigned item_index,
struct row_buffer *buffer, int width)
{
(void) self;
(void) width;
// TODO
}
static struct tab *
info_tab_create (void)
{
struct tab *super = &g_info_tab.super;
tab_init (super, "Info");
super->on_item_draw = info_tab_on_item_draw;
super->item_count = 0;
super->item_selected = 0;
return super;
}
// --- Debug tab ---------------------------------------------------------------
struct debug_item
{
char *text; ///< Logged line
int64_t timestamp; ///< Timestamp
chtype attrs; ///< Line attributes
};
static struct
{
struct tab super; ///< Parent class
struct debug_item *items; ///< Items
size_t items_alloc; ///< How many items are allocated
bool active; ///< The tab is present
}
g_debug_tab;
static void
debug_tab_on_item_draw (struct tab *self, unsigned item_index,
struct row_buffer *buffer, int width)
{
(void) self;
hard_assert (item_index <= g_debug_tab.super.item_count);
struct debug_item *item = &g_debug_tab.items[item_index];
char buf[16];
struct tm tm;
time_t when = item->timestamp / 1000;
strftime (buf, sizeof buf, "%T", localtime_r (&when, &tm));
char *prefix = xstrdup_printf
("%s.%03d", buf, (int) (item->timestamp % 1000));
row_buffer_append (buffer, prefix, 0);
free (prefix);
row_buffer_append (buffer, " ", item->attrs);
row_buffer_append (buffer, item->text, item->attrs);
// We override the formatting including colors -- do it for the whole line
if (buffer->total_width > width)
row_buffer_ellipsis (buffer, width, item->attrs);
while (buffer->total_width < width)
row_buffer_append (buffer, " ", item->attrs);
int original_errno = errno;
if (write (g_signal_pipe[1], &id, 1) == -1)
soft_assert (errno == EAGAIN);
errno = original_errno;
}
static void
debug_tab_push (const char *message, chtype attrs)
signals_superhandler (int signum)
{
// TODO: uh... aren't we rather going to write our own abstraction?
if (g_debug_tab.items_alloc <= g_debug_tab.super.item_count)
switch (signum)
{
g_debug_tab.items = xreallocarray (g_debug_tab.items,
sizeof *g_debug_tab.items, (g_debug_tab.items_alloc <<= 1));
case SIGWINCH:
g_winch_received = true;
signals_postpone_handling ('w');
break;
case SIGINT:
case SIGTERM:
g_termination_requested = true;
signals_postpone_handling ('t');
break;
default:
hard_assert (!"unhandled signal");
}
// TODO: there should be a better, more efficient mechanism for this
struct debug_item *item =
&g_debug_tab.items[g_debug_tab.super.item_count++];
item->text = xstrdup (message);
item->attrs = attrs;
item->timestamp = clock_msec (CLOCK_REALTIME);
app_invalidate ();
}
static struct tab *
debug_tab_create (void)
{
g_debug_tab.items = xcalloc
((g_debug_tab.items_alloc = 16), sizeof *g_debug_tab.items);
g_debug_tab.active = true;
struct tab *super = &g_debug_tab.super;
tab_init (super, "Debug");
super->on_item_draw = debug_tab_on_item_draw;
super->item_count = 0;
super->item_selected = 0;
return super;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void
mpd_on_io_hook (void *user_data, bool outgoing, const char *line)
signals_setup_handlers (void)
{
(void) user_data;
if (pipe (g_signal_pipe) == -1)
exit_fatal ("%s: %s", "pipe", strerror (errno));
struct str s;
str_init (&s);
if (outgoing)
{
str_append_printf (&s, "<< %s", line);
debug_tab_push (s.str, APP_ATTR (OUTGOING));
}
else
{
str_append_printf (&s, ">> %s", line);
debug_tab_push (s.str, APP_ATTR (INCOMING));
}
str_free (&s);
set_cloexec (g_signal_pipe[0]);
set_cloexec (g_signal_pipe[1]);
// So that the pipe cannot overflow; it would make write() block within
// the signal handler, which is something we really don't want to happen.
// The same holds true for read().
set_blocking (g_signal_pipe[0], false);
set_blocking (g_signal_pipe[1], false);
signal (SIGPIPE, SIG_IGN);
struct sigaction sa;
sa.sa_flags = SA_RESTART;
sa.sa_handler = signals_superhandler;
sigemptyset (&sa.sa_mask);
if (sigaction (SIGWINCH, &sa, NULL) == -1
|| sigaction (SIGINT, &sa, NULL) == -1
|| sigaction (SIGTERM, &sa, NULL) == -1)
exit_fatal ("sigaction: %s", strerror (errno));
}
// --- Initialisation, event handling ------------------------------------------