Merge lp:~diwic/gnome-control-center/sound-nua-rebase into lp:~ubuntu-desktop/gnome-control-center/ubuntu

Proposed by David Henningsson
Status: Merged
Merged at revision: 509
Proposed branch: lp:~diwic/gnome-control-center/sound-nua-rebase
Merge into: lp:~ubuntu-desktop/gnome-control-center/ubuntu
Diff against target: 3334 lines (+3310/-1)
3 files modified
debian/changelog (+4/-1)
debian/patches/series (+1/-0)
debian/patches/sound_nua_panel.patch (+3305/-0)
To merge this branch: bzr merge lp:~diwic/gnome-control-center/sound-nua-rebase
Reviewer Review Type Date Requested Status
Sebastien Bacher Approve
David Henningsson (community) Approve
Review via email: mp+134134@code.launchpad.net

Description of the change

Rebase sound-nua against Gnome 3.6 code. Most of the code is now upstreamed, but Gnome wanted to keep their old design, so therefore we still keep the UI pieces as a patch.

The patch is reduced by about 75% compared to the previous size.

To post a comment you must log in.
Revision history for this message
David Henningsson (diwic) :
review: Needs Fixing
513. By David Henningsson

changed the version number back again

514. By David Henningsson

Updated patch comment

Revision history for this message
David Henningsson (diwic) :
review: Approve
Revision history for this message
Sebastien Bacher (seb128) wrote :

Thanks David!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/changelog'
--- debian/changelog 2012-11-06 04:32:05 +0000
+++ debian/changelog 2012-11-13 15:56:18 +0000
@@ -69,7 +69,10 @@
69 - Drop ubuntu-docs and gnome-user-guide from recommends to suggests69 - Drop ubuntu-docs and gnome-user-guide from recommends to suggests
70 - Don't recommend indicators; let's leave that to Unity70 - Don't recommend indicators; let's leave that to Unity
7171
72 -- Jeremy Bicha <jbicha@ubuntu.com> Mon, 05 Nov 2012 23:14:29 -050072 [ David Henningsson ]
73 * sound_nua_panel.patch: Rebase to gnome 3.6
74
75 -- David Henningsson <david.henningsson@canonical.com> Tue, 13 Nov 2012 15:59:40 +0100
7376
74gnome-control-center (1:3.4.2-0ubuntu20) quantal-proposed; urgency=low77gnome-control-center (1:3.4.2-0ubuntu20) quantal-proposed; urgency=low
7578
7679
=== modified file 'debian/patches/series'
--- debian/patches/series 2012-11-06 04:32:05 +0000
+++ debian/patches/series 2012-11-13 15:56:18 +0000
@@ -29,3 +29,4 @@
29dont_download_local_image.patch29dont_download_local_image.patch
30classic_use_sound_indicator.patch30classic_use_sound_indicator.patch
31accounts_fix_unsetting_icon.patch31accounts_fix_unsetting_icon.patch
32sound_nua_panel.patch
3233
=== added file 'debian/patches/sound_nua_panel.patch'
--- debian/patches/sound_nua_panel.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/sound_nua_panel.patch 2012-11-13 15:56:18 +0000
@@ -0,0 +1,3305 @@
1# Description: New design of the sound capplet
2# Most of the code has now been upstreamed to Gnome, but they wanted
3# to keep their old design, so about 25% of the original patch remains.
4=== modified file 'configure.ac'
5Index: gnome-control-center-3.6.2/configure.ac
6===================================================================
7--- gnome-control-center-3.6.2.orig/configure.ac 2012-11-13 16:25:40.665717988 +0100
8+++ gnome-control-center-3.6.2/configure.ac 2012-11-13 16:25:40.773717987 +0100
9@@ -435,6 +435,9 @@
10 panels/online-accounts/icons/32x32/Makefile
11 panels/online-accounts/icons/48x48/Makefile
12 panels/online-accounts/icons/256x256/Makefile
13+panels/sound-nua/Makefile
14+panels/sound-nua/data/Makefile
15+panels/sound-nua/data/gnome-sound-nua-panel.desktop.in
16 panels/sound/Makefile
17 panels/sound/data/Makefile
18 panels/sound/data/gnome-sound-panel.desktop.in
19Index: gnome-control-center-3.6.2/panels/Makefile.am
20===================================================================
21--- gnome-control-center-3.6.2.orig/panels/Makefile.am 2012-10-01 11:38:59.000000000 +0200
22+++ gnome-control-center-3.6.2/panels/Makefile.am 2012-11-13 16:25:40.777717988 +0100
23@@ -10,6 +10,7 @@
24 region \
25 info \
26 sound \
27+ sound-nua \
28 keyboard \
29 universal-access \
30 user-accounts \
31Index: gnome-control-center-3.6.2/panels/sound-nua/Makefile.am
32===================================================================
33--- /dev/null 1970-01-01 00:00:00.000000000 +0000
34+++ gnome-control-center-3.6.2/panels/sound-nua/Makefile.am 2012-11-13 16:25:40.777717988 +0100
35@@ -0,0 +1,63 @@
36+SUBDIRS = data
37+
38+# This is used in PANEL_CFLAGS
39+cappletname = sound
40+NULL =
41+
42+ccpanelsdir = $(PANELS_DIR)
43+ccpanels_LTLIBRARIES = libsoundnua.la
44+
45+AM_CPPFLAGS = \
46+ $(PANEL_CFLAGS) \
47+ $(SOUND_PANEL_CFLAGS) \
48+ -DLOCALE_DIR=\""$(datadir)/locale"\" \
49+ -DLIBEXECDIR=\"$(libexecdir)\" \
50+ -DGLADEDIR=\""$(pkgdatadir)"\" \
51+ -DSOUND_DATA_DIR="\"$(datadir)/sounds\"" \
52+ -DSOUND_SET_DIR="\"$(pkgdatadir)/sounds\"" \
53+ -DICON_DATA_DIR="\"$(pkgdatadir)/icons\"" \
54+ -I../sound \
55+ $(NULL)
56+
57+libsoundnua_la_LIBADD = \
58+ -lm \
59+ ../sound/libgnomevolumecontrol.la \
60+ $(PANEL_LIBS) \
61+ $(SOUND_PANEL_LIBS) \
62+ $(NULL)
63+
64+libsoundnua_la_LDFLAGS = \
65+ $(PANEL_LDFLAGS) \
66+ $(NULL)
67+
68+libsoundnua_la_SOURCES = \
69+ gvc-balance-bar.h \
70+ gvc-balance-bar.c \
71+ gvc-mixer-dialog.h \
72+ gvc-mixer-dialog.c \
73+ ../sound/gvc-level-bar.h \
74+ ../sound/gvc-level-bar.c \
75+ ../sound/gvc-combo-box.h \
76+ ../sound/gvc-combo-box.c \
77+ ../sound/gvc-speaker-test.h \
78+ ../sound/gvc-speaker-test.c \
79+ ../sound/gvc-sound-theme-chooser.c \
80+ ../sound/gvc-sound-theme-chooser.h \
81+ ../sound/sound-theme-file-utils.c \
82+ ../sound/sound-theme-file-utils.h \
83+ cc-sound-panel.c \
84+ cc-sound-panel.h \
85+ $(NULL)
86+
87+BUILT_SOURCES = \
88+ $(NULL)
89+
90+CLEANFILES = \
91+ $(BUILT_SOURCES) \
92+ $(NULL)
93+
94+MAINTAINERCLEANFILES = \
95+ *~ \
96+ Makefile.in
97+
98+-include $(top_srcdir)/git.mk
99Index: gnome-control-center-3.6.2/panels/sound-nua/cc-sound-panel.c
100===================================================================
101--- /dev/null 1970-01-01 00:00:00.000000000 +0000
102+++ gnome-control-center-3.6.2/panels/sound-nua/cc-sound-panel.c 2012-11-13 16:25:40.777717988 +0100
103@@ -0,0 +1,141 @@
104+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
105+ *
106+ * Copyright (C) 2008 Red Hat, Inc.
107+ *
108+ * This program is free software; you can redistribute it and/or
109+ * modify it under the terms of the GNU General Public License as
110+ * published by the Free Software Foundation; either version 2 of the
111+ * License, or (at your option) any later version.
112+ *
113+ * This program is distributed in the hope that it will be useful, but
114+ * WITHOUT ANY WARRANTY; without even the implied warranty of
115+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
116+ * Lesser General Public License for more details.
117+ *
118+ * You should have received a copy of the GNU General Public License
119+ * along with this program; if not, write to the Free Software
120+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
121+ * 02111-1307, USA.
122+ */
123+
124+#include "config.h"
125+
126+#include <libintl.h>
127+#include <stdlib.h>
128+#include <string.h>
129+#include <unistd.h>
130+#include <errno.h>
131+
132+#include <glib/gi18n-lib.h>
133+#include <glib.h>
134+#include <gtk/gtk.h>
135+#include <pulse/pulseaudio.h>
136+
137+#include "cc-sound-panel.h"
138+#include "gvc-mixer-dialog.h"
139+
140+G_DEFINE_DYNAMIC_TYPE (CcSoundNuaPanel, cc_sound_panel, CC_TYPE_PANEL)
141+
142+enum {
143+ PROP_0,
144+ PROP_ARGV
145+};
146+
147+static void cc_sound_panel_finalize (GObject *object);
148+
149+static void
150+cc_sound_panel_set_property (GObject *object,
151+ guint property_id,
152+ const GValue *value,
153+ GParamSpec *pspec)
154+{
155+ CcSoundNuaPanel *self = CC_SOUND_PANEL (object);
156+
157+ switch (property_id) {
158+ case PROP_ARGV: {
159+ gchar **args;
160+
161+ args = g_value_get_boxed (value);
162+
163+ if (args && args[0]) {
164+ gvc_mixer_dialog_set_page (self->dialog, args[0]);
165+ }
166+ break;
167+ }
168+ default:
169+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
170+ }
171+}
172+
173+static void
174+cc_sound_panel_class_init (CcSoundNuaPanelClass *klass)
175+{
176+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
177+
178+ object_class->finalize = cc_sound_panel_finalize;
179+ object_class->set_property = cc_sound_panel_set_property;
180+
181+ g_object_class_override_property (object_class, PROP_ARGV, "argv");
182+}
183+
184+static void
185+cc_sound_panel_class_finalize (CcSoundNuaPanelClass *klass)
186+{
187+}
188+
189+static void
190+cc_sound_panel_finalize (GObject *object)
191+{
192+ CcSoundNuaPanel *panel = CC_SOUND_PANEL (object);
193+
194+ if (panel->dialog != NULL)
195+ panel->dialog = NULL;
196+ if (panel->connecting_label != NULL)
197+ panel->connecting_label = NULL;
198+ if (panel->control != NULL) {
199+ g_object_unref (panel->control);
200+ panel->control = NULL;
201+ }
202+
203+ G_OBJECT_CLASS (cc_sound_panel_parent_class)->finalize (object);
204+}
205+
206+static void
207+cc_sound_panel_init (CcSoundNuaPanel *self)
208+{
209+ gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
210+ ICON_DATA_DIR);
211+ gtk_window_set_default_icon_name ("multimedia-volume-control");
212+
213+ self->control = gvc_mixer_control_new ("GNOME Volume Control Dialog");
214+ gvc_mixer_control_open (self->control);
215+ self->dialog = gvc_mixer_dialog_new (self->control);
216+ gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->dialog));
217+ gtk_widget_show (GTK_WIDGET (self->dialog));
218+}
219+
220+void
221+cc_sound_panel_register (GIOModule *module)
222+{
223+ cc_sound_panel_register_type (G_TYPE_MODULE (module));
224+ g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT,
225+ CC_TYPE_SOUND_PANEL,
226+ "sound-nua", 0);
227+}
228+
229+/* GIO extension stuff */
230+void
231+g_io_module_load (GIOModule *module)
232+{
233+ bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
234+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
235+
236+ /* register the panel */
237+ cc_sound_panel_register (module);
238+}
239+
240+void
241+g_io_module_unload (GIOModule *module)
242+{
243+}
244+
245Index: gnome-control-center-3.6.2/panels/sound-nua/cc-sound-panel.h
246===================================================================
247--- /dev/null 1970-01-01 00:00:00.000000000 +0000
248+++ gnome-control-center-3.6.2/panels/sound-nua/cc-sound-panel.h 2012-11-13 16:25:40.777717988 +0100
249@@ -0,0 +1,60 @@
250+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
251+ *
252+ * Copyright (C) 2010 Red Hat, Inc.
253+ *
254+ * This program is free software; you can redistribute it and/or
255+ * modify it under the terms of the GNU General Public License as
256+ * published by the Free Software Foundation; either version 2 of the
257+ * License, or (at your option) any later version.
258+ *
259+ * This program is distributed in the hope that it will be useful, but
260+ * WITHOUT ANY WARRANTY; without even the implied warranty of
261+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
262+ * Lesser General Public License for more details.
263+ *
264+ * You should have received a copy of the GNU General Public License
265+ * along with this program; if not, write to the Free Software
266+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
267+ * 02111-1307, USA.
268+ */
269+
270+#ifndef _CC_SOUND_PANEL_H
271+#define _CC_SOUND_PANEL_H
272+
273+#include <shell/cc-panel.h>
274+#include "gvc-mixer-control.h"
275+#include "gvc-mixer-dialog.h"
276+
277+G_BEGIN_DECLS
278+
279+#define CC_TYPE_SOUND_PANEL cc_sound_panel_get_type()
280+#define CC_SOUND_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CC_TYPE_SOUND_PANEL, CcSoundNuaPanel))
281+#define CC_SOUND_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CC_TYPE_SOUND_PANEL, CcSoundNuaPanelClass))
282+#define CC_IS_SOUND_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CC_TYPE_SOUND_PANEL))
283+#define CC_IS_SOUND_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CC_TYPE_SOUND_PANEL))
284+#define CC_SOUND_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CC_TYPE_SOUND_PANEL, CcSoundNuaPanelClass))
285+
286+typedef struct _CcSoundNuaPanel CcSoundNuaPanel;
287+typedef struct _CcSoundNuaPanelClass CcSoundNuaPanelClass;
288+typedef struct _CcSoundNuaPanelPrivate CcSoundNuaPanelPrivate;
289+
290+struct _CcSoundNuaPanel {
291+ CcPanel parent;
292+
293+ GvcMixerControl *control;
294+ GvcMixerDialog *dialog;
295+ GtkWidget *connecting_label;
296+};
297+
298+struct _CcSoundNuaPanelClass {
299+ CcPanelClass parent_class;
300+};
301+
302+GType cc_sound_panel_get_type (void) G_GNUC_CONST;
303+
304+void cc_sound_panel_register (GIOModule *module);
305+
306+G_END_DECLS
307+
308+#endif /* _CC_SOUND_PANEL_H */
309+
310Index: gnome-control-center-3.6.2/panels/sound-nua/data/Makefile.am
311===================================================================
312--- /dev/null 1970-01-01 00:00:00.000000000 +0000
313+++ gnome-control-center-3.6.2/panels/sound-nua/data/Makefile.am 2012-11-13 16:25:40.777717988 +0100
314@@ -0,0 +1,17 @@
315+NULL =
316+
317+@INTLTOOL_DESKTOP_RULE@
318+
319+appsdir = $(datadir)/applications
320+apps_in_files = gnome-sound-nua-panel.desktop.in
321+apps_DATA = $(apps_in_files:.desktop.in=.desktop)
322+
323+EXTRA_DIST = \
324+ gnome-sound-nua-panel.desktop.in.in \
325+ $(NULL)
326+
327+CLEANFILES = \
328+ gnome-sound-nua-panel.desktop \
329+ $(NULL)
330+
331+-include $(top_srcdir)/git.mk
332Index: gnome-control-center-3.6.2/panels/sound-nua/data/gnome-sound-nua-panel.desktop.in.in
333===================================================================
334--- /dev/null 1970-01-01 00:00:00.000000000 +0000
335+++ gnome-control-center-3.6.2/panels/sound-nua/data/gnome-sound-nua-panel.desktop.in.in 2012-11-13 16:25:40.781717988 +0100
336@@ -0,0 +1,17 @@
337+[Desktop Entry]
338+_Name=Sound
339+_Comment=Change sound volume and sound events
340+Exec=gnome-control-center sound-nua
341+Icon=multimedia-volume-control
342+Terminal=false
343+Type=Application
344+StartupNotify=true
345+Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel;
346+OnlyShowIn=Unity;
347+X-GNOME-Bugzilla-Bugzilla=GNOME
348+X-GNOME-Bugzilla-Product=gnome-control-center
349+X-GNOME-Bugzilla-Component=sound
350+X-GNOME-Bugzilla-Version=@VERSION@
351+X-GNOME-Settings-Panel=sound-nua
352+# Translators: those are keywords for the sound control-center panel
353+_Keywords=Card;Microphone;Volume;Fade;Balance;Bluetooth;Headset;
354Index: gnome-control-center-3.6.2/panels/sound-nua/gvc-balance-bar.c
355===================================================================
356--- /dev/null 1970-01-01 00:00:00.000000000 +0000
357+++ gnome-control-center-3.6.2/panels/sound-nua/gvc-balance-bar.c 2012-11-13 16:25:40.797717987 +0100
358@@ -0,0 +1,575 @@
359+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
360+ *
361+ * Copyright (C) 2008 William Jon McCann
362+ *
363+ * This program is free software; you can redistribute it and/or modify
364+ * it under the terms of the GNU General Public License as published by
365+ * the Free Software Foundation; either version 2 of the License, or
366+ * (at your option) any later version.
367+ *
368+ * This program is distributed in the hope that it will be useful,
369+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
370+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
371+ * GNU General Public License for more details.
372+ *
373+ * You should have received a copy of the GNU General Public License
374+ * along with this program; if not, write to the Free Software
375+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
376+ *
377+ */
378+
379+#include "config.h"
380+
381+#include <stdlib.h>
382+#include <stdio.h>
383+#include <unistd.h>
384+
385+#include <glib.h>
386+#include <glib/gi18n-lib.h>
387+#include <gtk/gtk.h>
388+#include <canberra-gtk.h>
389+#include <pulse/pulseaudio.h>
390+
391+#include "gvc-balance-bar.h"
392+#include "gvc-channel-map-private.h"
393+
394+#define SCALE_SIZE 220
395+#define ADJUSTMENT_MAX_NORMAL 65536.0 /* PA_VOLUME_NORM */
396+
397+#define GVC_BALANCE_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_BALANCE_BAR, GvcBalanceBarPrivate))
398+
399+struct GvcBalanceBarPrivate
400+{
401+ GvcChannelMap *channel_map;
402+ GvcBalanceType btype;
403+ GtkWidget *scale_box;
404+ GtkWidget *start_box;
405+ GtkWidget *end_box;
406+ GtkWidget *label;
407+ GtkWidget *scale;
408+ GtkAdjustment *adjustment;
409+ GtkSizeGroup *size_group;
410+ gboolean symmetric;
411+ gboolean click_lock;
412+};
413+
414+enum
415+{
416+ PROP_0,
417+ PROP_CHANNEL_MAP,
418+ PROP_BALANCE_TYPE,
419+};
420+
421+static void gvc_balance_bar_class_init (GvcBalanceBarClass *klass);
422+static void gvc_balance_bar_init (GvcBalanceBar *balance_bar);
423+static void gvc_balance_bar_finalize (GObject *object);
424+
425+static gboolean on_scale_button_press_event (GtkWidget *widget,
426+ GdkEventButton *event,
427+ GvcBalanceBar *bar);
428+static gboolean on_scale_button_release_event (GtkWidget *widget,
429+ GdkEventButton *event,
430+ GvcBalanceBar *bar);
431+static gboolean on_scale_scroll_event (GtkWidget *widget,
432+ GdkEventScroll *event,
433+ GvcBalanceBar *bar);
434+static void on_adjustment_value_changed (GtkAdjustment *adjustment,
435+ GvcBalanceBar *bar);
436+
437+G_DEFINE_TYPE (GvcBalanceBar, gvc_balance_bar, GTK_TYPE_HBOX)
438+
439+static GtkWidget *
440+_scale_box_new (GvcBalanceBar *bar)
441+{
442+ GvcBalanceBarPrivate *priv = bar->priv;
443+ GtkWidget *box;
444+ GtkWidget *sbox;
445+ GtkWidget *ebox;
446+ GtkAdjustment *adjustment = bar->priv->adjustment;
447+ char *str_lower, *str_upper;
448+ gdouble lower, upper;
449+
450+ bar->priv->scale_box = box = gtk_box_new (FALSE, 6);
451+ priv->scale = gtk_hscale_new (priv->adjustment);
452+ gtk_widget_set_size_request (priv->scale, SCALE_SIZE, -1);
453+ gtk_scale_set_has_origin (GTK_SCALE (priv->scale), FALSE);
454+ gtk_widget_set_name (priv->scale, "balance-bar-scale");
455+ gtk_rc_parse_string ("style \"balance-bar-scale-style\" {\n"
456+ " GtkScale::trough-side-details = 0\n"
457+ "}\n"
458+ "widget \"*.balance-bar-scale\" style : rc \"balance-bar-scale-style\"\n");
459+
460+ bar->priv->start_box = sbox = gtk_box_new (FALSE, 6);
461+ gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0);
462+
463+ gtk_box_pack_start (GTK_BOX (sbox), priv->label, FALSE, FALSE, 0);
464+
465+ gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, TRUE, 0);
466+
467+ switch (bar->priv->btype) {
468+ case BALANCE_TYPE_RL:
469+ str_lower = g_strdup_printf ("<small>%s</small>", C_("balance", "Left"));
470+ str_upper = g_strdup_printf ("<small>%s</small>", C_("balance", "Right"));
471+ break;
472+ case BALANCE_TYPE_FR:
473+ str_lower = g_strdup_printf ("<small>%s</small>", C_("balance", "Rear"));
474+ str_upper = g_strdup_printf ("<small>%s</small>", C_("balance", "Front"));
475+ break;
476+ case BALANCE_TYPE_LFE:
477+ str_lower = g_strdup_printf ("<small>%s</small>", C_("balance", "Minimum"));
478+ str_upper = g_strdup_printf ("<small>%s</small>", C_("balance", "Maximum"));
479+ break;
480+ default:
481+ g_assert_not_reached ();
482+ }
483+
484+ lower = gtk_adjustment_get_lower (adjustment);
485+ gtk_scale_add_mark (GTK_SCALE (priv->scale), lower,
486+ GTK_POS_BOTTOM, str_lower);
487+ g_free (str_lower);
488+ upper = gtk_adjustment_get_upper (adjustment);
489+ gtk_scale_add_mark (GTK_SCALE (priv->scale), upper,
490+ GTK_POS_BOTTOM, str_upper);
491+ g_free (str_upper);
492+
493+ if (bar->priv->btype != BALANCE_TYPE_LFE) {
494+ gtk_scale_add_mark (GTK_SCALE (priv->scale),
495+ (upper - lower)/2 + lower,
496+ GTK_POS_BOTTOM, NULL);
497+ }
498+
499+ bar->priv->end_box = ebox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
500+ gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0);
501+
502+ ca_gtk_widget_disable_sounds (bar->priv->scale, FALSE);
503+ gtk_widget_add_events (bar->priv->scale, GDK_SCROLL_MASK);
504+
505+ g_signal_connect (G_OBJECT (bar->priv->scale), "button-press-event",
506+ G_CALLBACK (on_scale_button_press_event), bar);
507+ g_signal_connect (G_OBJECT (bar->priv->scale), "button-release-event",
508+ G_CALLBACK (on_scale_button_release_event), bar);
509+ g_signal_connect (G_OBJECT (bar->priv->scale), "scroll-event",
510+ G_CALLBACK (on_scale_scroll_event), bar);
511+
512+ if (bar->priv->size_group != NULL) {
513+ gtk_size_group_add_widget (bar->priv->size_group, sbox);
514+
515+ if (bar->priv->symmetric) {
516+ gtk_size_group_add_widget (bar->priv->size_group, ebox);
517+ }
518+ }
519+
520+ gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE);
521+
522+ return box;
523+}
524+
525+void
526+gvc_balance_bar_set_size_group (GvcBalanceBar *bar,
527+ GtkSizeGroup *group,
528+ gboolean symmetric)
529+{
530+ g_return_if_fail (GVC_IS_BALANCE_BAR (bar));
531+
532+ bar->priv->size_group = group;
533+ bar->priv->symmetric = symmetric;
534+
535+ if (bar->priv->size_group != NULL) {
536+ gtk_size_group_add_widget (bar->priv->size_group,
537+ bar->priv->start_box);
538+
539+ if (bar->priv->symmetric) {
540+ gtk_size_group_add_widget (bar->priv->size_group,
541+ bar->priv->end_box);
542+ }
543+ }
544+ gtk_widget_queue_draw (GTK_WIDGET (bar));
545+}
546+
547+static const char *
548+btype_to_string (guint btype)
549+{
550+ switch (btype) {
551+ case BALANCE_TYPE_RL:
552+ return "Balance";
553+ case BALANCE_TYPE_FR:
554+ return "Fade";
555+ break;
556+ case BALANCE_TYPE_LFE:
557+ return "LFE";
558+ default:
559+ g_assert_not_reached ();
560+ }
561+ return NULL;
562+}
563+
564+static void
565+update_level_from_map (GvcBalanceBar *bar,
566+ GvcChannelMap *map)
567+{
568+ const gdouble *volumes;
569+ gdouble val;
570+
571+ g_debug ("Volume changed (for %s bar)", btype_to_string (bar->priv->btype));
572+
573+ volumes = gvc_channel_map_get_volume (map);
574+ switch (bar->priv->btype) {
575+ case BALANCE_TYPE_RL:
576+ val = volumes[BALANCE];
577+ break;
578+ case BALANCE_TYPE_FR:
579+ val = volumes[FADE];
580+ break;
581+ case BALANCE_TYPE_LFE:
582+ val = volumes[LFE];
583+ break;
584+ default:
585+ g_assert_not_reached ();
586+ }
587+
588+ gtk_adjustment_set_value (bar->priv->adjustment, val);
589+}
590+
591+static void
592+on_channel_map_volume_changed (GvcChannelMap *map,
593+ gboolean set,
594+ GvcBalanceBar *bar)
595+{
596+ update_level_from_map (bar, map);
597+}
598+
599+static void
600+gvc_balance_bar_set_channel_map (GvcBalanceBar *bar,
601+ GvcChannelMap *map)
602+{
603+ g_return_if_fail (GVC_BALANCE_BAR (bar));
604+
605+ if (bar->priv->channel_map != NULL) {
606+ g_signal_handlers_disconnect_by_func (G_OBJECT (bar->priv->channel_map),
607+ on_channel_map_volume_changed, bar);
608+ g_object_unref (bar->priv->channel_map);
609+ }
610+ bar->priv->channel_map = g_object_ref (map);
611+
612+ update_level_from_map (bar, map);
613+
614+ g_signal_connect (G_OBJECT (map), "volume-changed",
615+ G_CALLBACK (on_channel_map_volume_changed), bar);
616+
617+ g_object_notify (G_OBJECT (bar), "channel-map");
618+}
619+
620+static void
621+gvc_balance_bar_set_balance_type (GvcBalanceBar *bar,
622+ GvcBalanceType btype)
623+{
624+ GtkWidget *frame;
625+
626+ g_return_if_fail (GVC_BALANCE_BAR (bar));
627+
628+ bar->priv->btype = btype;
629+ if (bar->priv->btype != BALANCE_TYPE_LFE) {
630+ bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
631+ -1.0,
632+ 1.0,
633+ 0.5,
634+ 0.5,
635+ 0.0));
636+ } else {
637+ bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
638+ 0.0,
639+ ADJUSTMENT_MAX_NORMAL,
640+ ADJUSTMENT_MAX_NORMAL/100.0,
641+ ADJUSTMENT_MAX_NORMAL/10.0,
642+ 0.0));
643+ }
644+
645+ g_object_ref_sink (bar->priv->adjustment);
646+ g_signal_connect (bar->priv->adjustment,
647+ "value-changed",
648+ G_CALLBACK (on_adjustment_value_changed),
649+ bar);
650+
651+ switch (btype) {
652+ case BALANCE_TYPE_RL:
653+ bar->priv->label = gtk_label_new_with_mnemonic (_("_Balance:"));
654+ break;
655+ case BALANCE_TYPE_FR:
656+ bar->priv->label = gtk_label_new_with_mnemonic (_("_Fade:"));
657+ break;
658+ case BALANCE_TYPE_LFE:
659+ bar->priv->label = gtk_label_new_with_mnemonic (_("_Subwoofer:"));
660+ break;
661+ default:
662+ g_assert_not_reached ();
663+ }
664+ gtk_misc_set_alignment (GTK_MISC (bar->priv->label),
665+ 0.0,
666+ 0.0);
667+ /* frame */
668+ frame = gtk_frame_new (NULL);
669+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
670+ gtk_container_add (GTK_CONTAINER (bar), frame);
671+
672+ /* box with scale */
673+ bar->priv->scale_box = _scale_box_new (bar);
674+ gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box);
675+ gtk_widget_show_all (frame);
676+
677+ gtk_widget_set_direction (bar->priv->scale, GTK_TEXT_DIR_LTR);
678+ gtk_label_set_mnemonic_widget (GTK_LABEL (bar->priv->label),
679+ bar->priv->scale);
680+
681+ g_object_notify (G_OBJECT (bar), "balance-type");
682+}
683+
684+static void
685+gvc_balance_bar_set_property (GObject *object,
686+ guint prop_id,
687+ const GValue *value,
688+ GParamSpec *pspec)
689+{
690+ GvcBalanceBar *self = GVC_BALANCE_BAR (object);
691+
692+ switch (prop_id) {
693+ case PROP_CHANNEL_MAP:
694+ gvc_balance_bar_set_channel_map (self, g_value_get_object (value));
695+ break;
696+ case PROP_BALANCE_TYPE:
697+ gvc_balance_bar_set_balance_type (self, g_value_get_int (value));
698+ break;
699+ default:
700+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
701+ break;
702+ }
703+}
704+
705+static void
706+gvc_balance_bar_get_property (GObject *object,
707+ guint prop_id,
708+ GValue *value,
709+ GParamSpec *pspec)
710+{
711+ GvcBalanceBar *self = GVC_BALANCE_BAR (object);
712+
713+ switch (prop_id) {
714+ case PROP_CHANNEL_MAP:
715+ g_value_set_object (value, self->priv->channel_map);
716+ break;
717+ default:
718+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
719+ break;
720+ }
721+}
722+
723+static GObject *
724+gvc_balance_bar_constructor (GType type,
725+ guint n_construct_properties,
726+ GObjectConstructParam *construct_params)
727+{
728+ return G_OBJECT_CLASS (gvc_balance_bar_parent_class)->constructor (type, n_construct_properties, construct_params);
729+}
730+
731+static void
732+gvc_balance_bar_class_init (GvcBalanceBarClass *klass)
733+{
734+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
735+
736+ object_class->constructor = gvc_balance_bar_constructor;
737+ object_class->finalize = gvc_balance_bar_finalize;
738+ object_class->set_property = gvc_balance_bar_set_property;
739+ object_class->get_property = gvc_balance_bar_get_property;
740+
741+ g_object_class_install_property (object_class,
742+ PROP_CHANNEL_MAP,
743+ g_param_spec_object ("channel-map",
744+ "channel map",
745+ "The channel map",
746+ GVC_TYPE_CHANNEL_MAP,
747+ G_PARAM_READWRITE));
748+ g_object_class_install_property (object_class,
749+ PROP_BALANCE_TYPE,
750+ g_param_spec_int ("balance-type",
751+ "balance type",
752+ "Whether the balance is right-left or front-rear",
753+ BALANCE_TYPE_RL, NUM_BALANCE_TYPES - 1, BALANCE_TYPE_RL,
754+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
755+
756+ g_type_class_add_private (klass, sizeof (GvcBalanceBarPrivate));
757+}
758+
759+
760+static gboolean
761+on_scale_button_press_event (GtkWidget *widget,
762+ GdkEventButton *event,
763+ GvcBalanceBar *bar)
764+{
765+ bar->priv->click_lock = TRUE;
766+
767+ return FALSE;
768+}
769+
770+static gboolean
771+on_scale_button_release_event (GtkWidget *widget,
772+ GdkEventButton *event,
773+ GvcBalanceBar *bar)
774+{
775+ bar->priv->click_lock = FALSE;
776+
777+ return FALSE;
778+}
779+
780+static gboolean
781+on_scale_scroll_event (GtkWidget *widget,
782+ GdkEventScroll *event,
783+ GvcBalanceBar *bar)
784+{
785+ gdouble value;
786+ gdouble dx, dy;
787+
788+ value = gtk_adjustment_get_value (bar->priv->adjustment);
789+
790+ if (!gdk_event_get_scroll_deltas ((GdkEvent*)event, &dx, &dy)) {
791+ dx = 0.0;
792+ dy = 0.0;
793+
794+ switch (event->direction) {
795+ case GDK_SCROLL_UP:
796+ case GDK_SCROLL_RIGHT:
797+ dy = 1.0;
798+ break;
799+ case GDK_SCROLL_DOWN:
800+ case GDK_SCROLL_LEFT:
801+ dy = -1.0;
802+ break;
803+ default:
804+ ;
805+ }
806+ }
807+
808+ if (bar->priv->btype == BALANCE_TYPE_LFE) {
809+ if (dy > 0) {
810+ if (value + dy * ADJUSTMENT_MAX_NORMAL/100.0 > ADJUSTMENT_MAX_NORMAL)
811+ value = ADJUSTMENT_MAX_NORMAL;
812+ else
813+ value = value + dy * ADJUSTMENT_MAX_NORMAL/100.0;
814+ } else if (dy < 0) {
815+ if (value + dy * ADJUSTMENT_MAX_NORMAL/100.0 < 0)
816+ value = 0.0;
817+ else
818+ value = value + dy * ADJUSTMENT_MAX_NORMAL/100.0;
819+ }
820+ } else {
821+ if (dy > 0) {
822+ if (value + dy * 0.01 > 1.0)
823+ value = 1.0;
824+ else
825+ value = value + dy * 0.01;
826+ } else if (dy < 0) {
827+ if (value + dy * 0.01 < -1.0)
828+ value = -1.0;
829+ else
830+ value = value + dy * 0.01;
831+ }
832+ }
833+ gtk_adjustment_set_value (bar->priv->adjustment, value);
834+
835+ return TRUE;
836+}
837+
838+/* FIXME remove when we depend on a newer PA */
839+static pa_cvolume *
840+gvc_pa_cvolume_set_position (pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t, pa_volume_t v) {
841+ unsigned c;
842+ gboolean good = FALSE;
843+
844+ g_assert(cv);
845+ g_assert(map);
846+
847+ g_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), NULL);
848+ g_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, NULL);
849+
850+ for (c = 0; c < map->channels; c++)
851+ if (map->map[c] == t) {
852+ cv->values[c] = v;
853+ good = TRUE;
854+ }
855+
856+ return good ? cv : NULL;
857+}
858+
859+static void
860+on_adjustment_value_changed (GtkAdjustment *adjustment,
861+ GvcBalanceBar *bar)
862+{
863+ gdouble val;
864+ pa_cvolume cv;
865+ const pa_channel_map *pa_map;
866+
867+ if (bar->priv->channel_map == NULL)
868+ return;
869+
870+ cv = *gvc_channel_map_get_cvolume (bar->priv->channel_map);
871+ val = gtk_adjustment_get_value (adjustment);
872+
873+ pa_map = gvc_channel_map_get_pa_channel_map (bar->priv->channel_map);
874+
875+ switch (bar->priv->btype) {
876+ case BALANCE_TYPE_RL:
877+ pa_cvolume_set_balance (&cv, pa_map, val);
878+ break;
879+ case BALANCE_TYPE_FR:
880+ pa_cvolume_set_fade (&cv, pa_map, val);
881+ break;
882+ case BALANCE_TYPE_LFE:
883+ gvc_pa_cvolume_set_position (&cv, pa_map, PA_CHANNEL_POSITION_LFE, val);
884+ break;
885+ }
886+
887+ gvc_channel_map_volume_changed (bar->priv->channel_map, &cv, TRUE);
888+}
889+
890+static void
891+gvc_balance_bar_init (GvcBalanceBar *bar)
892+{
893+ bar->priv = GVC_BALANCE_BAR_GET_PRIVATE (bar);
894+}
895+
896+static void
897+gvc_balance_bar_finalize (GObject *object)
898+{
899+ GvcBalanceBar *bar;
900+
901+ g_return_if_fail (object != NULL);
902+ g_return_if_fail (GVC_IS_BALANCE_BAR (object));
903+
904+ bar = GVC_BALANCE_BAR (object);
905+
906+ g_return_if_fail (bar->priv != NULL);
907+
908+ if (bar->priv->channel_map != NULL) {
909+ g_signal_handlers_disconnect_by_func (G_OBJECT (bar->priv->channel_map),
910+ on_channel_map_volume_changed, bar);
911+ g_object_unref (bar->priv->channel_map);
912+ }
913+
914+ G_OBJECT_CLASS (gvc_balance_bar_parent_class)->finalize (object);
915+}
916+
917+void
918+gvc_balance_bar_set_map (GvcBalanceBar* self,
919+ const GvcChannelMap *channel_map)
920+{
921+ g_object_set (G_OBJECT (self),
922+ "channel-map", channel_map, NULL);
923+}
924+
925+GtkWidget *
926+gvc_balance_bar_new (GvcBalanceType btype)
927+{
928+ GObject *bar;
929+ bar = g_object_new (GVC_TYPE_BALANCE_BAR,
930+ "balance-type", btype, NULL);
931+
932+ return GTK_WIDGET (bar);
933+}
934Index: gnome-control-center-3.6.2/panels/sound-nua/gvc-balance-bar.h
935===================================================================
936--- /dev/null 1970-01-01 00:00:00.000000000 +0000
937+++ gnome-control-center-3.6.2/panels/sound-nua/gvc-balance-bar.h 2012-11-13 16:25:40.873717987 +0100
938@@ -0,0 +1,70 @@
939+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
940+ *
941+ * Copyright (C) 2008 Red Hat, Inc.
942+ *
943+ * This program is free software; you can redistribute it and/or modify
944+ * it under the terms of the GNU General Public License as published by
945+ * the Free Software Foundation; either version 2 of the License, or
946+ * (at your option) any later version.
947+ *
948+ * This program is distributed in the hope that it will be useful,
949+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
950+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
951+ * GNU General Public License for more details.
952+ *
953+ * You should have received a copy of the GNU General Public License
954+ * along with this program; if not, write to the Free Software
955+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
956+ *
957+ */
958+
959+#ifndef __GVC_BALANCE_BAR_H
960+#define __GVC_BALANCE_BAR_H
961+
962+#include <glib-object.h>
963+
964+#include "gvc-channel-map.h"
965+
966+G_BEGIN_DECLS
967+
968+#define GVC_TYPE_BALANCE_BAR (gvc_balance_bar_get_type ())
969+#define GVC_BALANCE_BAR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_BALANCE_BAR, GvcBalanceBar))
970+#define GVC_BALANCE_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_BALANCE_BAR, GvcBalanceBarClass))
971+#define GVC_IS_BALANCE_BAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_BALANCE_BAR))
972+#define GVC_IS_BALANCE_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_BALANCE_BAR))
973+#define GVC_BALANCE_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_BALANCE_BAR, GvcBalanceBarClass))
974+
975+typedef enum {
976+ BALANCE_TYPE_RL,
977+ BALANCE_TYPE_FR,
978+ BALANCE_TYPE_LFE,
979+} GvcBalanceType;
980+
981+#define NUM_BALANCE_TYPES BALANCE_TYPE_LFE + 1
982+
983+typedef struct GvcBalanceBarPrivate GvcBalanceBarPrivate;
984+
985+typedef struct
986+{
987+ GtkHBox parent;
988+ GvcBalanceBarPrivate *priv;
989+} GvcBalanceBar;
990+
991+typedef struct
992+{
993+ GtkHBoxClass parent_class;
994+} GvcBalanceBarClass;
995+
996+GType gvc_balance_bar_get_type (void);
997+GtkWidget * gvc_balance_bar_new (GvcBalanceType btype);
998+
999+void gvc_balance_bar_set_size_group (GvcBalanceBar *bar,
1000+ GtkSizeGroup *group,
1001+ gboolean symmetric);
1002+
1003+void gvc_balance_bar_set_map (GvcBalanceBar *self,
1004+ const GvcChannelMap *channel_map);
1005+
1006+G_END_DECLS
1007+
1008+#endif /* __GVC_BALANCE_BAR_H */
1009Index: gnome-control-center-3.6.2/panels/sound-nua/gvc-mixer-dialog.c
1010===================================================================
1011--- /dev/null 1970-01-01 00:00:00.000000000 +0000
1012+++ gnome-control-center-3.6.2/panels/sound-nua/gvc-mixer-dialog.c 2012-11-13 16:26:26.245717312 +0100
1013@@ -0,0 +1,2187 @@
1014+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
1015+ *
1016+ * Copyright (C) 2008 William Jon McCann
1017+ * Copyright (C) 2012 Conor Curran
1018+ *
1019+ * This program is free software; you can redistribute it and/or modify
1020+ * it under the terms of the GNU General Public License as published by
1021+ * the Free Software Foundation; either version 2 of the License, or
1022+ * (at your option) any later version.
1023+ *
1024+ * This program is distributed in the hope that it will be useful,
1025+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1026+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1027+ * GNU General Public License for more details.
1028+ *
1029+ * You should have received a copy of the GNU General Public License
1030+ * along with this program; if not, write to the Free Software
1031+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1032+ *
1033+ */
1034+
1035+#include "config.h"
1036+
1037+#include <stdlib.h>
1038+#include <stdio.h>
1039+#include <unistd.h>
1040+#include <math.h>
1041+
1042+#include <glib.h>
1043+#include <glib/gi18n-lib.h>
1044+#include <gdk/gdkkeysyms.h>
1045+#include <gtk/gtk.h>
1046+#include <pulse/pulseaudio.h>
1047+
1048+
1049+#include "gvc-channel-bar.h"
1050+#include "gvc-balance-bar.h"
1051+#include "gvc-combo-box.h"
1052+#include "gvc-mixer-control.h"
1053+#include "gvc-mixer-card.h"
1054+#include "gvc-mixer-ui-device.h"
1055+#include "gvc-mixer-sink.h"
1056+#include "gvc-mixer-source.h"
1057+#include "gvc-mixer-source-output.h"
1058+#include "gvc-mixer-dialog.h"
1059+#include "gvc-sound-theme-chooser.h"
1060+#include "gvc-level-bar.h"
1061+#include "gvc-speaker-test.h"
1062+#include "gvc-mixer-control-private.h"
1063+
1064+#define SCALE_SIZE 128
1065+
1066+#define GVC_MIXER_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_DIALOG, GvcMixerDialogPrivate))
1067+
1068+struct GvcMixerDialogPrivate
1069+{
1070+ GvcMixerControl *mixer_control;
1071+ GHashTable *bars;
1072+ GtkWidget *notebook;
1073+ GtkWidget *output_bar;
1074+ GtkWidget *input_bar;
1075+ GtkWidget *input_level_bar;
1076+ GtkWidget *effects_bar;
1077+ GtkWidget *output_stream_box;
1078+ GtkWidget *sound_effects_box;
1079+ GtkWidget *hw_box;
1080+ GtkWidget *hw_treeview;
1081+ GtkWidget *hw_settings_box;
1082+ GtkWidget *hw_profile_combo;
1083+ GtkWidget *input_box;
1084+ GtkWidget *output_box;
1085+ GtkWidget *applications_box;
1086+ GtkWidget *no_apps_label;
1087+ GtkWidget *output_treeview;
1088+ GtkWidget *output_settings_box;
1089+ GtkWidget *output_balance_bar;
1090+ GtkWidget *output_fade_bar;
1091+ GtkWidget *output_lfe_bar;
1092+ GtkWidget *output_profile_combo;
1093+ GtkWidget *input_profile_combo;
1094+ GtkWidget *input_treeview;
1095+ GtkWidget *input_settings_box;
1096+ GtkWidget *sound_theme_chooser;
1097+ GtkWidget *click_feedback_button;
1098+ GtkWidget *audible_bell_button;
1099+ GtkSizeGroup *size_group;
1100+ GtkWidget *selected_output_label;
1101+ GtkWidget *selected_input_label;
1102+ GtkWidget *test_output_button;
1103+ GSettings *indicator_settings;
1104+
1105+ gdouble last_input_peak;
1106+ guint num_apps;
1107+};
1108+
1109+enum {
1110+ NAME_COLUMN,
1111+ DEVICE_COLUMN,
1112+ ACTIVE_COLUMN,
1113+ ID_COLUMN,
1114+ SPEAKERS_COLUMN,
1115+ ICON_COLUMN,
1116+ NUM_COLUMNS
1117+};
1118+
1119+enum {
1120+ HW_ID_COLUMN,
1121+ HW_ICON_COLUMN,
1122+ HW_NAME_COLUMN,
1123+ HW_STATUS_COLUMN,
1124+ HW_PROFILE_COLUMN,
1125+ HW_PROFILE_HUMAN_COLUMN,
1126+ HW_SENSITIVE_COLUMN,
1127+ HW_NUM_COLUMNS
1128+};
1129+
1130+enum
1131+{
1132+ PROP_0,
1133+ PROP_MIXER_CONTROL
1134+};
1135+
1136+static void gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass);
1137+static void gvc_mixer_dialog_init (GvcMixerDialog *mixer_dialog);
1138+static void gvc_mixer_dialog_finalize (GObject *object);
1139+
1140+static void bar_set_stream (GvcMixerDialog *dialog,
1141+ GtkWidget *bar,
1142+ GvcMixerStream *stream);
1143+
1144+static void on_adjustment_value_changed (GtkAdjustment *adjustment,
1145+ GvcMixerDialog *dialog);
1146+static void on_control_output_added (GvcMixerControl *control,
1147+ guint id,
1148+ GvcMixerDialog *dialog);
1149+static void on_control_active_output_update (GvcMixerControl *control,
1150+ guint id,
1151+ GvcMixerDialog *dialog);
1152+
1153+static void on_control_active_input_update (GvcMixerControl *control,
1154+ guint id,
1155+ GvcMixerDialog *dialog);
1156+
1157+G_DEFINE_TYPE (GvcMixerDialog, gvc_mixer_dialog, GTK_TYPE_VBOX)
1158+
1159+
1160+static void
1161+update_description (GvcMixerDialog *dialog,
1162+ guint column,
1163+ const char *value,
1164+ GvcMixerStream *stream)
1165+{
1166+ GtkTreeModel *model;
1167+ GtkTreeIter iter;
1168+ guint id;
1169+
1170+ if (GVC_IS_MIXER_SOURCE (stream))
1171+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
1172+ else if (GVC_IS_MIXER_SINK (stream))
1173+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
1174+ else
1175+ g_assert_not_reached ();
1176+
1177+ if (gtk_tree_model_get_iter_first (model, &iter) == FALSE){
1178+ g_warning ("The tree is empty => Cannot update the description");
1179+ return;
1180+ }
1181+
1182+ id = gvc_mixer_stream_get_id (stream);
1183+ do {
1184+ guint current_id;
1185+
1186+ gtk_tree_model_get (model, &iter,
1187+ ID_COLUMN, &current_id,
1188+ -1);
1189+ if (id != current_id)
1190+ continue;
1191+
1192+ gtk_list_store_set (GTK_LIST_STORE (model),
1193+ &iter,
1194+ column, value,
1195+ -1);
1196+ break;
1197+ } while (gtk_tree_model_iter_next (model, &iter));
1198+}
1199+
1200+static void
1201+profile_selection_changed (GvcComboBox *combo_box,
1202+ const char *profile,
1203+ GvcMixerDialog *dialog)
1204+{
1205+ g_debug ("profile_selection_changed - %s", profile);
1206+ GvcMixerUIDevice *out;
1207+ out = g_object_get_data (G_OBJECT (combo_box), "uidevice");
1208+
1209+ if (out == NULL) {
1210+ g_warning ("Could not find Output for profile combo box");
1211+ return;
1212+ }
1213+
1214+ g_debug (" \n on profile selection changed on output with \n description %s \n origin %s \n id %i \n \n",
1215+ gvc_mixer_ui_device_get_description (out),
1216+ gvc_mixer_ui_device_get_origin (out),
1217+ gvc_mixer_ui_device_get_id (out));
1218+
1219+ if (gvc_mixer_control_change_profile_on_selected_device (dialog->priv->mixer_control, out, profile) == FALSE) {
1220+ g_warning ("Could not change profile on device %s",
1221+ gvc_mixer_ui_device_get_description (out));
1222+ }
1223+}
1224+
1225+#define DECAY_STEP .15
1226+
1227+static void
1228+update_input_peak (GvcMixerDialog *dialog,
1229+ gdouble v)
1230+{
1231+ GtkAdjustment *adj;
1232+
1233+ if (dialog->priv->last_input_peak >= DECAY_STEP) {
1234+ if (v < dialog->priv->last_input_peak - DECAY_STEP) {
1235+ v = dialog->priv->last_input_peak - DECAY_STEP;
1236+ }
1237+ }
1238+
1239+ dialog->priv->last_input_peak = v;
1240+
1241+ adj = gvc_level_bar_get_peak_adjustment (GVC_LEVEL_BAR (dialog->priv->input_level_bar));
1242+ if (v >= 0) {
1243+ gtk_adjustment_set_value (adj, v);
1244+ } else {
1245+ gtk_adjustment_set_value (adj, 0.0);
1246+ }
1247+}
1248+
1249+static void
1250+update_input_meter (GvcMixerDialog *dialog,
1251+ uint32_t source_index,
1252+ uint32_t sink_input_idx,
1253+ double v)
1254+{
1255+ update_input_peak (dialog, v);
1256+}
1257+
1258+static void
1259+on_monitor_suspended_callback (pa_stream *s,
1260+ void *userdata)
1261+{
1262+ GvcMixerDialog *dialog;
1263+
1264+ dialog = userdata;
1265+
1266+ if (pa_stream_is_suspended (s)) {
1267+ g_debug ("Stream suspended");
1268+ update_input_meter (dialog,
1269+ pa_stream_get_device_index (s),
1270+ PA_INVALID_INDEX,
1271+ -1);
1272+ }
1273+}
1274+
1275+static void
1276+on_monitor_read_callback (pa_stream *s,
1277+ size_t length,
1278+ void *userdata)
1279+{
1280+ GvcMixerDialog *dialog;
1281+ const void *data;
1282+ double v;
1283+
1284+ dialog = userdata;
1285+
1286+ if (pa_stream_peek (s, &data, &length) < 0) {
1287+ g_warning ("Failed to read data from stream");
1288+ return;
1289+ }
1290+
1291+ assert (length > 0);
1292+ assert (length % sizeof (float) == 0);
1293+
1294+ v = ((const float *) data)[length / sizeof (float) -1];
1295+
1296+ pa_stream_drop (s);
1297+
1298+ if (v < 0) {
1299+ v = 0;
1300+ }
1301+ if (v > 1) {
1302+ v = 1;
1303+ }
1304+
1305+ update_input_meter (dialog,
1306+ pa_stream_get_device_index (s),
1307+ pa_stream_get_monitor_stream (s),
1308+ v);
1309+}
1310+
1311+static void
1312+create_monitor_stream_for_source (GvcMixerDialog *dialog,
1313+ GvcMixerStream *stream)
1314+{
1315+ pa_stream *s;
1316+ char t[16];
1317+ pa_buffer_attr attr;
1318+ pa_sample_spec ss;
1319+ pa_context *context;
1320+ int res;
1321+ pa_proplist *proplist;
1322+ gboolean has_monitor;
1323+
1324+ if (stream == NULL) {
1325+ g_debug ("\n create_monitor_stream_for_source - stream is null - returning\n");
1326+ return;
1327+ }
1328+ has_monitor = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (stream), "has-monitor"));
1329+ if (has_monitor != FALSE) {
1330+ g_debug ("\n create_monitor_stream_for_source, has monitor is not false - returning \n");
1331+ return;
1332+ }
1333+
1334+ g_debug ("Create monitor for %u",
1335+ gvc_mixer_stream_get_index (stream));
1336+
1337+ context = gvc_mixer_control_get_pa_context (dialog->priv->mixer_control);
1338+
1339+ if (pa_context_get_server_protocol_version (context) < 13) {
1340+ g_debug ("\n create_monitor_stream_for_source - protocol version is less 13 \n");
1341+ return;
1342+ }
1343+
1344+ ss.channels = 1;
1345+ ss.format = PA_SAMPLE_FLOAT32;
1346+ ss.rate = 25;
1347+
1348+ memset (&attr, 0, sizeof (attr));
1349+ attr.fragsize = sizeof (float);
1350+ attr.maxlength = (uint32_t) -1;
1351+
1352+ snprintf (t, sizeof (t), "%u", gvc_mixer_stream_get_index (stream));
1353+
1354+ proplist = pa_proplist_new ();
1355+ pa_proplist_sets (proplist, PA_PROP_APPLICATION_ID, "org.gnome.VolumeControl");
1356+ s = pa_stream_new_with_proplist (context, _("Peak detect"), &ss, NULL, proplist);
1357+ pa_proplist_free (proplist);
1358+ if (s == NULL) {
1359+ g_warning ("Failed to create monitoring stream");
1360+ return;
1361+ }
1362+
1363+ pa_stream_set_read_callback (s, on_monitor_read_callback, dialog);
1364+ pa_stream_set_suspended_callback (s, on_monitor_suspended_callback, dialog);
1365+
1366+ res = pa_stream_connect_record (s,
1367+ t,
1368+ &attr,
1369+ (pa_stream_flags_t) (PA_STREAM_DONT_MOVE
1370+ |PA_STREAM_PEAK_DETECT
1371+ |PA_STREAM_ADJUST_LATENCY));
1372+ if (res < 0) {
1373+ g_warning ("Failed to connect monitoring stream");
1374+ pa_stream_unref (s);
1375+ } else {
1376+ g_object_set_data (G_OBJECT (stream), "has-monitor", GINT_TO_POINTER (TRUE));
1377+ g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream", s);
1378+ g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "stream", stream);
1379+ }
1380+}
1381+
1382+
1383+static void
1384+stop_monitor_stream_for_source (GvcMixerDialog *dialog)
1385+{
1386+ pa_stream *s;
1387+ pa_context *context;
1388+ int res = 0;
1389+ GvcMixerStream *stream;
1390+
1391+ stream = g_object_get_data (G_OBJECT (dialog->priv->input_level_bar), "stream");
1392+
1393+ if (stream == NULL){
1394+ g_debug ("\n stop_monitor_stream_for_source - gvcstream is null - returning \n");
1395+ return;
1396+ }
1397+ else{
1398+ g_debug ("\n stop_monitor_stream_for_source - gvcstream is not null - continue \n");
1399+ }
1400+
1401+ s = g_object_get_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream");
1402+
1403+ if (s != NULL){
1404+ res = pa_stream_disconnect (s);
1405+ if (res == 0) {
1406+ g_debug("stream has been disconnected");
1407+ pa_stream_unref (s);
1408+ }
1409+ g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream", NULL);
1410+ }
1411+
1412+ context = gvc_mixer_control_get_pa_context (dialog->priv->mixer_control);
1413+
1414+ if (pa_context_get_server_protocol_version (context) < 13) {
1415+ return;
1416+ }
1417+ if (res == 0) {
1418+ g_object_set_data (G_OBJECT (stream), "has-monitor", GINT_TO_POINTER (FALSE));
1419+ }
1420+ g_debug ("Stopping monitor for %u", pa_stream_get_index (s));
1421+ g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "stream", NULL);
1422+}
1423+
1424+static void
1425+gvc_mixer_dialog_set_mixer_control (GvcMixerDialog *dialog,
1426+ GvcMixerControl *control)
1427+{
1428+ g_return_if_fail (GVC_MIXER_DIALOG (dialog));
1429+ g_return_if_fail (GVC_IS_MIXER_CONTROL (control));
1430+
1431+ g_object_ref (control);
1432+
1433+ if (dialog->priv->mixer_control != NULL) {
1434+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
1435+ G_CALLBACK (on_control_active_output_update),
1436+ dialog);
1437+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
1438+ G_CALLBACK (on_control_active_input_update),
1439+ dialog);
1440+ g_object_unref (dialog->priv->mixer_control);
1441+ }
1442+
1443+ dialog->priv->mixer_control = control;
1444+
1445+ g_signal_connect (dialog->priv->mixer_control,
1446+ "active-output-update",
1447+ G_CALLBACK (on_control_active_output_update),
1448+ dialog);
1449+ g_signal_connect (dialog->priv->mixer_control,
1450+ "active-input-update",
1451+ G_CALLBACK (on_control_active_input_update),
1452+ dialog);
1453+
1454+ g_object_notify (G_OBJECT (dialog), "mixer-control");
1455+}
1456+
1457+static GvcMixerControl *
1458+gvc_mixer_dialog_get_mixer_control (GvcMixerDialog *dialog)
1459+{
1460+ g_return_val_if_fail (GVC_IS_MIXER_DIALOG (dialog), NULL);
1461+
1462+ return dialog->priv->mixer_control;
1463+}
1464+
1465+static void
1466+gvc_mixer_dialog_set_property (GObject *object,
1467+ guint prop_id,
1468+ const GValue *value,
1469+ GParamSpec *pspec)
1470+{
1471+ GvcMixerDialog *self = GVC_MIXER_DIALOG (object);
1472+
1473+ switch (prop_id) {
1474+ case PROP_MIXER_CONTROL:
1475+ gvc_mixer_dialog_set_mixer_control (self, g_value_get_object (value));
1476+ break;
1477+ default:
1478+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1479+ break;
1480+ }
1481+}
1482+
1483+static void
1484+gvc_mixer_dialog_get_property (GObject *object,
1485+ guint prop_id,
1486+ GValue *value,
1487+ GParamSpec *pspec)
1488+{
1489+ GvcMixerDialog *self = GVC_MIXER_DIALOG (object);
1490+
1491+ switch (prop_id) {
1492+ case PROP_MIXER_CONTROL:
1493+ g_value_set_object (value, gvc_mixer_dialog_get_mixer_control (self));
1494+ break;
1495+ default:
1496+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1497+ break;
1498+ }
1499+}
1500+
1501+static void
1502+on_adjustment_value_changed (GtkAdjustment *adjustment,
1503+ GvcMixerDialog *dialog)
1504+{
1505+ GvcMixerStream *stream;
1506+
1507+ stream = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-stream");
1508+ if (stream != NULL) {
1509+ GObject *bar;
1510+ gdouble volume, rounded;
1511+ char *name;
1512+
1513+ volume = gtk_adjustment_get_value (adjustment);
1514+ rounded = round (volume);
1515+
1516+ bar = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-bar");
1517+ g_object_get (bar, "name", &name, NULL);
1518+ g_debug ("Setting stream volume %lf (rounded: %lf) for bar '%s'", volume, rounded, name);
1519+ g_free (name);
1520+
1521+ /* FIXME would need to do that in the balance bar really... */
1522+ /* Make sure we do not unmute muted streams, there's a button for that */
1523+ if (volume == 0.0)
1524+ gvc_mixer_stream_set_is_muted (stream, TRUE);
1525+ /* Only push the volume if it's actually changed */
1526+ if (gvc_mixer_stream_set_volume(stream, (pa_volume_t) rounded) != FALSE)
1527+ gvc_mixer_stream_push_volume (stream);
1528+ }
1529+}
1530+
1531+static void
1532+on_bar_is_muted_notify (GObject *object,
1533+ GParamSpec *pspec,
1534+ GvcMixerDialog *dialog)
1535+{
1536+ gboolean is_muted;
1537+ GvcMixerStream *stream;
1538+
1539+ is_muted = gvc_channel_bar_get_is_muted (GVC_CHANNEL_BAR (object));
1540+
1541+ stream = g_object_get_data (object, "gvc-mixer-dialog-stream");
1542+ if (stream != NULL) {
1543+ gvc_mixer_stream_change_is_muted (stream, is_muted);
1544+ } else {
1545+ char *name;
1546+ g_object_get (object, "name", &name, NULL);
1547+ g_warning ("Unable to find stream for bar '%s'", name);
1548+ g_free (name);
1549+ }
1550+}
1551+
1552+static GtkWidget *
1553+lookup_bar_for_stream (GvcMixerDialog *dialog,
1554+ GvcMixerStream *stream)
1555+{
1556+ GtkWidget *bar;
1557+
1558+ bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)));
1559+
1560+ return bar;
1561+}
1562+
1563+// TODO
1564+// Do we need this ?
1565+// UI devices now pull description material mainly for the card ports.
1566+// Therefore the need for stream description dynamic changes more than ever seems unneccessary.
1567+static void
1568+on_stream_description_notify (GvcMixerStream *stream,
1569+ GParamSpec *pspec,
1570+ GvcMixerDialog *dialog)
1571+{
1572+ update_description (dialog, NAME_COLUMN,
1573+ gvc_mixer_stream_get_description (stream),
1574+ stream);
1575+}
1576+
1577+static void
1578+on_stream_volume_notify (GObject *object,
1579+ GParamSpec *pspec,
1580+ GvcMixerDialog *dialog)
1581+{
1582+ GvcMixerStream *stream;
1583+ GtkWidget *bar;
1584+ GtkAdjustment *adj;
1585+ stream = GVC_MIXER_STREAM (object);
1586+
1587+ bar = lookup_bar_for_stream (dialog, stream);
1588+
1589+ if (bar == NULL) {
1590+ if (stream == gvc_mixer_control_get_default_sink(dialog->priv->mixer_control)) {
1591+ bar = dialog->priv->output_bar;
1592+ }
1593+ else if(stream == gvc_mixer_control_get_default_source(dialog->priv->mixer_control)) {
1594+ bar = dialog->priv->input_bar;
1595+ }
1596+ else{
1597+ g_warning ("Unable to find bar for stream %s in on_stream_volume_notify()",
1598+ gvc_mixer_stream_get_name (stream));
1599+ return;
1600+ }
1601+ }
1602+
1603+ adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
1604+
1605+ g_signal_handlers_block_by_func (adj,
1606+ on_adjustment_value_changed,
1607+ dialog);
1608+
1609+ gtk_adjustment_set_value (adj,
1610+ gvc_mixer_stream_get_volume (stream));
1611+
1612+ g_signal_handlers_unblock_by_func (adj,
1613+ on_adjustment_value_changed,
1614+ dialog);
1615+}
1616+
1617+static void
1618+on_stream_is_muted_notify (GObject *object,
1619+ GParamSpec *pspec,
1620+ GvcMixerDialog *dialog)
1621+{
1622+ GvcMixerStream *stream;
1623+ GtkWidget *bar;
1624+ gboolean is_muted;
1625+
1626+ stream = GVC_MIXER_STREAM (object);
1627+
1628+ bar = lookup_bar_for_stream (dialog, stream);
1629+
1630+ if (bar == NULL) {
1631+ if (stream == gvc_mixer_control_get_default_sink(dialog->priv->mixer_control)) {
1632+ bar = dialog->priv->output_bar;
1633+ }
1634+ else if(stream == gvc_mixer_control_get_default_source(dialog->priv->mixer_control)) {
1635+ bar = dialog->priv->input_bar;
1636+ }
1637+ else{
1638+ g_warning ("Unable to find bar for stream %s in on_stream_muted_notify()",
1639+ gvc_mixer_stream_get_name (stream));
1640+ return;
1641+ }
1642+ }
1643+
1644+
1645+ is_muted = gvc_mixer_stream_get_is_muted (stream);
1646+ gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar),
1647+ is_muted);
1648+
1649+ if (stream == gvc_mixer_control_get_default_sink (dialog->priv->mixer_control)) {
1650+ gtk_widget_set_sensitive (dialog->priv->applications_box,
1651+ !is_muted);
1652+ }
1653+
1654+}
1655+
1656+static void
1657+save_bar_for_stream (GvcMixerDialog *dialog,
1658+ GvcMixerStream *stream,
1659+ GtkWidget *bar)
1660+{
1661+ g_debug ("\n saving bar for stream %s",
1662+ gvc_mixer_stream_get_name (stream));
1663+ g_hash_table_insert (dialog->priv->bars,
1664+ GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)),
1665+ bar);
1666+}
1667+
1668+static GtkWidget *
1669+create_bar (GvcMixerDialog *dialog,
1670+ gboolean add_to_size_group,
1671+ gboolean symmetric)
1672+{
1673+ GtkWidget *bar;
1674+
1675+ bar = gvc_channel_bar_new ();
1676+ gtk_widget_set_sensitive (bar, FALSE);
1677+ if (add_to_size_group && dialog->priv->size_group != NULL) {
1678+ gvc_channel_bar_set_size_group (GVC_CHANNEL_BAR (bar),
1679+ dialog->priv->size_group,
1680+ symmetric);
1681+ }
1682+ gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (bar),
1683+ GTK_ORIENTATION_HORIZONTAL);
1684+ gvc_channel_bar_set_show_mute (GVC_CHANNEL_BAR (bar),
1685+ TRUE);
1686+ g_signal_connect (bar,
1687+ "notify::is-muted",
1688+ G_CALLBACK (on_bar_is_muted_notify),
1689+ dialog);
1690+ return bar;
1691+}
1692+
1693+static GtkWidget *
1694+create_app_bar (GvcMixerDialog *dialog,
1695+ const char *name,
1696+ const char *icon_name)
1697+{
1698+ GtkWidget *bar;
1699+
1700+ bar = create_bar (dialog, FALSE, FALSE);
1701+ gvc_channel_bar_set_ellipsize (GVC_CHANNEL_BAR (bar), TRUE);
1702+ gvc_channel_bar_set_icon_name (GVC_CHANNEL_BAR (bar), icon_name);
1703+ if (name == NULL || strchr (name, '_') == NULL) {
1704+ gvc_channel_bar_set_name (GVC_CHANNEL_BAR (bar), name);
1705+ } else {
1706+ char **tokens, *escaped;
1707+
1708+ tokens = g_strsplit (name, "_", -1);
1709+ escaped = g_strjoinv ("__", tokens);
1710+ g_strfreev (tokens);
1711+ gvc_channel_bar_set_name (GVC_CHANNEL_BAR (bar), escaped);
1712+ g_free (escaped);
1713+ }
1714+
1715+ return bar;
1716+}
1717+
1718+static gint test_it = 0;
1719+
1720+/* active_input_update
1721+ * Handle input update change from the backend (control).
1722+ * Trust the backend whole-heartedly to deliver the correct input
1723+ * i.e. keep it MVC.
1724+ */
1725+static void
1726+active_input_update (GvcMixerDialog *dialog,
1727+ GvcMixerUIDevice *active_input)
1728+{
1729+ g_debug ("\n active_input_update %s \n", gvc_mixer_ui_device_get_description (active_input));
1730+ // First make sure the correct UI device is selected.
1731+ GtkTreeModel *model;
1732+ GtkTreeIter iter;
1733+
1734+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
1735+
1736+ if (gtk_tree_model_get_iter_first (model, &iter) == FALSE){
1737+ g_warning ("The tree is empty => we have no devices so cannot set the active input");
1738+ return;
1739+ }
1740+
1741+ do {
1742+ gboolean is_selected = FALSE;
1743+ gint id;
1744+
1745+ gtk_tree_model_get (model, &iter,
1746+ ID_COLUMN, &id,
1747+ -1);
1748+
1749+ is_selected = id == gvc_mixer_ui_device_get_id (active_input);
1750+
1751+ gtk_list_store_set (GTK_LIST_STORE (model),
1752+ &iter,
1753+ ACTIVE_COLUMN, is_selected,
1754+ -1);
1755+
1756+ if (is_selected) {
1757+ GtkTreeSelection *selection;
1758+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->input_treeview));
1759+ gtk_tree_selection_select_iter (selection, &iter);
1760+ }
1761+
1762+ }while (gtk_tree_model_iter_next (model, &iter));
1763+
1764+
1765+ // Not ideal but for now destroy the combo and recreate below.
1766+ if (dialog->priv->input_profile_combo != NULL) {
1767+ gtk_container_remove (GTK_CONTAINER (dialog->priv->input_settings_box),
1768+ dialog->priv->input_profile_combo);
1769+ dialog->priv->input_profile_combo = NULL;
1770+ }
1771+
1772+ GvcMixerStream *stream;
1773+ GtkAdjustment *adj;
1774+
1775+ stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control,
1776+ active_input);
1777+ if (stream == NULL) {
1778+ g_warning ("active_input_update - couldn't find a stream from the supposed active input");
1779+ gtk_widget_set_sensitive (dialog->priv->input_bar,
1780+ FALSE);
1781+ return;
1782+ }
1783+
1784+ // Set the label accordingly
1785+ adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->input_bar)));
1786+ g_signal_handlers_disconnect_by_func(adj, on_adjustment_value_changed, dialog);
1787+
1788+ gtk_label_set_label (GTK_LABEL(dialog->priv->selected_input_label),
1789+ g_strdup_printf(_("Settings for %s"),
1790+ gvc_mixer_ui_device_get_description (active_input)));
1791+
1792+ gvc_channel_bar_set_base_volume (GVC_CHANNEL_BAR (dialog->priv->input_bar),
1793+ gvc_mixer_stream_get_base_volume (stream));
1794+ gvc_channel_bar_set_is_amplified (GVC_CHANNEL_BAR (dialog->priv->input_bar),
1795+ gvc_mixer_stream_get_can_decibel (stream));
1796+ /* Update the adjustment in case the previous bar wasn't decibel
1797+ * capable, and we clipped it */
1798+ adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->input_bar)));
1799+ gtk_adjustment_set_value (adj,
1800+ gvc_mixer_stream_get_volume (stream));
1801+
1802+ stop_monitor_stream_for_source (dialog);
1803+ //if (test_it < 6){
1804+ create_monitor_stream_for_source (dialog, stream);
1805+ test_it += 1;
1806+ //}
1807+ bar_set_stream (dialog, dialog->priv->input_bar, stream);
1808+ // remove any previous stream that might have been pointed at
1809+ // the static input bar and connect new signals from new stream.
1810+
1811+ const GList* profiles = gvc_mixer_ui_device_get_profiles (active_input);
1812+
1813+ if (profiles != NULL && !gvc_mixer_ui_device_should_profiles_be_hidden (active_input)){
1814+ const gchar *active_profile;
1815+ dialog->priv->input_profile_combo = gvc_combo_box_new (_("Mode:"));
1816+ gvc_combo_box_set_profiles (GVC_COMBO_BOX (dialog->priv->input_profile_combo),
1817+ profiles);
1818+
1819+ active_profile = gvc_mixer_ui_device_get_active_profile (active_input);
1820+ if (active_profile)
1821+ gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->input_profile_combo), active_profile);
1822+
1823+ g_object_set_data (G_OBJECT (dialog->priv->input_profile_combo),
1824+ "uidevice",
1825+ active_input);
1826+
1827+ g_signal_connect (G_OBJECT (dialog->priv->input_profile_combo), "changed",
1828+ G_CALLBACK (profile_selection_changed), dialog);
1829+
1830+ gtk_box_pack_start (GTK_BOX (dialog->priv->input_settings_box),
1831+ dialog->priv->input_profile_combo,
1832+ TRUE, FALSE, 0);
1833+
1834+ if (dialog->priv->size_group != NULL) {
1835+ gvc_combo_box_set_size_group (GVC_COMBO_BOX (dialog->priv->input_profile_combo),
1836+ dialog->priv->size_group, FALSE);
1837+ }
1838+ gtk_widget_show (dialog->priv->input_profile_combo);
1839+ }
1840+}
1841+
1842+/* active_output_update
1843+ * Handle output update change from the backend (control).
1844+ * Trust the backend whole heartedly to deliver the correct output
1845+ * i.e. keep it MVC.
1846+ */
1847+static void
1848+active_output_update (GvcMixerDialog *dialog,
1849+ GvcMixerUIDevice *active_output)
1850+{
1851+ // First make sure the correct UI device is selected.
1852+ GtkTreeModel *model;
1853+ GtkTreeIter iter;
1854+ g_debug ("\n\n active output update - device id = %i \n\n",
1855+ gvc_mixer_ui_device_get_id (active_output));
1856+
1857+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
1858+
1859+ if (gtk_tree_model_get_iter_first (model, &iter) == FALSE){
1860+ g_warning ("The tree is empty => we have no devices in the tree => cannot set the active output");
1861+ return;
1862+ }
1863+
1864+ do {
1865+ gboolean is_selected;
1866+ gint id;
1867+
1868+ gtk_tree_model_get (model, &iter,
1869+ ID_COLUMN, &id,
1870+ ACTIVE_COLUMN, &is_selected,
1871+ -1);
1872+
1873+ if (is_selected && id == gvc_mixer_ui_device_get_id (active_output)) {
1874+ g_debug ("\n\n unneccessary active output update unless it was a profile change on the same device ? \n\n");
1875+ }
1876+
1877+ is_selected = id == gvc_mixer_ui_device_get_id (active_output);
1878+
1879+ gtk_list_store_set (GTK_LIST_STORE (model),
1880+ &iter,
1881+ ACTIVE_COLUMN, is_selected,
1882+ -1);
1883+
1884+ if (is_selected) {
1885+ GtkTreeSelection *selection;
1886+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->output_treeview));
1887+ gtk_tree_selection_select_iter (selection, &iter);
1888+ }
1889+
1890+ }while (gtk_tree_model_iter_next (model, &iter));
1891+
1892+ // Not ideal but for now destroy the combo and recreate below.
1893+ if (dialog->priv->output_profile_combo != NULL) {
1894+ gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box),
1895+ dialog->priv->output_profile_combo);
1896+ dialog->priv->output_profile_combo = NULL;
1897+ }
1898+
1899+ GvcMixerStream *stream;
1900+ const GvcChannelMap *map;
1901+ GtkAdjustment *adj;
1902+
1903+ stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control,
1904+ active_output);
1905+
1906+ if (stream == NULL) {
1907+ g_warning ("active_output_update - couldn't find a stream from the supposed active output");
1908+ return;
1909+ }
1910+
1911+ gboolean is_muted = gvc_mixer_stream_get_is_muted (stream);
1912+ gtk_widget_set_sensitive (dialog->priv->applications_box,
1913+ !is_muted);
1914+ adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->output_bar)));
1915+ g_signal_handlers_disconnect_by_func(adj, on_adjustment_value_changed, dialog);
1916+
1917+ bar_set_stream (dialog, dialog->priv->output_bar, stream);
1918+ gvc_channel_bar_set_base_volume (GVC_CHANNEL_BAR (dialog->priv->output_bar),
1919+ gvc_mixer_stream_get_base_volume (stream));
1920+ gvc_channel_bar_set_is_amplified (GVC_CHANNEL_BAR (dialog->priv->output_bar),
1921+ gvc_mixer_stream_get_can_decibel (stream));
1922+ /* Update the adjustment in case the previous bar wasn't decibel
1923+ * capable, and we clipped it */
1924+ adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->output_bar)));
1925+ gtk_adjustment_set_value (adj,
1926+ gvc_mixer_stream_get_volume (stream));
1927+
1928+ map = gvc_mixer_stream_get_channel_map (stream);
1929+
1930+ if (map == NULL) {
1931+ g_warning ("Active output stream has no channel map");
1932+ gtk_widget_set_sensitive (dialog->priv->output_bar, FALSE);
1933+ gtk_widget_set_sensitive (dialog->priv->output_balance_bar, FALSE);
1934+ gtk_widget_set_sensitive (dialog->priv->output_lfe_bar, FALSE);
1935+ gtk_widget_set_sensitive (dialog->priv->output_fade_bar, FALSE);
1936+ return;
1937+ }
1938+
1939+
1940+ // Swap bars to the active map
1941+ gvc_balance_bar_set_map (GVC_BALANCE_BAR (dialog->priv->output_balance_bar),
1942+ map);
1943+ gvc_balance_bar_set_map (GVC_BALANCE_BAR (dialog->priv->output_fade_bar),
1944+ map);
1945+ gvc_balance_bar_set_map (GVC_BALANCE_BAR (dialog->priv->output_lfe_bar),
1946+ map);
1947+
1948+ // Set sensitivities accordingly.
1949+ gtk_widget_set_sensitive (dialog->priv->output_balance_bar,
1950+ gvc_channel_map_can_balance (map));
1951+ gtk_widget_set_sensitive (dialog->priv->output_fade_bar,
1952+ gvc_channel_map_can_fade (map));
1953+ gtk_widget_set_sensitive (dialog->priv->output_lfe_bar,
1954+ gvc_channel_map_has_lfe (map));
1955+ gtk_widget_set_sensitive (dialog->priv->output_bar,
1956+ TRUE);
1957+ // Set the label accordingly
1958+ gtk_label_set_label (GTK_LABEL(dialog->priv->selected_output_label),
1959+ g_strdup_printf(_("Settings for %s"),
1960+ gvc_mixer_ui_device_get_description (active_output)));
1961+ g_debug ("\n active_output_update %s \n", gvc_mixer_ui_device_get_description (active_output));
1962+
1963+ GList* profiles = gvc_mixer_ui_device_get_profiles (active_output);
1964+
1965+ if (profiles != NULL && !gvc_mixer_ui_device_should_profiles_be_hidden (active_output)) {
1966+ const gchar *active_profile;
1967+
1968+ dialog->priv->output_profile_combo = gvc_combo_box_new (_("Mode:"));
1969+ gvc_combo_box_set_profiles (GVC_COMBO_BOX (dialog->priv->output_profile_combo),
1970+ profiles);
1971+
1972+ gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box),
1973+ dialog->priv->output_profile_combo,
1974+ FALSE, FALSE, 3);
1975+
1976+ if (dialog->priv->size_group != NULL) {
1977+ gvc_combo_box_set_size_group (GVC_COMBO_BOX (dialog->priv->output_profile_combo),
1978+ dialog->priv->size_group, FALSE);
1979+ }
1980+
1981+ active_profile = gvc_mixer_ui_device_get_active_profile (active_output);
1982+ if (active_profile)
1983+ gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->output_profile_combo), active_profile);
1984+
1985+
1986+ g_object_set_data (G_OBJECT (dialog->priv->output_profile_combo),
1987+ "uidevice",
1988+ active_output);
1989+ g_signal_connect (G_OBJECT (dialog->priv->output_profile_combo), "changed",
1990+ G_CALLBACK (profile_selection_changed), dialog);
1991+
1992+ gtk_widget_show (dialog->priv->output_profile_combo);
1993+ }
1994+
1995+}
1996+
1997+static void
1998+bar_set_stream (GvcMixerDialog *dialog,
1999+ GtkWidget *bar,
2000+ GvcMixerStream *stream)
2001+{
2002+ GtkAdjustment *adj;
2003+
2004+ g_assert (bar != NULL);
2005+
2006+ gtk_widget_set_sensitive (bar, (stream != NULL));
2007+
2008+ adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
2009+
2010+ g_signal_handlers_disconnect_by_func (adj, on_adjustment_value_changed, dialog);
2011+
2012+ g_object_set_data (G_OBJECT (bar), "gvc-mixer-dialog-stream", stream);
2013+ g_object_set_data (G_OBJECT (adj), "gvc-mixer-dialog-stream", stream);
2014+ g_object_set_data (G_OBJECT (adj), "gvc-mixer-dialog-bar", bar);
2015+
2016+ if (stream != NULL) {
2017+ gboolean is_muted;
2018+
2019+ is_muted = gvc_mixer_stream_get_is_muted (stream);
2020+ gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar), is_muted);
2021+
2022+ gtk_adjustment_set_value (adj,
2023+ gvc_mixer_stream_get_volume (stream));
2024+ g_signal_connect (stream,
2025+ "notify::is-muted",
2026+ G_CALLBACK (on_stream_is_muted_notify),
2027+ dialog);
2028+ g_signal_connect (stream,
2029+ "notify::volume",
2030+ G_CALLBACK (on_stream_volume_notify),
2031+ dialog);
2032+ g_signal_connect (adj,
2033+ "value-changed",
2034+ G_CALLBACK (on_adjustment_value_changed),
2035+ dialog);
2036+ }
2037+}
2038+
2039+/**
2040+* This method handles all streams that are not an input or output
2041+* i.e. effects streams and application streams
2042+* TODO rename to truly reflect its usage.
2043+**/
2044+static void
2045+add_stream (GvcMixerDialog *dialog,
2046+ GvcMixerStream *stream)
2047+{
2048+
2049+ GtkWidget *bar;
2050+ bar = NULL;
2051+
2052+ if (stream == gvc_mixer_control_get_event_sink_input (dialog->priv->mixer_control)) {
2053+ bar = dialog->priv->effects_bar;
2054+ g_debug ("Adding effects stream");
2055+ } else {
2056+ // Must be a sink/source input/output
2057+ const char *name;
2058+ name = gvc_mixer_stream_get_name (stream);
2059+ g_debug ("\n Add bar for application stream : %s",
2060+ name);
2061+
2062+ bar = create_app_bar (dialog, name,
2063+ gvc_mixer_stream_get_icon_name (stream));
2064+
2065+ gtk_box_pack_start (GTK_BOX (dialog->priv->applications_box), bar, FALSE, FALSE, 12);
2066+ dialog->priv->num_apps++;
2067+ gtk_widget_hide (dialog->priv->no_apps_label);
2068+ }
2069+ // We should have a bar by now.
2070+ g_assert (bar != NULL);
2071+ GvcMixerStream *old_stream;
2072+
2073+ if (bar != NULL) {
2074+ old_stream = g_object_get_data (G_OBJECT (bar), "gvc-mixer-dialog-stream");
2075+ if (old_stream != NULL) {
2076+ char *name;
2077+ g_object_get (bar, "name", &name, NULL);
2078+ g_debug ("Disconnecting old stream '%s' from bar '%s'",
2079+ gvc_mixer_stream_get_name (old_stream), name);
2080+ g_free (name);
2081+
2082+ g_signal_handlers_disconnect_by_func (old_stream, on_stream_is_muted_notify, dialog);
2083+ g_signal_handlers_disconnect_by_func (old_stream, on_stream_volume_notify, dialog);
2084+ g_print ("\n in add stream \n");
2085+ g_hash_table_remove (dialog->priv->bars, GUINT_TO_POINTER (gvc_mixer_stream_get_id (old_stream)));
2086+ }
2087+ save_bar_for_stream (dialog, stream, bar);
2088+ bar_set_stream (dialog, bar, stream);
2089+ gtk_widget_show (bar);
2090+ }
2091+}
2092+
2093+static void
2094+remove_stream (GvcMixerDialog *dialog,
2095+ guint id)
2096+{
2097+ GtkWidget *bar;
2098+ bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (id));
2099+ if (bar != NULL) {
2100+ g_hash_table_remove (dialog->priv->bars, GUINT_TO_POINTER (id));
2101+ gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (bar)),
2102+ bar);
2103+ dialog->priv->num_apps--;
2104+ if (dialog->priv->num_apps == 0) {
2105+ gtk_widget_show (dialog->priv->no_apps_label);
2106+ }
2107+ }
2108+
2109+}
2110+
2111+static void
2112+on_control_stream_added (GvcMixerControl *control,
2113+ guint id,
2114+ GvcMixerDialog *dialog)
2115+{
2116+ GvcMixerStream *stream;
2117+ stream = gvc_mixer_control_lookup_stream_id (control, id);
2118+
2119+ if (stream == NULL)
2120+ return;
2121+
2122+ const char *app_id;
2123+ app_id = gvc_mixer_stream_get_application_id (stream);
2124+
2125+ if (stream == gvc_mixer_control_get_event_sink_input (dialog->priv->mixer_control) || (!GVC_IS_MIXER_SOURCE (stream) &&
2126+ !GVC_IS_MIXER_SINK (stream)
2127+ && !gvc_mixer_stream_is_virtual (stream)
2128+ && g_strcmp0 (app_id, "org.gnome.VolumeControl") != 0
2129+ && g_strcmp0 (app_id, "org.PulseAudio.pavucontrol") != 0)) {
2130+
2131+ GtkWidget *bar;
2132+
2133+ bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (id));
2134+ if (bar != NULL) {
2135+ g_debug ("GvcMixerDialog: Stream %u already added", id);
2136+ return;
2137+ }
2138+ add_stream (dialog, stream);
2139+ }
2140+}
2141+
2142+static void
2143+on_control_stream_removed (GvcMixerControl *control,
2144+ guint id,
2145+ GvcMixerDialog *dialog)
2146+{
2147+ remove_stream (dialog, id);
2148+}
2149+
2150+static gboolean
2151+find_item_by_id (GtkTreeModel *model,
2152+ guint id,
2153+ guint column,
2154+ GtkTreeIter *iter)
2155+{
2156+ gboolean found_item;
2157+
2158+ found_item = FALSE;
2159+
2160+ if (!gtk_tree_model_get_iter_first (model, iter)) {
2161+ return FALSE;
2162+ }
2163+
2164+ do {
2165+ guint t_id;
2166+
2167+ gtk_tree_model_get (model, iter,
2168+ column, &t_id, -1);
2169+
2170+ if (id == t_id) {
2171+ found_item = TRUE;
2172+ }
2173+ } while (!found_item && gtk_tree_model_iter_next (model, iter));
2174+
2175+ return found_item;
2176+}
2177+
2178+static void
2179+add_input_ui_entry (GvcMixerDialog *dialog,
2180+ GvcMixerUIDevice *input)
2181+{
2182+ g_debug ("\n Add input ui entry with id : %u \n",
2183+ gvc_mixer_ui_device_get_id (input));
2184+
2185+ gchar *port_name;
2186+ gchar *origin;
2187+ gchar *description;
2188+ gboolean active;
2189+ gboolean available;
2190+ gint stream_id;
2191+ GvcMixerCard *card;
2192+
2193+ g_object_get (G_OBJECT (input),
2194+ "stream-id", &stream_id,
2195+ "card", &card,
2196+ "origin", &origin,
2197+ "description", &description,
2198+ "port-name", &port_name,
2199+ "port-available", &available,
2200+ NULL);
2201+ GtkTreeModel *model;
2202+ GtkTreeIter iter;
2203+ const GvcChannelMap *map;
2204+ GIcon *icon;
2205+
2206+ if (card == NULL) {
2207+ GvcMixerStream *stream;
2208+ g_debug ("just detected a network source");
2209+ stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control, input);
2210+ if (stream == NULL) {
2211+ g_warning ("tried to add the network source but the stream was null - fail ?!");
2212+ g_free (port_name);
2213+ g_free (origin);
2214+ g_free (description);
2215+ return;
2216+ }
2217+ icon = gvc_mixer_stream_get_gicon (stream);
2218+ }
2219+ else
2220+ icon = gvc_mixer_card_get_gicon (card);
2221+
2222+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
2223+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
2224+
2225+ gtk_list_store_set (GTK_LIST_STORE (model),
2226+ &iter,
2227+ NAME_COLUMN, description,
2228+ DEVICE_COLUMN, origin,
2229+ ACTIVE_COLUMN, FALSE,
2230+ ICON_COLUMN, icon,
2231+ ID_COLUMN, gvc_mixer_ui_device_get_id (input),
2232+ SPEAKERS_COLUMN,origin,
2233+ -1);
2234+
2235+ if (icon != NULL)
2236+ g_object_unref (icon);
2237+
2238+ // TODO check this.
2239+ /*g_signal_connect (output,
2240+ "notify::description",
2241+ G_CALLBACK (on_output_description_notify),
2242+ dialog);*/
2243+
2244+ g_free (port_name);
2245+ g_free (origin);
2246+ g_free (description);
2247+}
2248+
2249+static void
2250+add_output_ui_entry (GvcMixerDialog *dialog,
2251+ GvcMixerUIDevice *output)
2252+{
2253+ g_debug ("\n Add output ui entry with id : %u \n",
2254+ gvc_mixer_ui_device_get_id (output));
2255+
2256+ gchar *sink_port_name;
2257+ gchar *origin;
2258+ gchar *description;
2259+ gboolean active;
2260+ gboolean available;
2261+ gint sink_stream_id;
2262+ GvcMixerCard *card;
2263+
2264+ g_object_get (G_OBJECT (output),
2265+ "stream-id", &sink_stream_id,
2266+ "card", &card,
2267+ "origin", &origin,
2268+ "description", &description,
2269+ "port-name", &sink_port_name,
2270+ "port-available", &available,
2271+ NULL);
2272+
2273+ GtkTreeModel *model;
2274+ GtkTreeIter iter;
2275+ const GvcChannelMap *map;
2276+ GIcon *icon;
2277+
2278+ if (card == NULL) {
2279+ g_debug ("just detected a network sink");
2280+
2281+ GvcMixerStream *stream;
2282+ stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control, output);
2283+ if (stream == NULL) {
2284+ g_warning ("tried to add the network sink but the stream was null - fail ?!");
2285+ g_free (sink_port_name);
2286+ g_free (origin);
2287+ g_free (description);
2288+ return;
2289+ }
2290+ icon = gvc_mixer_stream_get_gicon (stream);
2291+ }
2292+ else
2293+ icon = gvc_mixer_card_get_gicon (card);
2294+
2295+
2296+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
2297+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
2298+
2299+ gtk_list_store_set (GTK_LIST_STORE (model),
2300+ &iter,
2301+ NAME_COLUMN, description,
2302+ DEVICE_COLUMN, origin,
2303+ ACTIVE_COLUMN, FALSE,
2304+ ICON_COLUMN, icon,
2305+ ID_COLUMN, gvc_mixer_ui_device_get_id (output),
2306+ SPEAKERS_COLUMN,origin,
2307+ -1);
2308+
2309+ if (icon != NULL)
2310+ g_object_unref (icon);
2311+
2312+ // TODO check this.
2313+ /*g_signal_connect (output,
2314+ "notify::description",
2315+ G_CALLBACK (on_output_description_notify),
2316+ dialog);*/
2317+
2318+ g_free (sink_port_name);
2319+ g_free (origin);
2320+ g_free (description);
2321+}
2322+
2323+static void
2324+on_control_output_added (GvcMixerControl *control,
2325+ guint id,
2326+ GvcMixerDialog *dialog)
2327+{
2328+ GvcMixerUIDevice* out = NULL;
2329+ out = gvc_mixer_control_lookup_output_id (control, id);
2330+
2331+ if (out == NULL) {
2332+ g_warning ("on_control_output_added - tried to fetch an output of id %u but got nothing", id);
2333+ return;
2334+ }
2335+
2336+ add_output_ui_entry (dialog, out);
2337+}
2338+
2339+static void
2340+on_control_active_output_update (GvcMixerControl *control,
2341+ guint id,
2342+ GvcMixerDialog *dialog)
2343+{
2344+ GvcMixerUIDevice* out = NULL;
2345+ out = gvc_mixer_control_lookup_output_id (control, id);
2346+
2347+ if (out == NULL) {
2348+ g_warning ("\n on_control_active_output_update - tried to fetch an output of id %u but got nothing", id);
2349+ return;
2350+ }
2351+ active_output_update (dialog, out);
2352+}
2353+
2354+static void
2355+on_control_active_input_update (GvcMixerControl *control,
2356+ guint id,
2357+ GvcMixerDialog *dialog)
2358+{
2359+ GvcMixerUIDevice* in = NULL;
2360+ in = gvc_mixer_control_lookup_input_id (control, id);
2361+
2362+ if (in == NULL) {
2363+ g_warning ("on_control_active_input_update - tried to fetch an input of id %u but got nothing", id);
2364+ return;
2365+ }
2366+ active_input_update (dialog, in);
2367+}
2368+
2369+static void
2370+on_control_input_added (GvcMixerControl *control,
2371+ guint id,
2372+ GvcMixerDialog *dialog)
2373+{
2374+ GvcMixerUIDevice* in = NULL;
2375+ in = gvc_mixer_control_lookup_input_id (control, id);
2376+
2377+ if (in == NULL) {
2378+ g_warning ("on_control_input_added - tried to fetch an input of id %u but got nothing", id);
2379+ return;
2380+ }
2381+ add_input_ui_entry (dialog, in);
2382+}
2383+
2384+static void
2385+on_control_output_removed (GvcMixerControl *control,
2386+ guint id,
2387+ GvcMixerDialog *dialog)
2388+{
2389+ GtkWidget *bar;
2390+ gboolean found;
2391+ GtkTreeIter iter;
2392+ GtkTreeModel *model;
2393+
2394+ GvcMixerUIDevice* out = NULL;
2395+ out = gvc_mixer_control_lookup_output_id (control, id);
2396+
2397+ gint sink_stream_id;
2398+
2399+ g_object_get (G_OBJECT (out),
2400+ "stream-id", &sink_stream_id,
2401+ NULL);
2402+
2403+ g_debug ("Remove output from dialog \n id : %u \n sink stream id : %i \n",
2404+ id,
2405+ sink_stream_id);
2406+
2407+ /* remove from any models */
2408+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
2409+ found = find_item_by_id (GTK_TREE_MODEL (model), id, ID_COLUMN, &iter);
2410+ if (found) {
2411+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
2412+ }
2413+}
2414+
2415+
2416+
2417+static void
2418+on_control_input_removed (GvcMixerControl *control,
2419+ guint id,
2420+ GvcMixerDialog *dialog)
2421+{
2422+ GtkWidget *bar;
2423+ gboolean found;
2424+ GtkTreeIter iter;
2425+ GtkTreeModel *model;
2426+
2427+ GvcMixerUIDevice* in = NULL;
2428+ in = gvc_mixer_control_lookup_input_id (control, id);
2429+
2430+ gint stream_id;
2431+
2432+ g_object_get (G_OBJECT (in),
2433+ "stream-id", &stream_id,
2434+ NULL);
2435+
2436+ g_debug ("Remove input from dialog \n id : %u \n stream id : %i \n",
2437+ id,
2438+ stream_id);
2439+
2440+ /* remove from any models */
2441+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
2442+ found = find_item_by_id (GTK_TREE_MODEL (model), id, ID_COLUMN, &iter);
2443+ if (found) {
2444+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
2445+ }
2446+}
2447+
2448+static void
2449+_gtk_label_make_bold (GtkLabel *label)
2450+{
2451+ PangoFontDescription *font_desc;
2452+
2453+ font_desc = pango_font_description_new ();
2454+
2455+ pango_font_description_set_weight (font_desc,
2456+ PANGO_WEIGHT_BOLD);
2457+
2458+ /* This will only affect the weight of the font, the rest is
2459+ * from the current state of the widget, which comes from the
2460+ * theme or user prefs, since the font desc only has the
2461+ * weight flag turned on.
2462+ */
2463+ gtk_widget_modify_font (GTK_WIDGET (label), font_desc);
2464+
2465+ pango_font_description_free (font_desc);
2466+}
2467+
2468+
2469+static void
2470+on_input_selection_changed (GtkTreeSelection *selection,
2471+ GvcMixerDialog *dialog)
2472+{
2473+ GtkTreeModel *model;
2474+ GtkTreeIter iter;
2475+ gboolean toggled;
2476+ guint id;
2477+
2478+ if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) {
2479+ g_debug ("Could not get default input from selection");
2480+ return;
2481+ }
2482+
2483+ gtk_tree_model_get (model, &iter,
2484+ ID_COLUMN, &id,
2485+ ACTIVE_COLUMN, &toggled,
2486+ -1);
2487+
2488+ toggled ^= 1;
2489+ GvcMixerUIDevice *input;
2490+ //g_debug ("on_input_selection_changed - try swap to input with id %u", id);
2491+ input = gvc_mixer_control_lookup_input_id (dialog->priv->mixer_control, id);
2492+
2493+ if (input == NULL) {
2494+ g_warning ("on_input_selection_changed - Unable to find input with id: %u", id);
2495+ return;
2496+ }
2497+
2498+ gvc_mixer_control_change_input (dialog->priv->mixer_control, input);
2499+}
2500+
2501+static void
2502+on_output_selection_changed (GtkTreeSelection *selection,
2503+ GvcMixerDialog *dialog)
2504+{
2505+ GtkTreeModel *model;
2506+ GtkTreeIter iter;
2507+ gboolean active;
2508+ guint id;
2509+
2510+ if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) {
2511+ g_debug ("Could not get default output from selection");
2512+ return;
2513+ }
2514+
2515+ gtk_tree_model_get (model, &iter,
2516+ ID_COLUMN, &id,
2517+ ACTIVE_COLUMN, &active,
2518+ -1);
2519+
2520+ g_debug ("\n\n on_output_selection_changed - active %i \n\n", active);
2521+ if (active){
2522+ return;
2523+ }
2524+
2525+ GvcMixerUIDevice *output;
2526+ g_debug ("\n on_output_selection_changed - try swap to output with id %u", id);
2527+ output = gvc_mixer_control_lookup_output_id (dialog->priv->mixer_control, id);
2528+
2529+ if (output == NULL) {
2530+ g_warning ("on_output_selection_changed - Unable to find output with id: %u", id);
2531+ return;
2532+ }
2533+
2534+ gvc_mixer_control_change_output (dialog->priv->mixer_control, output);
2535+}
2536+
2537+static void
2538+name_to_text (GtkTreeViewColumn *column,
2539+ GtkCellRenderer *cell,
2540+ GtkTreeModel *model,
2541+ GtkTreeIter *iter,
2542+ gpointer user_data)
2543+{
2544+ char *name, *mapping;
2545+
2546+ gtk_tree_model_get(model, iter,
2547+ NAME_COLUMN, &name,
2548+ SPEAKERS_COLUMN, &mapping,
2549+ -1);
2550+
2551+ if (mapping == NULL) {
2552+ g_object_set (cell, "text", name, NULL);
2553+ } else {
2554+ char *str;
2555+
2556+ str = g_strdup_printf ("%s\n<i>%s</i>",
2557+ name, mapping);
2558+ g_object_set (cell, "markup", str, NULL);
2559+ g_free (str);
2560+ }
2561+
2562+ g_free (name);
2563+ g_free (mapping);
2564+}
2565+
2566+static GtkWidget *
2567+create_stream_treeview (GvcMixerDialog *dialog,
2568+ GCallback on_selection_changed)
2569+{
2570+ GtkWidget *treeview;
2571+ GtkListStore *store;
2572+ GtkCellRenderer *renderer;
2573+ GtkTreeViewColumn *column;
2574+ GtkTreeSelection *selection;
2575+
2576+ treeview = gtk_tree_view_new ();
2577+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
2578+
2579+ store = gtk_list_store_new (NUM_COLUMNS,
2580+ G_TYPE_STRING,
2581+ G_TYPE_STRING,
2582+ G_TYPE_BOOLEAN,
2583+ G_TYPE_UINT,
2584+ G_TYPE_STRING,
2585+ G_TYPE_ICON);
2586+ gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
2587+ GTK_TREE_MODEL (store));
2588+
2589+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
2590+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
2591+
2592+ column = gtk_tree_view_column_new ();
2593+ gtk_tree_view_column_set_title (column, _("Name"));
2594+ renderer = gtk_cell_renderer_pixbuf_new ();
2595+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
2596+ g_object_set (G_OBJECT (renderer), "stock-size", GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
2597+ gtk_tree_view_column_set_attributes (column, renderer,
2598+ "gicon", ICON_COLUMN,
2599+ NULL);
2600+
2601+ renderer = gtk_cell_renderer_text_new ();
2602+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
2603+ gtk_tree_view_column_set_cell_data_func (column, renderer,
2604+ name_to_text, NULL, NULL);
2605+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
2606+
2607+ g_signal_connect ( selection, "changed",
2608+ on_selection_changed, dialog);
2609+#if 0
2610+ renderer = gtk_cell_renderer_text_new ();
2611+ column = gtk_tree_view_column_new_with_attributes (_("Device"),
2612+ renderer,
2613+ "text", DEVICE_COLUMN,
2614+ NULL);
2615+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
2616+#endif
2617+ return treeview;
2618+}
2619+
2620+static void
2621+on_profile_changed (GvcComboBox *widget,
2622+ const char *profile,
2623+ gpointer user_data)
2624+{
2625+ GvcMixerCard *card;
2626+
2627+ card = g_object_get_data (G_OBJECT (widget), "card");
2628+ if (card == NULL) {
2629+ g_warning ("Could not find card for combobox");
2630+ return;
2631+ }
2632+
2633+ g_debug ("Profile changed to %s for card %s", profile,
2634+ gvc_mixer_card_get_name (card));
2635+
2636+ gvc_mixer_card_change_profile (card, profile);
2637+}
2638+
2639+static void
2640+on_test_speakers_clicked (GtkButton *widget,
2641+ gpointer user_data)
2642+{
2643+ GvcMixerDialog *dialog = GVC_MIXER_DIALOG (user_data);
2644+ GtkTreeModel *model;
2645+ GtkTreeIter iter;
2646+ gint active_output = GVC_MIXER_UI_DEVICE_INVALID;
2647+
2648+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
2649+
2650+ if (gtk_tree_model_get_iter_first (model, &iter) == FALSE){
2651+ g_warning ("The tree is empty => we have no device to test speakers with return");
2652+ return;
2653+ }
2654+
2655+ do {
2656+ gboolean is_selected = FALSE ;
2657+ gint id;
2658+
2659+ gtk_tree_model_get (model, &iter,
2660+ ID_COLUMN, &id,
2661+ ACTIVE_COLUMN, &is_selected,
2662+ -1);
2663+
2664+ if (is_selected) {
2665+ active_output = id;
2666+ break;
2667+ }
2668+
2669+ }while (gtk_tree_model_iter_next (model, &iter));
2670+
2671+ if (active_output == GVC_MIXER_UI_DEVICE_INVALID) {
2672+ g_warning ("Cant find the active output from the UI");
2673+ return;
2674+ }
2675+
2676+ GvcMixerUIDevice *output;
2677+ output = gvc_mixer_control_lookup_output_id (dialog->priv->mixer_control, (guint)active_output);
2678+ gint stream_id = gvc_mixer_ui_device_get_stream_id(output);
2679+
2680+ if (stream_id == GVC_MIXER_UI_DEVICE_INVALID)
2681+ return;
2682+
2683+ g_debug ("Test the speakers on the %s", gvc_mixer_ui_device_get_description (output));
2684+
2685+ GvcMixerStream *stream;
2686+ GvcMixerCardProfile *profile;
2687+ GtkWidget *d, *speaker_test, *container;
2688+ char *title;
2689+
2690+ stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, stream_id);
2691+ if (stream == NULL) {
2692+ g_debug ("Stream/sink not found");
2693+ return;
2694+ }
2695+ title = g_strdup_printf (_("Speaker Testing for %s"), gvc_mixer_ui_device_get_description (output));
2696+ d = gtk_dialog_new_with_buttons (title,
2697+ GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget))),
2698+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2699+ GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
2700+ NULL);
2701+ gtk_window_set_has_resize_grip (GTK_WINDOW (d), FALSE);
2702+
2703+ g_free (title);
2704+ speaker_test = gvc_speaker_test_new (dialog->priv->mixer_control,
2705+ stream);
2706+ gtk_widget_show (speaker_test);
2707+ container = gtk_dialog_get_content_area (GTK_DIALOG (d));
2708+ gtk_container_add (GTK_CONTAINER (container), speaker_test);
2709+
2710+ gtk_dialog_run (GTK_DIALOG (d));
2711+ gtk_widget_destroy (d);
2712+}
2713+
2714+static GObject *
2715+gvc_mixer_dialog_constructor (GType type,
2716+ guint n_construct_properties,
2717+ GObjectConstructParam *construct_params)
2718+{
2719+ GObject *object;
2720+ GvcMixerDialog *self;
2721+ GtkWidget *main_vbox;
2722+ GtkWidget *label;
2723+ GtkWidget *alignment;
2724+ GtkWidget *alignment_settings_box;
2725+ GtkWidget *settings_box;
2726+ GtkWidget *box;
2727+ GtkWidget *sbox;
2728+ GtkWidget *ebox;
2729+ GtkWidget *test_sound_box;
2730+ GSList *streams;
2731+ GSList *cards;
2732+ GSList *l;
2733+ GvcMixerStream *stream;
2734+ GvcMixerCard *card;
2735+ GtkTreeSelection *selection;
2736+
2737+ object = G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->constructor (type, n_construct_properties, construct_params);
2738+
2739+ self = GVC_MIXER_DIALOG (object);
2740+
2741+ main_vbox = GTK_WIDGET (self);
2742+ gtk_box_set_spacing (GTK_BOX (main_vbox), 2);
2743+
2744+ gtk_container_set_border_width (GTK_CONTAINER (self), 3);
2745+
2746+ self->priv->output_stream_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
2747+ alignment = gtk_alignment_new (0, 0, 1, 1);
2748+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 0, 0);
2749+ gtk_container_add (GTK_CONTAINER (alignment), self->priv->output_stream_box);
2750+ gtk_box_pack_start (GTK_BOX (main_vbox),
2751+ alignment,
2752+ FALSE, FALSE, 0);
2753+
2754+ self->priv->notebook = gtk_notebook_new ();
2755+ gtk_box_pack_start (GTK_BOX (main_vbox),
2756+ self->priv->notebook,
2757+ TRUE, TRUE, 0);
2758+ gtk_container_set_border_width (GTK_CONTAINER (self->priv->notebook), 5);
2759+
2760+ /* Output page */
2761+ self->priv->output_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
2762+ gtk_container_set_border_width (GTK_CONTAINER (self->priv->output_box), 12);
2763+ label = gtk_label_new (_("Output"));
2764+ gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
2765+ self->priv->output_box,
2766+ label);
2767+
2768+ box = gtk_frame_new (_("Play sound through"));
2769+ gtk_widget_set_size_request (GTK_WIDGET (box), 310, -1);
2770+ label = gtk_frame_get_label_widget (GTK_FRAME (box));
2771+ _gtk_label_make_bold (GTK_LABEL (label));
2772+ gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
2773+ gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
2774+ gtk_box_pack_start (GTK_BOX (self->priv->output_box), box, FALSE, TRUE, 0);
2775+
2776+ alignment = gtk_alignment_new (0, 0, 1, 1);
2777+ gtk_container_add (GTK_CONTAINER (box), alignment);
2778+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 10, 5, 0, 15);
2779+
2780+ self->priv->output_treeview = create_stream_treeview (self,
2781+ G_CALLBACK (on_output_selection_changed));
2782+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->output_treeview);
2783+
2784+ box = gtk_scrolled_window_new (NULL, NULL);
2785+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (box),
2786+ GTK_POLICY_NEVER,
2787+ GTK_POLICY_AUTOMATIC);
2788+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (box),
2789+ GTK_SHADOW_IN);
2790+ gtk_container_add (GTK_CONTAINER (box), self->priv->output_treeview);
2791+ gtk_container_add (GTK_CONTAINER (alignment), box);
2792+
2793+ self->priv->selected_output_label = gtk_label_new (_("Settings for the selected device"));
2794+ gtk_widget_set_halign (self->priv->selected_output_label, GTK_ALIGN_START);
2795+ gtk_widget_set_valign (self->priv->selected_output_label, GTK_ALIGN_START);
2796+ gtk_misc_set_padding (GTK_MISC (self->priv->selected_output_label), 0, 0);
2797+ _gtk_label_make_bold (GTK_LABEL (self->priv->selected_output_label));
2798+ settings_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
2799+ alignment_settings_box = gtk_alignment_new (0, 0, 1, 1);
2800+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment_settings_box), 7, 0, 0, 0);
2801+ self->priv->output_settings_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
2802+ gtk_container_add (GTK_CONTAINER (alignment_settings_box), self->priv->output_settings_box);
2803+
2804+ gtk_box_pack_start (GTK_BOX (self->priv->output_box),
2805+ settings_box,
2806+ FALSE,
2807+ FALSE,
2808+ 0);
2809+ gtk_box_pack_start (GTK_BOX (settings_box),
2810+ self->priv->selected_output_label,
2811+ FALSE,
2812+ FALSE,
2813+ 0);
2814+ gtk_box_pack_start (GTK_BOX (settings_box),
2815+ alignment_settings_box,
2816+ FALSE,
2817+ FALSE,
2818+ 0);
2819+
2820+ self->priv->output_balance_bar = gvc_balance_bar_new (BALANCE_TYPE_RL);
2821+ if (self->priv->size_group != NULL) {
2822+ gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (self->priv->output_balance_bar),
2823+ self->priv->size_group,
2824+ FALSE);
2825+ }
2826+ gtk_box_pack_start (GTK_BOX (self->priv->output_settings_box),
2827+ self->priv->output_balance_bar,
2828+ FALSE, FALSE, 3);
2829+ gtk_widget_show (self->priv->output_balance_bar);
2830+
2831+ self->priv->output_fade_bar = gvc_balance_bar_new (BALANCE_TYPE_FR);
2832+ if (self->priv->size_group != NULL) {
2833+ gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (self->priv->output_fade_bar),
2834+ self->priv->size_group,
2835+ FALSE);
2836+ }
2837+ gtk_box_pack_start (GTK_BOX (self->priv->output_settings_box),
2838+ self->priv->output_fade_bar,
2839+ FALSE, FALSE, 3);
2840+ gtk_widget_show (self->priv->output_fade_bar);
2841+
2842+ self->priv->output_lfe_bar = gvc_balance_bar_new (BALANCE_TYPE_LFE);
2843+ if (self->priv->size_group != NULL) {
2844+ gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (self->priv->output_lfe_bar),
2845+ self->priv->size_group,
2846+ FALSE);
2847+ }
2848+ gtk_box_pack_start (GTK_BOX (self->priv->output_settings_box),
2849+ self->priv->output_lfe_bar,
2850+ FALSE, FALSE, 3);
2851+ gtk_widget_show (self->priv->output_lfe_bar);
2852+
2853+ /* Creating a box and try to deal using the same size group. */
2854+ test_sound_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
2855+ gtk_box_pack_end (GTK_BOX (self->priv->output_settings_box),
2856+ test_sound_box,
2857+ FALSE,
2858+ FALSE,
2859+ 5);
2860+
2861+ sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
2862+ gtk_box_pack_start (GTK_BOX (test_sound_box),
2863+ sbox,
2864+ FALSE, FALSE, 0);
2865+
2866+ label = gtk_label_new (_("Test:"));
2867+ gtk_box_pack_start (GTK_BOX (sbox),
2868+ label,
2869+ FALSE, FALSE, 0);
2870+ if (self->priv->size_group != NULL)
2871+ gtk_size_group_add_widget (self->priv->size_group, sbox);
2872+
2873+ self->priv->test_output_button = gtk_button_new_with_label (_("Test Sound"));
2874+
2875+ /* FIXME: I am getting mental with all these hardcoded padding values,
2876+ * Here 8 works fine, not sure why. */
2877+ gtk_box_pack_start (GTK_BOX (test_sound_box),
2878+ self->priv->test_output_button,
2879+ TRUE, TRUE, 8);
2880+
2881+ /* Is this needed */
2882+ if (self->priv->size_group != NULL)
2883+ gtk_size_group_add_widget (self->priv->size_group, self->priv->test_output_button);
2884+
2885+ gtk_widget_show (test_sound_box);
2886+
2887+ //gtk_container_add (GTK_CONTAINER (box), self->priv->output_settings_box);
2888+ g_signal_connect (self->priv->test_output_button,
2889+ "released",
2890+ G_CALLBACK (on_test_speakers_clicked),
2891+ self);
2892+
2893+ /* Input page */
2894+ self->priv->input_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
2895+ gtk_container_set_border_width (GTK_CONTAINER (self->priv->input_box), 12);
2896+ label = gtk_label_new (_("Input"));
2897+ gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
2898+ self->priv->input_box,
2899+ label);
2900+ box = gtk_frame_new (_("Record sound from"));
2901+ gtk_widget_set_size_request (GTK_WIDGET (box), 310, -1);
2902+ label = gtk_frame_get_label_widget (GTK_FRAME (box));
2903+ _gtk_label_make_bold (GTK_LABEL (label));
2904+ gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
2905+ gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
2906+ gtk_box_pack_start (GTK_BOX (self->priv->input_box), box, FALSE, TRUE, 0);
2907+
2908+ alignment = gtk_alignment_new (0, 0, 1, 1);
2909+ gtk_container_add (GTK_CONTAINER (box), alignment);
2910+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 10, 5, 0, 15);
2911+
2912+ self->priv->input_treeview = create_stream_treeview (self,
2913+ G_CALLBACK (on_input_selection_changed));
2914+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->input_treeview);
2915+
2916+ box = gtk_scrolled_window_new (NULL, NULL);
2917+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (box),
2918+ GTK_POLICY_NEVER,
2919+ GTK_POLICY_AUTOMATIC);
2920+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (box),
2921+ GTK_SHADOW_IN);
2922+ gtk_container_add (GTK_CONTAINER (box), self->priv->input_treeview);
2923+ gtk_container_add (GTK_CONTAINER (alignment), box);
2924+
2925+ self->priv->selected_input_label = gtk_label_new (_("Settings for the selected device"));
2926+ gtk_widget_set_halign (self->priv->selected_input_label, GTK_ALIGN_START);
2927+ _gtk_label_make_bold (GTK_LABEL (self->priv->selected_input_label));
2928+
2929+ self->priv->input_settings_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
2930+ gtk_box_pack_start (GTK_BOX (self->priv->input_box),
2931+ self->priv->input_settings_box,
2932+ FALSE,
2933+ FALSE,
2934+ 0);
2935+ gtk_box_pack_start (GTK_BOX (self->priv->input_settings_box),
2936+ self->priv->selected_input_label,
2937+ FALSE,
2938+ FALSE,
2939+ 0);
2940+
2941+ self->priv->input_bar = create_bar (self, FALSE, TRUE);
2942+ gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->input_bar),
2943+ _("_Input volume:"));
2944+ gvc_channel_bar_set_low_icon_name (GVC_CHANNEL_BAR (self->priv->input_bar),
2945+ "audio-input-microphone-low-symbolic");
2946+ gvc_channel_bar_set_high_icon_name (GVC_CHANNEL_BAR (self->priv->input_bar),
2947+ "audio-input-microphone-high-symbolic");
2948+ gtk_widget_set_sensitive (self->priv->input_bar, FALSE);
2949+
2950+ if (self->priv->size_group != NULL) {
2951+ gvc_channel_bar_set_size_group (GVC_CHANNEL_BAR (self->priv->input_bar),
2952+ self->priv->size_group,
2953+ FALSE);
2954+ }
2955+
2956+ gtk_box_pack_start (GTK_BOX (self->priv->input_settings_box),
2957+ self->priv->input_bar,
2958+ FALSE, FALSE, 15);
2959+ gtk_widget_show (self->priv->input_bar);
2960+
2961+
2962+ /* Creating a box and try to deal using the same size group. */
2963+ GtkWidget *input_level_box;
2964+ input_level_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
2965+ gtk_box_pack_start (GTK_BOX (self->priv->input_settings_box),
2966+ input_level_box,
2967+ FALSE,
2968+ FALSE,
2969+ 5);
2970+
2971+ sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
2972+ gtk_box_pack_start (GTK_BOX (input_level_box),
2973+ sbox,
2974+ FALSE, FALSE, 0);
2975+
2976+ label = gtk_label_new (_("Input level:"));
2977+ gtk_box_pack_start (GTK_BOX (sbox),
2978+ label,
2979+ FALSE, FALSE, 0);
2980+ if (self->priv->size_group != NULL)
2981+ gtk_size_group_add_widget (self->priv->size_group, sbox);
2982+
2983+
2984+ self->priv->input_level_bar = gvc_level_bar_new ();
2985+ gvc_level_bar_set_orientation (GVC_LEVEL_BAR (self->priv->input_level_bar),
2986+ GTK_ORIENTATION_HORIZONTAL);
2987+ gvc_level_bar_set_scale (GVC_LEVEL_BAR (self->priv->input_level_bar),
2988+ GVC_LEVEL_SCALE_LINEAR);
2989+
2990+ gtk_box_pack_start (GTK_BOX (input_level_box),
2991+ self->priv->input_level_bar,
2992+ TRUE, TRUE, 0);
2993+
2994+ /* Effects page */
2995+ self->priv->sound_effects_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
2996+ gtk_container_set_border_width (GTK_CONTAINER (self->priv->sound_effects_box), 12);
2997+ label = gtk_label_new (_("Sound Effects"));
2998+ gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
2999+ self->priv->sound_effects_box,
3000+ label);
3001+
3002+ self->priv->effects_bar = create_bar (self, FALSE, TRUE);
3003+ gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->effects_bar),
3004+ _("_Alert volume:"));
3005+ gtk_widget_set_sensitive (self->priv->effects_bar, FALSE);
3006+ gtk_box_pack_start (GTK_BOX (self->priv->sound_effects_box),
3007+ self->priv->effects_bar, FALSE, FALSE, 0);
3008+
3009+ self->priv->sound_theme_chooser = gvc_sound_theme_chooser_new ();
3010+ gtk_box_pack_start (GTK_BOX (self->priv->sound_effects_box),
3011+ self->priv->sound_theme_chooser,
3012+ TRUE, TRUE, 6);
3013+
3014+ /* Applications */
3015+ self->priv->applications_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
3016+ gtk_container_set_border_width (GTK_CONTAINER (self->priv->applications_box), 12);
3017+ label = gtk_label_new (_("Applications"));
3018+ gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
3019+ self->priv->applications_box,
3020+ label);
3021+ self->priv->no_apps_label = gtk_label_new (_("No application is currently playing or recording audio."));
3022+ gtk_box_pack_start (GTK_BOX (self->priv->applications_box),
3023+ self->priv->no_apps_label,
3024+ TRUE, TRUE, 0);
3025+
3026+ self->priv->output_stream_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
3027+ alignment = gtk_alignment_new (0, 0, 1, 1);
3028+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 12, 0, 0, 0);
3029+ gtk_container_add (GTK_CONTAINER (alignment), self->priv->output_stream_box);
3030+ gtk_box_pack_start (GTK_BOX (main_vbox),
3031+ alignment,
3032+ FALSE, FALSE, 0);
3033+ // Output volume
3034+ self->priv->output_bar = create_bar (self, FALSE, TRUE);
3035+ gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->output_bar),
3036+ _("_Output volume:"));
3037+ gtk_widget_set_sensitive (self->priv->output_bar, FALSE);
3038+ gtk_widget_set_size_request (self->priv->output_bar, 460, -1);
3039+
3040+ gtk_box_pack_start (GTK_BOX (self->priv->output_stream_box),
3041+ self->priv->output_bar, TRUE, FALSE, 12);
3042+
3043+ gtk_widget_show_all (main_vbox);
3044+
3045+ g_signal_connect (self->priv->mixer_control,
3046+ "stream-added",
3047+ G_CALLBACK (on_control_stream_added),
3048+ self);
3049+ g_signal_connect (self->priv->mixer_control,
3050+ "stream-removed",
3051+ G_CALLBACK (on_control_stream_removed),
3052+ self);
3053+ g_signal_connect (self->priv->mixer_control,
3054+ "output-added",
3055+ G_CALLBACK (on_control_output_added),
3056+ self);
3057+ g_signal_connect (self->priv->mixer_control,
3058+ "output-removed",
3059+ G_CALLBACK (on_control_output_removed),
3060+ self);
3061+ g_signal_connect (self->priv->mixer_control,
3062+ "input-added",
3063+ G_CALLBACK (on_control_input_added),
3064+ self);
3065+ g_signal_connect (self->priv->mixer_control,
3066+ "input-removed",
3067+ G_CALLBACK (on_control_input_removed),
3068+ self);
3069+ return object;
3070+}
3071+
3072+static void
3073+gvc_mixer_dialog_dispose (GObject *object)
3074+{
3075+ GvcMixerDialog *dialog = GVC_MIXER_DIALOG (object);
3076+
3077+ g_clear_object (&dialog->priv->indicator_settings);
3078+
3079+ if (dialog->priv->mixer_control != NULL) {
3080+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
3081+ on_control_output_added,
3082+ dialog);
3083+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
3084+ on_control_output_removed,
3085+ dialog);
3086+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
3087+ on_control_active_input_update,
3088+ dialog);
3089+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
3090+ on_control_active_output_update,
3091+ dialog);
3092+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
3093+ on_control_input_added,
3094+ dialog);
3095+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
3096+ on_control_input_removed,
3097+ dialog);
3098+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
3099+ on_control_stream_added,
3100+ dialog);
3101+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
3102+ on_control_stream_removed,
3103+ dialog);
3104+ g_object_unref (dialog->priv->mixer_control);
3105+ dialog->priv->mixer_control = NULL;
3106+ }
3107+
3108+ if (dialog->priv->bars != NULL) {
3109+ g_hash_table_destroy (dialog->priv->bars);
3110+ dialog->priv->bars = NULL;
3111+ }
3112+
3113+ G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->dispose (object);
3114+}
3115+
3116+static void
3117+gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass)
3118+{
3119+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
3120+
3121+ object_class->constructor = gvc_mixer_dialog_constructor;
3122+ object_class->dispose = gvc_mixer_dialog_dispose;
3123+ object_class->finalize = gvc_mixer_dialog_finalize;
3124+ object_class->set_property = gvc_mixer_dialog_set_property;
3125+ object_class->get_property = gvc_mixer_dialog_get_property;
3126+
3127+ g_object_class_install_property (object_class,
3128+ PROP_MIXER_CONTROL,
3129+ g_param_spec_object ("mixer-control",
3130+ "mixer control",
3131+ "mixer control",
3132+ GVC_TYPE_MIXER_CONTROL,
3133+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
3134+
3135+ g_type_class_add_private (klass, sizeof (GvcMixerDialogPrivate));
3136+}
3137+
3138+
3139+static void
3140+gvc_mixer_dialog_init (GvcMixerDialog *dialog)
3141+{
3142+ dialog->priv = GVC_MIXER_DIALOG_GET_PRIVATE (dialog);
3143+ dialog->priv->bars = g_hash_table_new (NULL, NULL);
3144+ dialog->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
3145+}
3146+
3147+static void
3148+gvc_mixer_dialog_finalize (GObject *object)
3149+{
3150+ GvcMixerDialog *mixer_dialog;
3151+
3152+ g_return_if_fail (object != NULL);
3153+ g_return_if_fail (GVC_IS_MIXER_DIALOG (object));
3154+
3155+ mixer_dialog = GVC_MIXER_DIALOG (object);
3156+
3157+ g_return_if_fail (mixer_dialog->priv != NULL);
3158+ G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->finalize (object);
3159+}
3160+
3161+GvcMixerDialog *
3162+gvc_mixer_dialog_new (GvcMixerControl *control)
3163+{
3164+ GObject *dialog;
3165+ dialog = g_object_new (GVC_TYPE_MIXER_DIALOG,
3166+ "mixer-control", control,
3167+ NULL);
3168+ return GVC_MIXER_DIALOG (dialog);
3169+}
3170+
3171+enum {
3172+ PAGE_OUTPUT,
3173+ PAGE_INPUT,
3174+ PAGE_EVENTS,
3175+ PAGE_APPLICATIONS
3176+};
3177+
3178+gboolean
3179+gvc_mixer_dialog_set_page (GvcMixerDialog *self,
3180+ const char *page)
3181+{
3182+ guint num;
3183+
3184+ g_return_val_if_fail (self != NULL, FALSE);
3185+
3186+ num = PAGE_OUTPUT;
3187+
3188+ if (g_str_equal (page, "effects"))
3189+ num = PAGE_EVENTS;
3190+ else if (g_str_equal (page, "input"))
3191+ num = PAGE_INPUT;
3192+ else if (g_str_equal (page, "output"))
3193+ num = PAGE_OUTPUT;
3194+ else if (g_str_equal (page, "applications"))
3195+ num = PAGE_APPLICATIONS;
3196+
3197+ gtk_notebook_set_current_page (GTK_NOTEBOOK (self->priv->notebook), num);
3198+
3199+ return TRUE;
3200+}
3201Index: gnome-control-center-3.6.2/panels/sound-nua/gvc-mixer-dialog.h
3202===================================================================
3203--- /dev/null 1970-01-01 00:00:00.000000000 +0000
3204+++ gnome-control-center-3.6.2/panels/sound-nua/gvc-mixer-dialog.h 2012-11-13 16:25:40.893717986 +0100
3205@@ -0,0 +1,56 @@
3206+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3207+ *
3208+ * Copyright (C) 2008 Red Hat, Inc.
3209+ *
3210+ * This program is free software; you can redistribute it and/or modify
3211+ * it under the terms of the GNU General Public License as published by
3212+ * the Free Software Foundation; either version 2 of the License, or
3213+ * (at your option) any later version.
3214+ *
3215+ * This program is distributed in the hope that it will be useful,
3216+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3217+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3218+ * GNU General Public License for more details.
3219+ *
3220+ * You should have received a copy of the GNU General Public License
3221+ * along with this program; if not, write to the Free Software
3222+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3223+ *
3224+ */
3225+
3226+#ifndef __GVC_MIXER_DIALOG_H
3227+#define __GVC_MIXER_DIALOG_H
3228+
3229+#include <glib-object.h>
3230+#include "gvc-mixer-control.h"
3231+
3232+G_BEGIN_DECLS
3233+
3234+#define GVC_TYPE_MIXER_DIALOG (gvc_mixer_dialog_get_type ())
3235+#define GVC_MIXER_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_DIALOG, GvcMixerDialog))
3236+#define GVC_MIXER_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_DIALOG, GvcMixerDialogClass))
3237+#define GVC_IS_MIXER_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_DIALOG))
3238+#define GVC_IS_MIXER_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_DIALOG))
3239+#define GVC_MIXER_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_DIALOG, GvcMixerDialogClass))
3240+
3241+typedef struct GvcMixerDialogPrivate GvcMixerDialogPrivate;
3242+
3243+typedef struct
3244+{
3245+ GtkVBox parent;
3246+ GvcMixerDialogPrivate *priv;
3247+} GvcMixerDialog;
3248+
3249+typedef struct
3250+{
3251+ GtkVBoxClass parent_class;
3252+} GvcMixerDialogClass;
3253+
3254+GType gvc_mixer_dialog_get_type (void);
3255+
3256+GvcMixerDialog * gvc_mixer_dialog_new (GvcMixerControl *control);
3257+gboolean gvc_mixer_dialog_set_page (GvcMixerDialog *dialog, const gchar* page);
3258+
3259+G_END_DECLS
3260+
3261+#endif /* __GVC_MIXER_DIALOG_H */
3262Index: gnome-control-center-3.6.2/panels/sound/data/gnome-sound-panel.desktop.in.in
3263===================================================================
3264--- gnome-control-center-3.6.2.orig/panels/sound/data/gnome-sound-panel.desktop.in.in 2012-10-01 11:39:00.000000000 +0200
3265+++ gnome-control-center-3.6.2/panels/sound/data/gnome-sound-panel.desktop.in.in 2012-11-13 16:25:40.897717987 +0100
3266@@ -7,7 +7,7 @@
3267 Type=Application
3268 StartupNotify=true
3269 Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel;
3270-OnlyShowIn=GNOME;Unity;
3271+OnlyShowIn=GNOME;
3272 X-GNOME-Bugzilla-Bugzilla=GNOME
3273 X-GNOME-Bugzilla-Product=gnome-control-center
3274 X-GNOME-Bugzilla-Component=sound
3275Index: gnome-control-center-3.6.2/panels/universal-access/cc-ua-panel.c
3276===================================================================
3277--- gnome-control-center-3.6.2.orig/panels/universal-access/cc-ua-panel.c 2012-11-13 16:25:40.341717994 +0100
3278+++ gnome-control-center-3.6.2/panels/universal-access/cc-ua-panel.c 2012-11-13 16:25:40.897717987 +0100
3279@@ -492,7 +492,10 @@
3280 CcShell *shell;
3281
3282 shell = cc_panel_get_shell (CC_PANEL (panel));
3283- cc_shell_set_active_panel_from_id (shell, "sound", NULL, NULL);
3284+ if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity") == 0)
3285+ cc_shell_set_active_panel_from_id (shell, "sound-nua", NULL, NULL);
3286+ else
3287+ cc_shell_set_active_panel_from_id (shell, "sound", NULL, NULL);
3288
3289 return TRUE;
3290 }
3291Index: gnome-control-center-3.6.2/shell/gnome-control-center.c
3292===================================================================
3293--- gnome-control-center-3.6.2.orig/shell/gnome-control-center.c 2012-11-13 16:25:40.669717988 +0100
3294+++ gnome-control-center-3.6.2/shell/gnome-control-center.c 2012-11-13 16:25:40.897717987 +0100
3295@@ -984,6 +984,10 @@
3296
3297 g_clear_pointer (&priv->current_panel_id, g_free);
3298
3299+ if (!g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity") &&
3300+ !g_strcmp0(start_id, "sound"))
3301+ start_id = "sound-nua";
3302+
3303 /* clear any custom widgets */
3304 _shell_remove_all_custom_widgets (priv);
3305

Subscribers

People subscribed via source and target branches