From 2310d43d6410de464dbd5ffa7edc7fd2785f21d3 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Fri, 21 Oct 2011 11:53:39 +0200 Subject: Use a GList instead of GArray for sinks. This lets us drop our ugly GArray wrappers sink.c and sink_input.c. It will make gradual updates of sinks easier, since elements can be added and dropped everywhere in the list easily. --- src/Makefile.am | 2 +- src/interface.c | 90 ++++++++++++++++++++++++++++++------------------------- src/pa-sink-ctl.c | 45 ++++++++++++++++++++-------- src/sink.c | 54 --------------------------------- src/sink.h | 14 +-------- src/sink_input.c | 23 -------------- src/sink_input.h | 3 -- 7 files changed, 84 insertions(+), 147 deletions(-) delete mode 100644 src/sink.c delete mode 100644 src/sink_input.c diff --git a/src/Makefile.am b/src/Makefile.am index 863fea4..327376b 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 EXTRA_pa_sink_ctl_SOURCES = unix_signal.c if !HAVE_SIGNALFD diff --git a/src/interface.c b/src/interface.c index d4b94be..11238df 100644 --- a/src/interface.c +++ b/src/interface.c @@ -40,6 +40,8 @@ static guint32 selected_index; guint max_name_len = 0; +extern GList *sink_list; + static gboolean interface_resize(gpointer data) { @@ -88,29 +90,30 @@ print_volume(pa_volume_t volume, int mute, int y) } static void -print_input_list(gint sink_num) +print_input_list(GList *input_list, gint sink_num) { + GList *l; gint offset = sink_num + 3 /* win border + empty line + 1th sink */; + gint i; - for (gint i = 0; i < sink_num; ++i) - offset += sink_list_get(i)->input_list->len; + for (l = sink_list, i = 0; l && i < sink_num; l = l->next,i++) + offset += g_list_length(((sink_info *)l->data)->input_list); - for (gint i = 0; i < sink_list_get(sink_num)->input_list->len; ++i) { + for (l = input_list, i = 0; l; l = l->next,++i) { + sink_input_info *input = l->data; gboolean selected = (chooser_sink == sink_num && chooser_input == i); if (selected) wattron(menu_win, A_REVERSE); mvwprintw(menu_win, offset + i, 2, "%*s%-*s", - 2+1+1, "", /* space for index number + indentation*/ - max_name_len - 1, - sink_input_get(sink_num, i)->name); + 2+1+1, "", /* space for index number + indentation*/ + max_name_len - 1, input->name); if (selected) wattroff(menu_win, A_REVERSE); - print_volume(sink_input_get(sink_num, i)->vol, - sink_input_get(sink_num, i)->mute, offset + i); + print_volume(input->vol, input->mute, offset + i); } } @@ -118,24 +121,22 @@ print_input_list(gint sink_num) static void set_max_name_len(void) { + GList *l,*k; guint len = 0; max_name_len = len; - for (gint sink_num = 0; sink_num < sink_list->len; ++sink_num) { - - len = strlen(sink_list_get(sink_num)->device != NULL ? - sink_list_get(sink_num)->device : - sink_list_get(sink_num)->name); + for (l = sink_list; l; l = l->next) { + sink_info *sink = l->data; + + len = strlen(sink->device != NULL ? sink->device : sink->name); if (len > max_name_len) max_name_len = len; - for (gint input_num = 0; - input_num < sink_list_get(sink_num)->input_list->len; - ++input_num) { + for (k = sink->input_list; k; k = k->next) { + sink_input_info *input = k->data; - len = strlen(sink_input_get(sink_num, input_num)->name) - + 1 /* indentation */; + len = strlen(input->name) + 1 /* indentation */; if (len > max_name_len) max_name_len = len; @@ -150,6 +151,7 @@ print_sink_list(void) gint x = 2; gint y = 2; gint offset = 0; + GList *l; /* looking for the longest name for right indentation */ set_max_name_len(); @@ -162,32 +164,34 @@ print_sink_list(void) /* if index is will not be found (in the loop), select the sink itself */ chooser_input = SELECTED_SINK; /* step through inputs for current sink and find the selected */ - for (i = 0; i < sink_list_get(chooser_sink)->input_list->len; ++i) { - if (selected_index == sink_input_get(chooser_sink, i)->index) { + sink_info *sink = g_list_nth_data(sink_list, chooser_sink); + for (l = sink->input_list, i = 0; l; l = l->next,++i) { + sink_input_info *input = l->data; + if (selected_index == input->index) { chooser_input = i; break; } } } - for (i = 0; i < sink_list->len; ++i) { + for (l = sink_list, i = 0; l; l = l->next,++i) { + sink_info *sink = l->data; gboolean selected = (i == chooser_sink && chooser_input == SELECTED_SINK); if (selected) wattron(menu_win, A_REVERSE); mvwprintw(menu_win, y+i+offset, x, "%2u %-*s", - sink_list_get(i)->index, - max_name_len, - sink_list_get(i)->device != NULL ? sink_list_get(i)->device : sink_list_get(i)->name); + sink->index, max_name_len, + sink->device != NULL ? sink->device : sink->name); if (selected) wattroff(menu_win, A_REVERSE); - print_volume(sink_list_get(i)->vol, sink_list_get(i)->mute, y+i+offset); + print_volume(sink->vol, sink->mute, y+i+offset); - print_input_list(i); + print_input_list(sink->input_list, i); - offset += sink_list_get(i)->input_list->len; + offset += g_list_length(sink->input_list); } wrefresh(menu_win); } @@ -197,6 +201,7 @@ interface_get_input(GIOChannel *source, GIOCondition condition, gpointer data) { gint c; gboolean volume_increment = TRUE; + sink_info *sink = NULL; if (!context_ready) return TRUE; @@ -207,8 +212,9 @@ interface_get_input(GIOChannel *source, GIOCondition condition, gpointer data) case 'w': case KEY_UP: if (chooser_input == SELECTED_SINK && chooser_sink > 0) { - --chooser_sink; - chooser_input = (gint)sink_list_get(chooser_sink)->input_list->len - 1; + sink = g_list_nth_data(sink_list, --chooser_sink); + /* automatic SELECTED_SINK (=-1) assignment if length = 0 */ + chooser_input = (gint)g_list_length(sink->input_list) - 1; } else if (chooser_input >= 0) @@ -219,11 +225,12 @@ interface_get_input(GIOChannel *source, GIOCondition condition, gpointer data) case 'j': case 's': case KEY_DOWN: - if (chooser_input == ((gint)sink_list_get(chooser_sink)->input_list->len - 1) && chooser_sink < (gint)sink_list->len - 1) { + sink = g_list_nth_data(sink_list, chooser_sink); + if (chooser_input == ((gint)g_list_length(sink->input_list) - 1) && chooser_sink < (gint)g_list_length(sink_list) - 1) { ++chooser_sink; chooser_input = SELECTED_SINK; } - else if (chooser_input < ((gint)sink_list_get(chooser_sink)->input_list->len - 1)) + else if (chooser_input < ((gint)g_list_length(sink->input_list) - 1)) ++chooser_input; print_sink_list(); break; @@ -243,8 +250,9 @@ interface_get_input(GIOChannel *source, GIOCondition condition, gpointer data) pa_operation* (*volume_set) (pa_context*, guint32, const pa_cvolume*, pa_context_success_cb_t, gpointer); } tmp; + sink = g_list_nth_data(sink_list, chooser_sink); if (chooser_input >= 0) { - sink_input_info *input = sink_input_get(chooser_sink, chooser_input); + sink_input_info *input = g_list_nth_data(sink->input_list, chooser_input); tmp = (struct tmp_t) { .index = input->index, .volume = (pa_cvolume) {.channels = input->channels}, @@ -252,7 +260,6 @@ interface_get_input(GIOChannel *source, GIOCondition condition, gpointer data) .volume_set = pa_context_set_sink_input_volume }; } else if (chooser_input == SELECTED_SINK) { - sink_info *sink = sink_list_get(chooser_sink); tmp = (struct tmp_t) { .index = sink->index, .volume = (pa_cvolume) {.channels = sink->channels}, @@ -288,15 +295,15 @@ interface_get_input(GIOChannel *source, GIOCondition condition, gpointer data) pa_operation* (*mute_set) (pa_context*, guint32, int, pa_context_success_cb_t, void*); } tmp; + sink = g_list_nth_data(sink_list, chooser_sink); if (chooser_input >= 0) { - sink_input_info *input = sink_input_get(chooser_sink, chooser_input); + sink_input_info *input = g_list_nth_data(sink->input_list, chooser_input); tmp = (struct tmp_t) { .index = input->index, .mute = input->mute, .mute_set = pa_context_set_sink_input_mute }; } else if (chooser_input == SELECTED_SINK) { - sink_info *sink = sink_list_get(chooser_sink); tmp = (struct tmp_t) { .index = sink->index, .mute = sink->mute, @@ -314,17 +321,20 @@ interface_get_input(GIOChannel *source, GIOCondition condition, gpointer data) case ' ': if (chooser_input == SELECTED_SINK) break; - selected_index = sink_input_get(chooser_sink, chooser_input)->index; - if (chooser_sink < (gint)sink_list->len - 1) + sink = g_list_nth_data(sink_list, chooser_sink); + sink_input_info *input = g_list_nth_data(sink->input_list, chooser_input); + selected_index = input->index; + if (chooser_sink < (gint)g_list_length(sink_list) - 1) chooser_sink++; else chooser_sink = 0; + sink = g_list_nth_data(sink_list, chooser_sink); /* chooser_input needs to be derived from $selected_index */ chooser_input = SELECTED_UNKNOWN; pa_operation_unref(pa_context_move_sink_input_by_index(context, selected_index, - sink_list_get(chooser_sink)->index, - change_callback, NULL)); + sink->index, + change_callback, NULL)); break; case 'q': diff --git a/src/pa-sink-ctl.c b/src/pa-sink-ctl.c index e9f9c23..3591df3 100644 --- a/src/pa-sink-ctl.c +++ b/src/pa-sink-ctl.c @@ -13,13 +13,25 @@ gboolean context_ready = FALSE; static gboolean info_callbacks_finished = TRUE; static gboolean info_callbacks_blocked = FALSE; +struct fetch_ctx { + GList *sinks; +}; + +GList *sink_list; + +#define list_append_struct(list, data) \ + do { \ + (list) = g_list_append((list), \ + g_memdup(&(data), sizeof(data))); \ + } while (0) + int main(int argc, char** argv) { pa_mainloop_api *mainloop_api = NULL; pa_glib_mainloop *m = NULL; - sink_list = sink_list_alloc(); + sink_list = NULL; GMainLoop *g_loop = g_main_loop_new(NULL, FALSE); @@ -49,7 +61,7 @@ main(int argc, char** argv) g_main_loop_run(g_loop); interface_clear(); - sink_list_free(sink_list); + g_list_free(sink_list); pa_glib_mainloop_free(m); g_main_loop_unref(g_loop); @@ -112,6 +124,7 @@ context_state_callback(pa_context *c, gpointer userdata) } } + /* * the begin of the callback loops */ @@ -119,7 +132,7 @@ void get_sink_info_callback(pa_context *c, const pa_sink_info *i, gint is_last, gpointer userdata) { g_assert(userdata != NULL); - GArray *sink_list_tmp = userdata; + struct fetch_ctx *fetch_ctx = userdata; if (is_last < 0) { g_printerr("Failed to get sink information: %s\n", pa_strerror(pa_context_errno(c))); @@ -127,11 +140,11 @@ get_sink_info_callback(pa_context *c, const pa_sink_info *i, gint is_last, gpoin } if (is_last) { - pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, sink_list_tmp)); + pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, fetch_ctx)); return; } - g_array_append_val(sink_list_tmp, ((sink_info) { + sink_info sink = { .index = i->index, .mute = i->mute, .vol = pa_cvolume_avg(&i->volume), @@ -139,8 +152,10 @@ get_sink_info_callback(pa_context *c, const pa_sink_info *i, gint is_last, gpoin .name = g_strdup(i->name), .device = pa_proplist_contains(i->proplist, "device.product.name") ? g_strdup(pa_proplist_gets(i->proplist, "device.product.name")) : NULL, - .input_list = sink_input_list_alloc() - })); + .input_list = NULL + }; + + list_append_struct(fetch_ctx->sinks, sink); } /* @@ -150,7 +165,7 @@ void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, gint is_last, gpointer userdata) { g_assert(userdata != NULL); - GArray *sink_list_tmp = userdata; + struct fetch_ctx *fetch_ctx = userdata; if (is_last < 0) { g_printerr("Failed to get sink input information: %s\n", pa_strerror(pa_context_errno(c))); @@ -159,8 +174,9 @@ get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, gint is if (is_last) { info_callbacks_finished = TRUE; - sink_list_free(sink_list); - sink_list = sink_list_tmp; + g_list_free_full(sink_list, g_free); + sink_list = fetch_ctx->sinks; + g_free(fetch_ctx); print_sink_list(); @@ -173,7 +189,7 @@ get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, gint is if (!(i->client != PA_INVALID_INDEX)) return; - g_array_append_val(g_array_index(sink_list_tmp, sink_info, i->sink).input_list, ((sink_input_info) { + sink_input_info sink_input = { .index = i->index, .sink = i->sink, .name = pa_proplist_contains(i->proplist, "application.name") ? @@ -183,7 +199,10 @@ get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, gint is .channels = i->volume.channels, .vol = pa_cvolume_avg(&i->volume), .pid = NULL /* maybe obsolete */ - })); + }; + + sink_info *sink = g_list_nth_data(fetch_ctx->sinks, i->sink); + list_append_struct(sink->input_list, sink_input); } void @@ -207,5 +226,5 @@ collect_all_info(void) if (!info_callbacks_finished) return; info_callbacks_finished = FALSE; - pa_operation_unref(pa_context_get_sink_info_list(context, get_sink_info_callback, sink_list_alloc())); + pa_operation_unref(pa_context_get_sink_info_list(context, get_sink_info_callback, g_new0(struct fetch_ctx, 1))); } diff --git a/src/sink.c b/src/sink.c deleted file mode 100644 index 090659f..0000000 --- a/src/sink.c +++ /dev/null @@ -1,54 +0,0 @@ -#include - -#define SINK_C -#include "sink.h" -#include "sink_input.h" - -/* - * init a sink list - */ -GArray * -sink_list_alloc(void) -{ - return g_array_sized_new(FALSE, FALSE, sizeof(sink_info), 16); -} - -/* - * frees all dynamic allocated components of a sink - */ -static void -sink_clear(sink_info* sink) -{ - g_free(sink->name); - g_free(sink->device); - sink_input_list_free(sink->input_list); -} - -/* - * frees a complete sink array - */ -void -sink_list_free(GArray *sink_list) -{ - for (int i = 0; i < sink_list->len; ++i) - sink_clear(&g_array_index(sink_list, sink_info, i)); - g_array_free(sink_list, TRUE); -} - -/* - * get sink at index from sink_list - */ -sink_info * -sink_list_get(gint index) -{ - return &g_array_index(sink_list, sink_info, index); -} - -/* - * get an input association to an sink by their indizes - */ -sink_input_info * -sink_input_get(gint sink_list_index, gint index) -{ - return &g_array_index(sink_list_get(sink_list_index)->input_list, sink_input_info, index); -} diff --git a/src/sink.h b/src/sink.h index cccbe1b..083f0d8 100644 --- a/src/sink.h +++ b/src/sink.h @@ -1,12 +1,6 @@ #ifndef SINK_H #define SINK_H -#ifdef SINK_C -GArray *sink_list; -#else -extern GArray *sink_list; -#endif - #include #include @@ -19,13 +13,7 @@ typedef struct _sink_info { gint mute; guint8 channels; pa_volume_t vol; - GArray *input_list; + GList *input_list; } sink_info; -GArray *sink_list_alloc(void); -void sink_list_free(GArray *sink_list); - -sink_info *sink_list_get(gint index); -sink_input_info *sink_input_get(gint sink_list_index, gint index); - #endif diff --git a/src/sink_input.c b/src/sink_input.c deleted file mode 100644 index 6dd292a..0000000 --- a/src/sink_input.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include "sink_input.h" - -GArray * -sink_input_list_alloc(void) -{ - return g_array_sized_new(FALSE, FALSE, sizeof(sink_input_info), 8); -} - -static void -sink_input_clear(sink_input_info* sink_input) -{ - g_free(sink_input->name); - g_free(sink_input->pid); -} - -void -sink_input_list_free(GArray *sink_input_list) -{ - for (int i = 0; i < sink_input_list->len; ++i) - sink_input_clear(&g_array_index(sink_input_list, sink_input_info, i)); - g_array_free(sink_input_list, TRUE); -} diff --git a/src/sink_input.h b/src/sink_input.h index a62a00b..82797c0 100644 --- a/src/sink_input.h +++ b/src/sink_input.h @@ -14,7 +14,4 @@ typedef struct _sink_input_info { pa_volume_t vol; // TOTO: exchange with the channel-list } sink_input_info; -GArray *sink_input_list_alloc(void); -void sink_input_list_free(GArray *sink_input_list); - #endif -- cgit