summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/command.c142
-rw-r--r--src/ctl.h8
-rw-r--r--src/interface.c67
-rw-r--r--src/interface.h9
-rw-r--r--src/pa-sink-ctl.c116
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
diff --git a/src/ctl.h b/src/ctl.h
index bb9ffda..e9ef304 100644
--- a/src/ctl.h
+++ b/src/ctl.h
@@ -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);