From 1f36351ab7cbded30f44f83ce6cdba414aa540c7 Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Sun, 28 Oct 2018 17:49:46 +0100 Subject: paswitch: avoid information duplication And miscellaneous cleanup. --- LICENSE | 2 +- README.adoc | 2 ++ paswitch.c | 85 ++++++++++++++++++++++++++++++++++++++----------------------- 3 files changed, 56 insertions(+), 33 deletions(-) diff --git a/LICENSE b/LICENSE index fcb23ab..01dc408 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015 - 2016, Přemysl Janouch +Copyright (c) 2015 - 2018, Přemysl Janouch Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. diff --git a/README.adoc b/README.adoc index 5bb70e3..3c3d4d3 100644 --- a/README.adoc +++ b/README.adoc @@ -8,6 +8,8 @@ to other people as well: - 'wmstatus' does literally everything my i3 doesn't but I'd like it to. It includes PulseAudio volume management and hand-written NUT and MPD clients, all in the name of liberation from GPL-licensed software of course + - 'paswitch' displays a list of all PulseAudio sinks and ports and allows + switching between them, moving all playing inputs - 'brightness' allows me to change the brightness of w/e display device I have - 'input-switch' likewise switches the input source of external displays - 'fancontrol-ng' is a clone of fancontrol that can handle errors on resume diff --git a/paswitch.c b/paswitch.c index afabbe0..18917dd 100644 --- a/paswitch.c +++ b/paswitch.c @@ -154,6 +154,9 @@ struct app_context pa_context *context; ///< PulseAudio connection context bool failed; ///< General PulseAudio failure + bool reset_sinks; ///< Flag for info callback + bool reset_inputs; ///< Flag for info callback + char *default_sink; ///< Name of the default sink struct sink *sinks; ///< PulseAudio sinks struct sink *sinks_tail; ///< Tail of PulseAudio sinks @@ -234,7 +237,13 @@ make_inputs_status (struct app_context *ctx, struct sink *sink) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -#define DEFAULT_SINK "@DEFAULT_SINK@" +static void +forget_sinks (struct app_context *ctx) +{ + LIST_FOR_EACH (struct sink, iter, ctx->sinks) + sink_destroy (iter); + ctx->sinks = ctx->sinks_tail = NULL; +} static void on_sink_info (pa_context *context, const pa_sink_info *info, int eol, @@ -242,6 +251,13 @@ on_sink_info (pa_context *context, const pa_sink_info *info, int eol, { (void) context; struct app_context *ctx = userdata; + + // Assuming replies cannot overlap + if (ctx->reset_sinks) + { + forget_sinks (ctx); + ctx->reset_sinks = false; + } if (!info || eol) { // TODO: handle the case of when sinks disappear @@ -249,6 +265,7 @@ on_sink_info (pa_context *context, const pa_sink_info *info, int eol, ctx->selected_sink = ctx->sinks->index; poller_idle_set (&ctx->redraw_event); + ctx->reset_sinks = true; return; } @@ -281,23 +298,18 @@ on_sink_info (pa_context *context, const pa_sink_info *info, int eol, } static void -forget_sinks (struct app_context *ctx) +update_sinks (struct app_context *ctx) { - LIST_FOR_EACH (struct sink, iter, ctx->sinks) - sink_destroy (iter); - ctx->sinks = ctx->sinks_tail = NULL; + pa_operation_unref (pa_context_get_sink_info_list + (ctx->context, on_sink_info, ctx)); } static void -update_sinks (struct app_context *ctx) +forget_sink_inputs (struct app_context *ctx) { - // It shouldn't matter much if we interrupt this operation in the middle - // since we request new information right away. At least so long as - // replies can't overlap. Though even then we're safe, at least. - forget_sinks (ctx); - - pa_operation_unref (pa_context_get_sink_info_list - (ctx->context, on_sink_info, ctx)); + LIST_FOR_EACH (struct sink_input, iter, ctx->inputs) + free (iter); + ctx->inputs = ctx->inputs_tail = NULL; } static void @@ -306,9 +318,17 @@ on_sink_input_info (pa_context *context, const struct pa_sink_input_info *info, { (void) context; struct app_context *ctx = userdata; + + // Assuming replies cannot overlap + if (ctx->reset_inputs) + { + forget_sink_inputs (ctx); + ctx->reset_inputs = false; + } if (!info || eol) { poller_idle_set (&ctx->redraw_event); + ctx->reset_inputs = true; return; } @@ -318,22 +338,9 @@ on_sink_input_info (pa_context *context, const struct pa_sink_input_info *info, LIST_APPEND_WITH_TAIL (ctx->inputs, ctx->inputs_tail, input); } -static void -forget_sink_inputs (struct app_context *ctx) -{ - LIST_FOR_EACH (struct sink_input, iter, ctx->inputs) - free (iter); - ctx->inputs = ctx->inputs_tail = NULL; -} - static void update_sink_inputs (struct app_context *ctx) { - // It shouldn't matter much if we interrupt this operation in the middle - // since we request new information right away. At least so long as - // replies can't overlap. Though even then we're safe, at least. - forget_sink_inputs (ctx); - pa_operation_unref (pa_context_get_sink_input_info_list (ctx->context, on_sink_input_info, ctx)); } @@ -351,6 +358,13 @@ on_server_info (pa_context *context, const struct pa_server_info *info, cstr_set (&ctx->default_sink, NULL); } +static void +update_server_info (struct app_context *ctx) +{ + pa_operation_unref (pa_context_get_server_info (ctx->context, + on_server_info, ctx)); +} + static void on_event (pa_context *context, pa_subscription_event_type_t event, uint32_t index, void *userdata) @@ -368,8 +382,7 @@ on_event (pa_context *context, pa_subscription_event_type_t event, update_sink_inputs (ctx); break; case PA_SUBSCRIPTION_EVENT_SERVER: - pa_operation_unref (pa_context_get_server_info (context, - on_server_info, userdata)); + update_server_info (ctx); } } @@ -401,11 +414,13 @@ on_context_state_change (pa_context *context, void *userdata) ctx->context = NULL; forget_sinks (ctx); + forget_sink_inputs (ctx); cstr_set (&ctx->default_sink, NULL); // Retry after an arbitrary delay of 5 seconds poller_timer_set (&ctx->make_context, 5000); return; + case PA_CONTEXT_READY: ctx->failed = false; poller_idle_set (&ctx->redraw_event); @@ -415,11 +430,12 @@ on_context_state_change (pa_context *context, void *userdata) PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SINK_INPUT | PA_SUBSCRIPTION_MASK_SERVER, on_subscribe_finish, userdata)); + ctx->reset_sinks = true; + ctx->reset_inputs = true; + update_sinks (ctx); update_sink_inputs (ctx); - - pa_operation_unref (pa_context_get_server_info (context, - on_server_info, userdata)); + update_server_info (ctx); default: return; } @@ -520,7 +536,8 @@ on_redraw (struct app_context *ctx) printf ("\x1b[H"); // Cursor to home printf ("\x1b[2J"); // Clear the whole screen - // TODO: see if we can reduce flickering. Buffering doesn't help much. + // TODO: see if we can reduce flickering in rxvt-unicode. + // Buffering doesn't help, we have to do something more sophisticated. // TODO: try not to write more lines than g_terminal_lines for starters if (ctx->failed) { @@ -682,7 +699,11 @@ g_key_handlers[] = { "k", ACTION_UP }, { "j", ACTION_DOWN }, + { "\x10", ACTION_UP }, + { "\x0e", ACTION_DOWN }, { "\r", ACTION_SELECT }, + { "+", ACTION_VOLUP }, + { "-", ACTION_VOLDOWN }, { "\x1b[5~", ACTION_VOLUP }, { "\x1b[6~", ACTION_VOLDOWN }, { "m", ACTION_MUTE }, -- cgit v1.2.3-70-g09d2