diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/g_unix_signal.c | 112 | ||||
-rw-r--r-- | src/g_unix_signal.h | 10 | ||||
-rw-r--r-- | src/interface.c | 30 | ||||
-rw-r--r-- | src/interface.h | 2 |
5 files changed, 132 insertions, 24 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index e23f3d5..3c905b8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@ bin_PROGRAMS = pa-sink-ctl -pa_sink_ctl_SOURCES = interface.c pa-sink-ctl.c sink.c sink_input.c +pa_sink_ctl_SOURCES = interface.c pa-sink-ctl.c sink.c sink_input.c g_unix_signal.c AM_CFLAGS = -std=c99 -pedantic -Wall -Werror @PULSE_CFLAGS@ @PULSE_MAINLOOP_CFLAGS@ @GLIB_CFLAGS@ pa_sink_ctl_LDADD = @GLIB_LIBS@ @PULSE_LIBS@ @PULSE_MAINLOOP_LIBS@ @CURSES_LIBS@ diff --git a/src/g_unix_signal.c b/src/g_unix_signal.c new file mode 100644 index 0000000..4d6a1a1 --- /dev/null +++ b/src/g_unix_signal.c @@ -0,0 +1,112 @@ +#define _POSIX_SOURCE +#include <signal.h> +#include <glib.h> + +static GPtrArray *signal_infos = NULL; + +typedef struct _GUnixSignalInfo { + guint source_id; + GMainContext *context; + gboolean triggered; + gint signum; +} GUnixSignalInfo; + +typedef struct _GUnixSignalSource { + GSource source; + GUnixSignalInfo *info; +} GUnixSignalSource; + +static inline GUnixSignalInfo* get_signal_info(guint index) +{ + return (GUnixSignalInfo*)g_ptr_array_index(signal_infos, index); +} + +static void handler(gint signum) { + g_assert(signal_infos != NULL); + for (guint i = 0; i < signal_infos->len; ++i) + if (get_signal_info(i)->signum == signum) + get_signal_info(i)->triggered = TRUE; + sigaction(signum, &(struct sigaction){handler}, NULL); +} + +static gboolean check(GSource *source) +{ + GUnixSignalSource *signal_source = (GUnixSignalSource*) source; + return signal_source->info->triggered; +} + +static gboolean prepare(GSource *source, gint *timeout_) +{ + GUnixSignalSource *signal_source = (GUnixSignalSource*) source; + if (signal_source->info->context == NULL) { + g_main_context_ref(signal_source->info->context = g_source_get_context(source)); + signal_source->info->source_id = g_source_get_id(source); + } + + *timeout_ = -1; + return signal_source->info->triggered; +} + +static gboolean dispatch(GSource *source, GSourceFunc callback, gpointer user_data) +{ + GUnixSignalSource *signal_source = (GUnixSignalSource*) source; + signal_source->info->triggered = FALSE; + return callback(user_data) ? TRUE : FALSE; +} +static void finalize(GSource *source) +{ + GUnixSignalSource *signal_source = (GUnixSignalSource*) source; + sigaction(signal_source->info->signum, &(struct sigaction){NULL}, NULL); + g_main_context_unref(signal_source->info->context); + g_ptr_array_remove_fast(signal_infos, signal_source->info); + if (signal_infos->len == 0) + signal_infos = (GPtrArray*) g_ptr_array_free(signal_infos, TRUE); + g_free(signal_source->info); + +} +static GSourceFuncs SourceFuncs = +{ + .prepare = prepare, + .check = check, + .dispatch = dispatch, + .finalize = finalize, + .closure_callback = NULL, .closure_marshal = NULL +}; + +static void g_unix_signal_source_init(GSource *source, gint signum) +{ + GUnixSignalSource *signal_source = (GUnixSignalSource *) source; + signal_source->info = g_new(GUnixSignalInfo, 1); + signal_source->info->triggered = FALSE; + signal_source->info->signum = signum; + signal_source->info->context = NULL; + + if (signal_infos == NULL) + signal_infos = g_ptr_array_new(); + g_ptr_array_add(signal_infos, signal_source->info); +} + +GSource *g_unix_signal_source_new(gint signum) +{ + GSource *source = g_source_new(&SourceFuncs, sizeof(GUnixSignalSource)); + g_unix_signal_source_init(source, signum); + sigaction(signum, &(struct sigaction){handler}, NULL); + return source; +} + +guint g_unix_signal_add_full(gint priority, gint signum, GSourceFunc function, gpointer data, GDestroyNotify notify) +{ + g_return_val_if_fail(function != NULL, 0); + GSource *source = g_unix_signal_source_new(signum); + if (priority != G_PRIORITY_DEFAULT) + g_source_set_priority (source, priority); + g_source_set_callback(source, function, data, notify); + guint id = g_source_attach(source, NULL); + g_source_unref(source); + return id; +} + +guint g_unix_signal_add(gint signum, GSourceFunc function, gpointer data) +{ + return g_unix_signal_add_full(G_PRIORITY_DEFAULT, signum, function, data, NULL); +} diff --git a/src/g_unix_signal.h b/src/g_unix_signal.h new file mode 100644 index 0000000..f9d6f8b --- /dev/null +++ b/src/g_unix_signal.h @@ -0,0 +1,10 @@ +#ifndef G_UNIX_SIGNAL_H +#define G_UNIX_SIGNAL_H + +#include <glib.h> + +GSource *g_unix_signal_source_new(gint signum); +guint g_unix_signal_add(gint signum, GSourceFunc function, gpointer data); +guint g_unix_signal_add_full(gint priority, gint signum, GSourceFunc function, gpointer data, GDestroyNotify notify); + +#endif /* G_UNIX_SIGNAL_H */ diff --git a/src/interface.c b/src/interface.c index 3c02e78..0b79ab4 100644 --- a/src/interface.c +++ b/src/interface.c @@ -10,6 +10,7 @@ #include "interface.h" #include "sink.h" #include "pa-sink-ctl.h" +#include "g_unix_signal.h" #define VOLUME_BAR_LEN 50 #define H_MSG_BOX 3 @@ -19,30 +20,12 @@ extern pa_context* context; static WINDOW *menu_win; static WINDOW *msg_win; +static guint resize_source_id; + static gint chooser_sink; static gint chooser_input; static guint32 selected_index; -static void _resize(gint signal) -{ - static gboolean resize_running = FALSE; - static gboolean resize_blocked = FALSE; - - sigaction(SIGWINCH, &(struct sigaction){_resize}, NULL); - - if (resize_running) { - resize_blocked = TRUE; - return; - } - - resize_running = TRUE; - do { - resize_blocked = FALSE; - interface_resize(); - } while (resize_blocked); - resize_running = FALSE; -} - void interface_init(void) { chooser_sink = 0; @@ -63,12 +46,13 @@ void interface_init(void) keypad(menu_win, TRUE); /* multichar keys are mapped to one char */ /* "resizing" here is for initial box positioning and layout */ - _resize(SIGWINCH); + interface_resize(NULL); + resize_source_id = g_unix_signal_add(SIGWINCH, interface_resize, NULL); refresh(); } -void interface_resize(void) +gboolean interface_resize(gpointer data) { struct winsize wsize; gint height = 80; @@ -89,6 +73,7 @@ void interface_resize(void) status(NULL); /* NULL := display old status */ print_sink_list(); + return TRUE; } void print_sink_list(void) @@ -312,6 +297,7 @@ void get_input(void) void interface_clear(void) { + g_source_remove(resize_source_id); clear(); refresh(); endwin(); diff --git a/src/interface.h b/src/interface.h index 2734c72..89c038d 100644 --- a/src/interface.h +++ b/src/interface.h @@ -9,7 +9,7 @@ void print_input_list(gint); void print_volume(pa_volume_t, gint, gint); void get_input(void); void interface_init(void); -void interface_resize(void); +gboolean interface_resize(gpointer); void interface_clear(void); void status(gchar *); |