summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am2
-rw-r--r--src/g_unix_signal.c112
-rw-r--r--src/g_unix_signal.h10
-rw-r--r--src/interface.c30
-rw-r--r--src/interface.h2
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 *);