diff options
-rw-r--r-- | src/command.c | 142 | ||||
-rw-r--r-- | src/ctl.h | 8 | ||||
-rw-r--r-- | src/interface.c | 67 | ||||
-rw-r--r-- | src/interface.h | 9 | ||||
-rw-r--r-- | src/pa-sink-ctl.c | 116 |
5 files changed, 205 insertions, 137 deletions
diff --git a/src/command.c b/src/command.c index 3b399dc..1b90c60 100644 --- a/src/command.c +++ b/src/command.c @@ -24,26 +24,43 @@ #include "ctl.h" #include "command.h" +static struct vol_ctl * +ctl_last_child_or_ctl(struct vol_ctl *ctl) +{ + int len; + + if (ctl->childs_len && (len = ctl->childs_len(ctl)) > 0) + return ctl->get_nth_child(ctl, len-1); + + return ctl; +} + static void up(struct context *ctx, int key) { struct interface *ifc = &ctx->interface; - struct main_ctl *ctl = NULL; + struct vol_ctl *ctl, *prev; + GList *last; if (!ctx->context_ready) return; - if (ifc->chooser_child == SELECTED_MAIN_CTL && - ifc->chooser_main_ctl > 0) { + ctl = ifc->current_ctl; + if (ctl == NULL) + return; - --ifc->chooser_main_ctl; - /* Always a main_ctl since chooser_child = SELECTED_MAIN_CTL */ - ctl = (struct main_ctl *) interface_get_current_ctl(ifc, NULL); + prev = ctl->prev_ctl(ctl); + if (prev) { + ifc->current_ctl = ctl_last_child_or_ctl(prev); + } else if (ctl->get_parent) { + ifc->current_ctl = ctl->get_parent(ctl); + } else { + struct main_ctl *mctl = (struct main_ctl *) ctl; - /* autoassigment to SELECTED_MAIN_CTL (=-1) if length = 0 */ - ifc->chooser_child = ctl->base.childs_len(&ctl->base) - 1; - } else if (ifc->chooser_child >= 0) - --ifc->chooser_child; + if (*mctl->list == ctx->source_list && + (last = g_list_last(ctx->sink_list)) != NULL) + ifc->current_ctl = ctl_last_child_or_ctl(last->data); + } interface_redraw(ifc); } @@ -52,33 +69,38 @@ static void down(struct context *ctx, int key) { struct interface *ifc = &ctx->interface; - int max_ctl_childs; - struct vol_ctl *ctl, *parent; + struct vol_ctl *ctl, *next = NULL, *tmp, *parent; if (!ctx->context_ready) return; - ctl = interface_get_current_ctl(&ctx->interface, &parent); - if (ctl == NULL) { - ifc->chooser_child = SELECTED_MAIN_CTL; - ctl = interface_get_current_ctl(&ctx->interface, &parent); - if (ctl == NULL) - return; + ctl = ifc->current_ctl; + if (ctl == NULL) + return; + + if (ctl->childs_len && ctl->childs_len(ctl) > 0) { + next = ctl->get_nth_child(ctl, 0); + } else if ((tmp = ctl->next_ctl(ctl)) != NULL) { + next = tmp; + } else if (ctl->get_parent) { + parent = ctl->get_parent(ctl); + next = parent->next_ctl(parent); + if (!next) + ctl = parent; /* parent for end-of-sink list lookup */ } - if (parent) - ctl = parent; - - max_ctl_childs = ctl->childs_len(ctl) -1; - if (ifc->chooser_child == max_ctl_childs) { - if (ifc->chooser_main_ctl < - interface_get_main_ctl_length(ifc) -1) { - ++ifc->chooser_main_ctl; - ifc->chooser_child = SELECTED_MAIN_CTL; - } - } else if (ifc->chooser_child < max_ctl_childs) - ++ifc->chooser_child; - interface_redraw(ifc); + if (!next) { + struct main_ctl *mctl = (struct main_ctl *) ctl; + + if (*mctl->list == ctx->sink_list && + g_list_first(ctx->source_list) != NULL) + next = g_list_first(ctx->source_list)->data; + } + + if (next) { + ifc->current_ctl = next; + interface_redraw(ifc); + } } static void @@ -92,7 +114,7 @@ volume_change(struct context *ctx, gboolean volume_increment) if (!ctx->context_ready) return; - ctl = interface_get_current_ctl(&ctx->interface, NULL); + ctl = ctx->interface.current_ctl; if (!ctl || !ctl->volume_set) return; @@ -135,7 +157,7 @@ toggle_mute(struct context *ctx, int key) if (!ctx->context_ready) return; - ctl = interface_get_current_ctl(&ctx->interface, NULL); + ctl = ctx->interface.current_ctl; if (!ctl && !ctl->mute_set) return; @@ -146,57 +168,33 @@ toggle_mute(struct context *ctx, int key) static void switch_sink(struct context *ctx, int key) { - struct interface *ifc = &ctx->interface; - struct slave_ctl *t; - struct vol_ctl *cslave, *cparent; - struct main_ctl *mcparent; + struct vol_ctl *cslave; + struct main_ctl *mcparent, *ctl; pa_operation *o; - gint i; - GList **list; - int offset; + GList *el; if (!ctx->context_ready) return; - cslave = interface_get_current_ctl(&ctx->interface, &cparent); - if (!cslave || !cparent) + cslave = ctx->interface.current_ctl; + if (!cslave || !cslave->get_parent) return; - mcparent = (struct main_ctl *) cparent; - if (*mcparent->childs_list == ctx->input_list) { - list = &ctx->sink_list; - offset = 0; - } else { - list = &ctx->source_list; - offset = g_list_length(ctx->sink_list); - } - - if (g_list_length(*list) <= 1) + mcparent = (struct main_ctl *) cslave->get_parent(cslave); + if (g_list_length(*mcparent->list) <= 1) return; - if (ifc->chooser_main_ctl < (gint) (offset + g_list_length(*list) - 1)) - ifc->chooser_main_ctl++; + el = g_list_find(*mcparent->list, mcparent); + g_assert(el != NULL); + if (el->next) + el = el->next; else - ifc->chooser_main_ctl = offset; + el = g_list_first(*mcparent->list); - mcparent = g_list_nth_data(*list, ifc->chooser_main_ctl - offset); - /* chooser_child needs to be derived from $selected_index */ - o = mcparent->move_child(ctx->context, - cslave->index, mcparent->base.index, - NULL, NULL); + ctl = el->data; + o = ctl->move_child(ctx->context, + cslave->index, ctl->base.index, NULL, NULL); pa_operation_unref(o); - - /* get new chooser_child, if non, select sink as fallback */ - ifc->chooser_child = SELECTED_MAIN_CTL; - i = -1; - list_foreach(*mcparent->childs_list, t) { - if (t->base.index == cslave->index) { - ifc->chooser_child = ++i; - break; - } - if (t->parent_index == mcparent->base.index) - ++i; - } } static void @@ -43,6 +43,11 @@ struct vol_ctl { void (*childs_foreach)(struct vol_ctl *ctl, GFunc func, gpointer udata); gint (*childs_len)(struct vol_ctl *ctl); + struct vol_ctl *(*get_nth_child)(struct vol_ctl *ctl, int n); + struct vol_ctl *(*get_parent)(struct vol_ctl *ctl); + + struct vol_ctl *(*prev_ctl)(struct vol_ctl *ctl); + struct vol_ctl *(*next_ctl)(struct vol_ctl *ctl); }; struct main_ctl { @@ -50,6 +55,7 @@ struct main_ctl { gint priority; GList **childs_list; + GList **list; pa_operation *(*move_child)(pa_context *, guint32 idx, guint32 parent_idx, pa_context_success_cb_t, gpointer); @@ -58,6 +64,8 @@ struct main_ctl { struct slave_ctl { struct vol_ctl base; guint32 parent_index; + GList **parent_list; + GList **list; }; #endif diff --git a/src/interface.c b/src/interface.c index 9c4cdc9..bbe902f 100644 --- a/src/interface.c +++ b/src/interface.c @@ -38,56 +38,6 @@ #include "unix_signal.h" #endif -static struct slave_ctl * -main_ctl_get_nth_child(struct context *ctx, struct main_ctl *ctl, int n) -{ - struct slave_ctl *sctl; - int i = 0; - - list_foreach(*ctl->childs_list, sctl) { - if (sctl->parent_index == ctl->base.index) - if (i++ == n) - return sctl; - } - - return NULL; -} - -struct vol_ctl * -interface_get_current_ctl(struct interface *ifc, struct vol_ctl **parent) -{ - struct context *ctx = container_of(ifc, struct context, interface); - struct main_ctl *main_ctl; - struct slave_ctl *sctl; - - if (parent) - *parent = NULL; - - main_ctl = g_list_nth_data(ctx->sink_list, ifc->chooser_main_ctl); - if (main_ctl == NULL) { - main_ctl = g_list_nth_data(ctx->source_list, - ifc->chooser_main_ctl - - g_list_length(ctx->sink_list)); - if (main_ctl == NULL) - return NULL; - } - - if (ifc->chooser_child == SELECTED_MAIN_CTL) - return &main_ctl->base; - else if (ifc->chooser_child >= 0) { - sctl = main_ctl_get_nth_child(ctx, (struct main_ctl *) main_ctl, - ifc->chooser_child); - if (sctl == NULL) - return NULL; - if (parent) - *parent = &main_ctl->base; - return &sctl->base; - } - - g_assert(0); - return NULL; -} - static void allocate_volume_bar(struct interface *ifc) { @@ -127,10 +77,9 @@ print_vol_ctl(gpointer data, gpointer user_data) struct vol_ctl *ctl = data; struct interface *ifc = user_data; gint x, y; - gboolean selected = (ctl == interface_get_current_ctl(ifc, NULL)); getyx(ifc->menu_win, y, x); - if (selected) + if (ctl == ifc->current_ctl) wattron(ifc->menu_win, A_REVERSE); if (!ctl->hide_index) @@ -139,7 +88,7 @@ print_vol_ctl(gpointer data, gpointer user_data) ctl->indent + (ctl->hide_index ? 2+1 : 0), "", ifc->max_name_len - ctl->indent, ctl->name); - if (selected) + if (ctl == ifc->current_ctl) wattroff(ifc->menu_win, A_REVERSE); print_volume(ifc, ctl); wmove(ifc->menu_win, y+1, x); @@ -179,6 +128,11 @@ interface_redraw(struct interface *ifc) ifc->volume_bar = NULL; } + if (ifc->current_ctl == NULL) + ifc->current_ctl = g_list_nth_data(ctx->sink_list, 0); + if (ifc->current_ctl == NULL) + ifc->current_ctl = g_list_nth_data(ctx->source_list, 0); + g_list_foreach(ctx->sink_list, max_name_len_helper, ifc); g_list_foreach(ctx->source_list, max_name_len_helper, ifc); @@ -287,11 +241,8 @@ interface_init(struct interface *ifc) { GIOChannel *input_channel; - /* Selected sink-device. 0 is the first device */ - ifc->chooser_main_ctl = 0; - /* Selected input of the current sink-device. */ - /* SELECTED_MAIN_CTL refers to sink-device itself */ - ifc->chooser_child = SELECTED_MAIN_CTL; + ifc->current_ctl = NULL; + initscr(); clear(); diff --git a/src/interface.h b/src/interface.h index c177c15..ef7cdc2 100644 --- a/src/interface.h +++ b/src/interface.h @@ -38,17 +38,12 @@ struct interface { int signal_fd; #endif guint input_source_id; - - gint chooser_main_ctl; - gint chooser_child; - guint max_name_len; gchar *status; -}; -struct vol_ctl * -interface_get_current_ctl(struct interface *ifc, struct vol_ctl **parent); + struct vol_ctl *current_ctl; +}; int interface_get_main_ctl_length(struct interface *ifc); diff --git a/src/pa-sink-ctl.c b/src/pa-sink-ctl.c index 77be8c1..68c7a0c 100644 --- a/src/pa-sink-ctl.c +++ b/src/pa-sink-ctl.c @@ -95,6 +95,50 @@ main_ctl_childs_len(struct vol_ctl *ctl) return len; } +static struct vol_ctl * +main_ctl_prev_ctl(struct vol_ctl *ctl) +{ + struct main_ctl *mctl = (struct main_ctl *) ctl; + GList *el, *prev; + + el = g_list_find(*mctl->list, mctl); + if (el == NULL) + return NULL; + prev = el->prev; + + return prev ? prev->data : NULL; +} + +static struct vol_ctl * +main_ctl_next_ctl(struct vol_ctl *ctl) +{ + struct main_ctl *mctl = (struct main_ctl *) ctl; + GList *el, *next; + + el = g_list_find(*mctl->list, mctl); + if (el == NULL) + return NULL; + next = el->next; + + return next ? next->data : NULL; +} + +static struct vol_ctl * +main_ctl_get_nth_child(struct vol_ctl *ctl, int n) +{ + struct main_ctl *mctl = (struct main_ctl *) ctl; + struct slave_ctl *sctl; + int i = 0; + + list_foreach(*mctl->childs_list, sctl) { + if (sctl->parent_index == mctl->base.index) + if (i++ == n) + return &sctl->base; + } + + return NULL; +} + static void sink_info_cb(pa_context *c, const pa_sink_info *i, gint is_last, gpointer userdata) @@ -127,7 +171,11 @@ sink_info_cb(pa_context *c, const pa_sink_info *i, sink->base.volume_set = pa_context_set_sink_volume_by_index; sink->base.childs_foreach = main_ctl_childs_foreach; sink->base.childs_len = main_ctl_childs_len; + sink->base.get_nth_child = main_ctl_get_nth_child; + sink->base.prev_ctl = main_ctl_prev_ctl; + sink->base.next_ctl = main_ctl_next_ctl; sink->move_child = pa_context_move_sink_input_by_index; + sink->list = &ctx->sink_list; sink->childs_list = &ctx->input_list; sink->priority = get_priority(ctx, i->proplist); @@ -176,7 +224,11 @@ source_info_cb(pa_context *c, const pa_source_info *i, source->base.volume_set = pa_context_set_source_volume_by_index; source->base.childs_foreach = main_ctl_childs_foreach; source->base.childs_len = main_ctl_childs_len; + source->base.get_nth_child = main_ctl_get_nth_child; + source->base.prev_ctl = main_ctl_prev_ctl; + source->base.next_ctl = main_ctl_next_ctl; source->move_child = pa_context_move_source_output_by_index; + source->list = &ctx->source_list; source->childs_list = &ctx->output_list; source->priority = get_priority(ctx, i->proplist); @@ -194,6 +246,57 @@ source_info_cb(pa_context *c, const pa_source_info *i, source->base.name = get_name(ctx, i->proplist, i->name); } +static struct vol_ctl * +slave_ctl_get_parent(struct vol_ctl *ctl) +{ + struct slave_ctl *sctl = (struct slave_ctl *) ctl; + struct vol_ctl *main_ctl; + + list_foreach(*sctl->parent_list, main_ctl) + if (sctl->parent_index == main_ctl->index) + return main_ctl; + + return NULL; +} + +static struct vol_ctl * +slave_ctl_prev_ctl(struct vol_ctl *ctl) +{ + struct slave_ctl *sctl = (struct slave_ctl *) ctl; + GList *el, *prev; + + el = g_list_find(*sctl->list, sctl); + if (el == NULL) + return NULL; + + while ((prev = el->prev)) { + struct slave_ctl *t = prev->data; + if (t->parent_index == sctl->parent_index) + return &t->base; + } + + return NULL; +} + +static struct vol_ctl * +slave_ctl_next_ctl(struct vol_ctl *ctl) +{ + struct slave_ctl *sctl = (struct slave_ctl *) ctl; + GList *el, *next; + + el = g_list_find(*sctl->list, sctl); + if (el == NULL) + return NULL; + + while ((next = el->next)) { + struct slave_ctl *t = next->data; + if (t->parent_index == sctl->parent_index) + return &t->base; + } + + return NULL; +} + static void sink_input_info_cb(pa_context *c, const pa_sink_input_info *i, gint is_last, gpointer userdata) @@ -228,6 +331,11 @@ sink_input_info_cb(pa_context *c, const pa_sink_input_info *i, sink_input->base.hide_index = TRUE; sink_input->base.mute_set = pa_context_set_sink_input_mute; sink_input->base.volume_set = pa_context_set_sink_input_volume; + sink_input->base.get_parent = slave_ctl_get_parent; + sink_input->base.prev_ctl = slave_ctl_prev_ctl; + sink_input->base.next_ctl = slave_ctl_next_ctl; + sink_input->list = &ctx->input_list; + sink_input->parent_list = &ctx->sink_list; ctx->input_list = g_list_append(ctx->input_list, sink_input); } else { sink_input = el->data; @@ -276,6 +384,11 @@ source_output_info_cb(pa_context *c, const pa_source_output_info *i, source_output->base.index = i->index; source_output->base.indent = 1; source_output->base.hide_index = TRUE; + source_output->base.get_parent = slave_ctl_get_parent; + source_output->base.prev_ctl = slave_ctl_prev_ctl; + source_output->base.next_ctl = slave_ctl_next_ctl; + source_output->list = &ctx->output_list; + source_output->parent_list = &ctx->source_list; ctx->output_list = g_list_append(ctx->output_list, source_output); } else { @@ -307,6 +420,9 @@ remove_index(struct context *ctx, GList **list, guint32 idx) if (el == NULL) return FALSE; + if (el->data == ctx->interface.current_ctl) + ctx->interface.current_ctl = NULL; + vol_ctl_free(el->data); *list = g_list_delete_link(*list, el); |