~ubuntu-branches/ubuntu/utopic/gnome-control-center/utopic-proposed

« back to all changes in this revision

Viewing changes to debian/patches/96_sound_nua_panel.patch

  • Committer: Package Import Robot
  • Author(s): Sebastien Bacher, Sebastien Bacher, Robert Ancell, Iain Lane, Edward Donovan, Rico Tzschichholz, Jeremy Bicha, David Henningsson
  • Date: 2012-11-21 19:32:45 UTC
  • mfrom: (1.1.63)
  • Revision ID: package-import@ubuntu.com-20121121193245-mj61nzz1z4fk3z25
Tags: 1:3.6.3-0ubuntu1
[ Sebastien Bacher ]
* New upstream version
* debian/control.in: recommends libcanberra-pulse (lp: #1004973)
* debian/patches/58_ubuntu_icon_views_redesign.patch:
  - drop most of the changes, keep the different grid size though
    to fit on screen with our extra icons
* debian/patches/91_dont_show_in_unity.patch:
  - dropped, show the upstream printer panel and the layout tab
* debian/patches/revert_git_keyboard_gsettings.patch,
  debian/patches/revert_git_stop_using_gconf.patch:
  - dropped the gconf->gsettings reverts

[ Robert Ancell ]
* New upstream release (LP: #1010317)
* debian/control:
  - Bump build-depends on libgnome-desktop-3-dev, libwacom-dev
  - Add build-depends on libclutter-1.0-dev, libclutter-gtk-1.0-dev,
    libpwquality-dev
  - Drop build-depends on libgnomekbd-dev
* debian/patches/60_ubuntu_nav_bar.patch:
  - Disabled for now, doesn't apply
* debian/patches/revert_ua_gsettings.patch:
  - We can use GSettings for universal access now
* debian/patches/00git_online_accounts_gtkgrid.patch:
* debian/patches/00git_online_accounts_layout.part:
* debian/patches/git_wacom_translations.patch:
  - Applied upstream

[ Iain Lane ]
* Add Build-Depends on libxkbfile-dev
* New upstream release.
* Refresh all patches to apply cleanly.

[ Edward Donovan ]
* debian/source_gnome-control-center.py: Fix for Python 3. (LP: #1013171)

[ Rico Tzschichholz ]
* debian/control.in:
  - Build-depend on gtk-doc-tools instead of docbook directly
  - Bump minimum glib-2.0, gnome-desktop3, gnome-settings-daemon
     and gsettings-desktop-schemas

[ Jeremy Bicha ]
* Dropped more patches applied in new version:
  - git_unmute_sound_event.patch
  - git_fix_big_editable_labels.patch
  - 96_sound_nua_panel.patch
* debian/patches/04_new_appearance_settings.patch:
  - Dropped, this is now packaged separately as gnome-control-center-unity
* debian/patches/10_keyboard_layout_on_unity.patch:
  - Don't change the keyboard panel name when not running Unity
* debian/patches/52_ubuntu_language_list_mods.patch:
  - Don't disable adding current language to the list. While this
    fix shows the current language twice, at least it avoids the
    "Ubuntu suddenly in Chinese" bug (LP: #1035219)
* debian/patches/53_use_ubuntu_help.patch:
  - Only show Ubuntu help when running Unity
* debian/patches/58_hide_gdm_notifications.patch:
  - Hide "Show notifications when locked" settings when running Unity
    since it's a GNOME Shell-specific feature
* debian/patches/63_normal_scrollbar_in_a11y.patch:
  - Drop, overlay-scrollbars should handle this instead
* debian/patches/91_dont_show_in_unity.patch:
  - Hide Printers & Region panels in Unity until we're ready to switch
    to them.
* debian/patches/fix-crash-on-user-panel.patch:
  - Dropped, GNOME says it's obsolete
* debian/rules:
  - Build with -z,defs again
  - Explicitly disable ibus support since ibus 1.4 isn't supported in
    this version
* debian/control.in:
  - Drop ubuntu-docs and gnome-user-guide from recommends to suggests
  - Don't recommend indicators; let's leave that to Unity

[ David Henningsson ]
* sound_nua_panel.patch: Rebase to gnome 3.6 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Description: New design of the sound capplet
2
 
# r35 of the new soundnua vcs
3
 
# The new design has been discussed upstream and work is ongoing to send
4
 
# changes back to GNOME
5
 
=== modified file 'configure.ac'
6
 
Index: gnome-control-center-3.4.2/configure.ac
7
 
===================================================================
8
 
--- gnome-control-center-3.4.2.orig/configure.ac        2012-05-15 12:19:58.000000000 +0200
9
 
+++ gnome-control-center-3.4.2/configure.ac     2012-08-28 17:08:53.636517102 +0200
10
 
@@ -345,6 +346,9 @@
11
 
 panels/online-accounts/icons/32x32/Makefile
12
 
 panels/online-accounts/icons/48x48/Makefile
13
 
 panels/online-accounts/icons/256x256/Makefile
14
 
+panels/sound-nua/Makefile
15
 
+panels/sound-nua/data/Makefile
16
 
+panels/sound-nua/data/gnome-sound-nua-panel.desktop.in
17
 
 panels/sound/Makefile
18
 
 panels/sound/data/Makefile
19
 
 panels/sound/data/gnome-sound-panel.desktop.in
20
 
Index: gnome-control-center-3.4.2/panels/Makefile.am
21
 
===================================================================
22
 
--- gnome-control-center-3.4.2.orig/panels/Makefile.am  2012-03-05 15:04:55.000000000 +0100
23
 
+++ gnome-control-center-3.4.2/panels/Makefile.am       2012-08-28 17:08:49.404516897 +0200
24
 
@@ -10,6 +10,7 @@
25
 
        region \
26
 
        info \
27
 
        sound \
28
 
+       sound-nua \
29
 
        keyboard \
30
 
        universal-access \
31
 
        user-accounts \
32
 
Index: gnome-control-center-3.4.2/panels/sound-nua/Makefile.am
33
 
===================================================================
34
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
35
 
+++ gnome-control-center-3.4.2/panels/sound-nua/Makefile.am     2012-08-28 17:08:49.408516897 +0200
36
 
@@ -0,0 +1,93 @@
37
 
+SUBDIRS = data
38
 
+
39
 
+# This is used in PANEL_CFLAGS
40
 
+cappletname = sound
41
 
+NULL =
42
 
+
43
 
+ccpanelsdir = $(PANELS_DIR)
44
 
+ccpanels_LTLIBRARIES = libsoundnua.la
45
 
+
46
 
+AM_CPPFLAGS =                                  \
47
 
+       $(PANEL_CFLAGS)                         \
48
 
+       $(SOUND_PANEL_CFLAGS)                   \
49
 
+       -DLOCALE_DIR=\""$(datadir)/locale"\"    \
50
 
+       -DLIBEXECDIR=\"$(libexecdir)\"          \
51
 
+       -DGLADEDIR=\""$(pkgdatadir)"\"          \
52
 
+        -DSOUND_DATA_DIR="\"$(datadir)/sounds\""       \
53
 
+        -DSOUND_SET_DIR="\"$(pkgdatadir)/sounds\""     \
54
 
+       -DICON_DATA_DIR="\"$(pkgdatadir)/icons\"" \
55
 
+       $(NULL)
56
 
+
57
 
+noinst_LTLIBRARIES = libgnomevolumecontrol.la
58
 
+libgnomevolumecontrol_la_SOURCES =             \
59
 
+       gvc-mixer-card.h                        \
60
 
+       gvc-mixer-card.c                        \
61
 
+       gvc-mixer-card-private.h                \
62
 
+       gvc-mixer-stream.h                      \
63
 
+       gvc-mixer-stream.c                      \
64
 
+       gvc-mixer-stream-private.h              \
65
 
+       gvc-mixer-ui-device.h                   \
66
 
+       gvc-mixer-ui-device.c                   \
67
 
+       gvc-channel-map.h                       \
68
 
+       gvc-channel-map.c                       \
69
 
+       gvc-channel-map-private.h               \
70
 
+       gvc-mixer-sink.h                        \
71
 
+       gvc-mixer-sink.c                        \
72
 
+       gvc-mixer-source.h                      \
73
 
+       gvc-mixer-source.c                      \
74
 
+       gvc-mixer-sink-input.h                  \
75
 
+       gvc-mixer-sink-input.c                  \
76
 
+       gvc-mixer-source-output.h               \
77
 
+       gvc-mixer-source-output.c               \
78
 
+       gvc-mixer-event-role.h                  \
79
 
+       gvc-mixer-event-role.c                  \
80
 
+       gvc-mixer-control.h                     \
81
 
+       gvc-mixer-control.c                     \
82
 
+       gvc-mixer-control-private.h             \
83
 
+       gvc-channel-bar.h                       \
84
 
+       gvc-channel-bar.c                       \
85
 
+       gvc-pulseaudio-fake.h                   \
86
 
+       $(NULL)
87
 
+
88
 
+libsoundnua_la_LIBADD =                                \
89
 
+       -lm                                     \
90
 
+       libgnomevolumecontrol.la                \
91
 
+       $(PANEL_LIBS)                           \
92
 
+       $(SOUND_PANEL_LIBS)                     \
93
 
+       $(NULL)
94
 
+
95
 
+libsoundnua_la_LDFLAGS =                               \
96
 
+       $(PANEL_LDFLAGS)                        \
97
 
+       $(NULL)
98
 
+
99
 
+libsoundnua_la_SOURCES =                               \
100
 
+       gvc-balance-bar.h                       \
101
 
+       gvc-balance-bar.c                       \
102
 
+       gvc-mixer-dialog.h                      \
103
 
+       gvc-mixer-dialog.c                      \
104
 
+       gvc-level-bar.h                         \
105
 
+       gvc-level-bar.c                         \
106
 
+       gvc-combo-box.h                         \
107
 
+       gvc-combo-box.c                         \
108
 
+       gvc-speaker-test.h                      \
109
 
+       gvc-speaker-test.c                      \
110
 
+       gvc-sound-theme-chooser.c               \
111
 
+       gvc-sound-theme-chooser.h               \
112
 
+       sound-theme-file-utils.c                \
113
 
+       sound-theme-file-utils.h                \
114
 
+       cc-sound-panel.c                        \
115
 
+       cc-sound-panel.h                        \
116
 
+       $(NULL)
117
 
+
118
 
+BUILT_SOURCES =                                \
119
 
+       $(NULL)
120
 
+
121
 
+CLEANFILES =                           \
122
 
+       $(BUILT_SOURCES)                \
123
 
+       $(NULL)
124
 
+
125
 
+MAINTAINERCLEANFILES =                  \
126
 
+        *~                              \
127
 
+        Makefile.in
128
 
+
129
 
+-include $(top_srcdir)/git.mk
130
 
Index: gnome-control-center-3.4.2/panels/sound-nua/applet-main.c
131
 
===================================================================
132
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
133
 
+++ gnome-control-center-3.4.2/panels/sound-nua/applet-main.c   2012-08-28 17:08:49.412516897 +0200
134
 
@@ -0,0 +1,110 @@
135
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
136
 
+ *
137
 
+ * Copyright (C) 2008 Red Hat, Inc.
138
 
+ *
139
 
+ * This program is free software; you can redistribute it and/or
140
 
+ * modify it under the terms of the GNU General Public License as
141
 
+ * published by the Free Software Foundation; either version 2 of the
142
 
+ * License, or (at your option) any later version.
143
 
+ *
144
 
+ * This program is distributed in the hope that it will be useful, but
145
 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
146
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
147
 
+ * Lesser General Public License for more details.
148
 
+ *
149
 
+ * You should have received a copy of the GNU General Public License
150
 
+ * along with this program; if not, write to the Free Software
151
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
152
 
+ * 02111-1307, USA.
153
 
+ */
154
 
+
155
 
+#include "config.h"
156
 
+
157
 
+#include <libintl.h>
158
 
+#include <stdlib.h>
159
 
+#include <string.h>
160
 
+#include <unistd.h>
161
 
+#include <errno.h>
162
 
+
163
 
+#include <glib/gi18n.h>
164
 
+#include <glib.h>
165
 
+#include <gtk/gtk.h>
166
 
+#include <gio/gio.h>
167
 
+
168
 
+#include "gvc-applet.h"
169
 
+#include "gvc-log.h"
170
 
+
171
 
+#define GVCA_DBUS_NAME "org.gnome.VolumeControlApplet"
172
 
+
173
 
+static gboolean show_version = FALSE;
174
 
+static gboolean debug = FALSE;
175
 
+
176
 
+int
177
 
+main (int argc, char **argv)
178
 
+{
179
 
+        GError             *error;
180
 
+        GvcApplet          *applet;
181
 
+        GApplication       *app = NULL;
182
 
+        static GOptionEntry entries[] = {
183
 
+                { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, N_("Enable debugging code"), NULL },
184
 
+                { "version", 0, 0, G_OPTION_ARG_NONE, &show_version, N_("Version of this application"), NULL },
185
 
+                { NULL, 0, 0, 0, NULL, NULL, NULL }
186
 
+        };
187
 
+
188
 
+        bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
189
 
+        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
190
 
+        textdomain (GETTEXT_PACKAGE);
191
 
+
192
 
+        gvc_log_init ();
193
 
+
194
 
+        error = NULL;
195
 
+        gtk_init_with_args (&argc, &argv,
196
 
+                            (char *) _(" — GNOME Volume Control Applet"),
197
 
+                            entries, GETTEXT_PACKAGE,
198
 
+                            &error);
199
 
+
200
 
+        if (error != NULL) {
201
 
+                g_warning ("%s", error->message);
202
 
+                exit (1);
203
 
+        }
204
 
+
205
 
+        if (show_version) {
206
 
+                g_print ("%s %s\n", argv [0], VERSION);
207
 
+                exit (1);
208
 
+        }
209
 
+
210
 
+        gvc_log_set_debug (debug);
211
 
+
212
 
+        if (debug == FALSE) {
213
 
+                GError *error = NULL;
214
 
+
215
 
+                app = g_application_new (GVCA_DBUS_NAME,
216
 
+                                         G_APPLICATION_FLAGS_NONE);
217
 
+                if (!g_application_register (app, NULL, &error)) {
218
 
+                       g_warning ("%s", error->message);
219
 
+                       g_error_free (error);
220
 
+                       return 1;
221
 
+                }
222
 
+                if (g_application_get_is_remote (app)) {
223
 
+                        g_warning ("Applet is already running, exiting");
224
 
+                        return 0;
225
 
+                }
226
 
+        }
227
 
+
228
 
+        gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
229
 
+                                           ICON_DATA_DIR);
230
 
+
231
 
+        applet = gvc_applet_new ();
232
 
+        gvc_applet_start (applet);
233
 
+
234
 
+        gtk_main ();
235
 
+
236
 
+        if (applet != NULL) {
237
 
+                g_object_unref (applet);
238
 
+        }
239
 
+        if (app != NULL) {
240
 
+                g_object_unref (app);
241
 
+        }
242
 
+
243
 
+        return 0;
244
 
+}
245
 
Index: gnome-control-center-3.4.2/panels/sound-nua/cc-sound-panel.c
246
 
===================================================================
247
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
248
 
+++ gnome-control-center-3.4.2/panels/sound-nua/cc-sound-panel.c        2012-08-28 17:08:49.412516897 +0200
249
 
@@ -0,0 +1,141 @@
250
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
251
 
+ *
252
 
+ * Copyright (C) 2008 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
 
+#include "config.h"
271
 
+
272
 
+#include <libintl.h>
273
 
+#include <stdlib.h>
274
 
+#include <string.h>
275
 
+#include <unistd.h>
276
 
+#include <errno.h>
277
 
+
278
 
+#include <glib/gi18n-lib.h>
279
 
+#include <glib.h>
280
 
+#include <gtk/gtk.h>
281
 
+#include <pulse/pulseaudio.h>
282
 
+
283
 
+#include "cc-sound-panel.h"
284
 
+#include "gvc-mixer-dialog.h"
285
 
+
286
 
+G_DEFINE_DYNAMIC_TYPE (CcSoundNuaPanel, cc_sound_panel, CC_TYPE_PANEL)
287
 
+
288
 
+enum {
289
 
+        PROP_0,
290
 
+        PROP_ARGV
291
 
+};
292
 
+
293
 
+static void cc_sound_panel_finalize (GObject *object);
294
 
+
295
 
+static void
296
 
+cc_sound_panel_set_property (GObject      *object,
297
 
+                             guint         property_id,
298
 
+                             const GValue *value,
299
 
+                             GParamSpec   *pspec)
300
 
+{
301
 
+        CcSoundNuaPanel *self = CC_SOUND_PANEL (object);
302
 
+
303
 
+        switch (property_id) {
304
 
+        case PROP_ARGV: {
305
 
+                gchar **args;
306
 
+
307
 
+                args = g_value_get_boxed (value);
308
 
+
309
 
+                if (args && args[0]) {
310
 
+                        gvc_mixer_dialog_set_page (self->dialog, args[0]);
311
 
+                }
312
 
+                break;
313
 
+        }
314
 
+        default:
315
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
316
 
+        }
317
 
+}
318
 
+
319
 
+static void
320
 
+cc_sound_panel_class_init (CcSoundNuaPanelClass *klass)
321
 
+{
322
 
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
323
 
+
324
 
+        object_class->finalize = cc_sound_panel_finalize;
325
 
+        object_class->set_property = cc_sound_panel_set_property;
326
 
+
327
 
+        g_object_class_override_property (object_class, PROP_ARGV, "argv");
328
 
+}
329
 
+
330
 
+static void
331
 
+cc_sound_panel_class_finalize (CcSoundNuaPanelClass *klass)
332
 
+{
333
 
+}
334
 
+
335
 
+static void
336
 
+cc_sound_panel_finalize (GObject *object)
337
 
+{
338
 
+        CcSoundNuaPanel *panel = CC_SOUND_PANEL (object);
339
 
+
340
 
+        if (panel->dialog != NULL)
341
 
+                panel->dialog = NULL;
342
 
+        if (panel->connecting_label != NULL)
343
 
+                panel->connecting_label = NULL;
344
 
+        if (panel->control != NULL) {
345
 
+                g_object_unref (panel->control);
346
 
+                panel->control = NULL;
347
 
+        }
348
 
+
349
 
+        G_OBJECT_CLASS (cc_sound_panel_parent_class)->finalize (object);
350
 
+}
351
 
+
352
 
+static void
353
 
+cc_sound_panel_init (CcSoundNuaPanel *self)
354
 
+{
355
 
+        gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
356
 
+                                           ICON_DATA_DIR);
357
 
+        gtk_window_set_default_icon_name ("multimedia-volume-control");
358
 
+
359
 
+        self->control = gvc_mixer_control_new ("GNOME Volume Control Dialog");
360
 
+        gvc_mixer_control_open (self->control);
361
 
+        self->dialog = gvc_mixer_dialog_new (self->control);
362
 
+        gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->dialog));
363
 
+        gtk_widget_show (GTK_WIDGET (self->dialog));
364
 
+}
365
 
+
366
 
+void
367
 
+cc_sound_panel_register (GIOModule *module)
368
 
+{
369
 
+        cc_sound_panel_register_type (G_TYPE_MODULE (module));
370
 
+        g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT,
371
 
+                                        CC_TYPE_SOUND_PANEL,
372
 
+                                        "sound-nua", 0);
373
 
+}
374
 
+
375
 
+/* GIO extension stuff */
376
 
+void
377
 
+g_io_module_load (GIOModule *module)
378
 
+{
379
 
+        bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
380
 
+        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
381
 
+
382
 
+        /* register the panel */
383
 
+        cc_sound_panel_register (module);
384
 
+}
385
 
+
386
 
+void
387
 
+g_io_module_unload (GIOModule *module)
388
 
+{
389
 
+}
390
 
+
391
 
Index: gnome-control-center-3.4.2/panels/sound-nua/cc-sound-panel.h
392
 
===================================================================
393
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
394
 
+++ gnome-control-center-3.4.2/panels/sound-nua/cc-sound-panel.h        2012-08-28 17:08:49.416516897 +0200
395
 
@@ -0,0 +1,60 @@
396
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
397
 
+ *
398
 
+ * Copyright (C) 2010 Red Hat, Inc.
399
 
+ *
400
 
+ * This program is free software; you can redistribute it and/or
401
 
+ * modify it under the terms of the GNU General Public License as
402
 
+ * published by the Free Software Foundation; either version 2 of the
403
 
+ * License, or (at your option) any later version.
404
 
+ *
405
 
+ * This program is distributed in the hope that it will be useful, but
406
 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
407
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
408
 
+ * Lesser General Public License for more details.
409
 
+ *
410
 
+ * You should have received a copy of the GNU General Public License
411
 
+ * along with this program; if not, write to the Free Software
412
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
413
 
+ * 02111-1307, USA.
414
 
+ */
415
 
+
416
 
+#ifndef _CC_SOUND_PANEL_H
417
 
+#define _CC_SOUND_PANEL_H
418
 
+
419
 
+#include <shell/cc-panel.h>
420
 
+#include "gvc-mixer-control.h"
421
 
+#include "gvc-mixer-dialog.h"
422
 
+
423
 
+G_BEGIN_DECLS
424
 
+
425
 
+#define CC_TYPE_SOUND_PANEL cc_sound_panel_get_type()
426
 
+#define CC_SOUND_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CC_TYPE_SOUND_PANEL, CcSoundNuaPanel))
427
 
+#define CC_SOUND_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CC_TYPE_SOUND_PANEL, CcSoundNuaPanelClass))
428
 
+#define CC_IS_SOUND_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CC_TYPE_SOUND_PANEL))
429
 
+#define CC_IS_SOUND_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CC_TYPE_SOUND_PANEL))
430
 
+#define CC_SOUND_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CC_TYPE_SOUND_PANEL, CcSoundNuaPanelClass))
431
 
+
432
 
+typedef struct _CcSoundNuaPanel CcSoundNuaPanel;
433
 
+typedef struct _CcSoundNuaPanelClass CcSoundNuaPanelClass;
434
 
+typedef struct _CcSoundNuaPanelPrivate CcSoundNuaPanelPrivate;
435
 
+
436
 
+struct _CcSoundNuaPanel {
437
 
+       CcPanel parent;
438
 
+
439
 
+       GvcMixerControl *control;
440
 
+       GvcMixerDialog  *dialog;
441
 
+       GtkWidget       *connecting_label;
442
 
+};
443
 
+
444
 
+struct _CcSoundNuaPanelClass {
445
 
+       CcPanelClass parent_class;
446
 
+};
447
 
+
448
 
+GType cc_sound_panel_get_type (void) G_GNUC_CONST;
449
 
+
450
 
+void  cc_sound_panel_register (GIOModule *module);
451
 
+
452
 
+G_END_DECLS
453
 
+
454
 
+#endif /* _CC_SOUND_PANEL_H */
455
 
+
456
 
Index: gnome-control-center-3.4.2/panels/sound-nua/data/Makefile.am
457
 
===================================================================
458
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
459
 
+++ gnome-control-center-3.4.2/panels/sound-nua/data/Makefile.am        2012-08-28 17:08:49.420516898 +0200
460
 
@@ -0,0 +1,17 @@
461
 
+NULL =
462
 
+
463
 
+@INTLTOOL_DESKTOP_RULE@
464
 
+
465
 
+appsdir = $(datadir)/applications
466
 
+apps_in_files = gnome-sound-nua-panel.desktop.in
467
 
+apps_DATA = $(apps_in_files:.desktop.in=.desktop)
468
 
+
469
 
+EXTRA_DIST =                                   \
470
 
+       gnome-sound-nua-panel.desktop.in.in             \
471
 
+       $(NULL)
472
 
+
473
 
+CLEANFILES =                                   \
474
 
+       gnome-sound-nua-panel.desktop           \
475
 
+       $(NULL)
476
 
+
477
 
+-include $(top_srcdir)/git.mk
478
 
Index: gnome-control-center-3.4.2/panels/sound-nua/data/gnome-sound-nua-panel.desktop.in.in
479
 
===================================================================
480
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
481
 
+++ gnome-control-center-3.4.2/panels/sound-nua/data/gnome-sound-nua-panel.desktop.in.in        2012-08-28 17:08:49.424516898 +0200
482
 
@@ -0,0 +1,17 @@
483
 
+[Desktop Entry]
484
 
+_Name=Sound
485
 
+_Comment=Change sound volume and sound events
486
 
+Exec=gnome-control-center sound-nua
487
 
+Icon=multimedia-volume-control
488
 
+Terminal=false
489
 
+Type=Application
490
 
+StartupNotify=true
491
 
+Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel;
492
 
+OnlyShowIn=Unity;
493
 
+X-GNOME-Bugzilla-Bugzilla=GNOME
494
 
+X-GNOME-Bugzilla-Product=gnome-control-center
495
 
+X-GNOME-Bugzilla-Component=sound
496
 
+X-GNOME-Bugzilla-Version=@VERSION@
497
 
+X-GNOME-Settings-Panel=sound-nua
498
 
+# Translators: those are keywords for the sound control-center panel
499
 
+_Keywords=Card;Microphone;Volume;Fade;Balance;Bluetooth;Headset;
500
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-applet.c
501
 
===================================================================
502
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
503
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-applet.c    2012-08-28 17:08:49.428516898 +0200
504
 
@@ -0,0 +1,305 @@
505
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
506
 
+ *
507
 
+ * Copyright (C) 2008 Red Hat, Inc.
508
 
+ *
509
 
+ * This program is free software; you can redistribute it and/or modify
510
 
+ * it under the terms of the GNU General Public License as published by
511
 
+ * the Free Software Foundation; either version 2 of the License, or
512
 
+ * (at your option) any later version.
513
 
+ *
514
 
+ * This program is distributed in the hope that it will be useful,
515
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
516
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
517
 
+ * GNU General Public License for more details.
518
 
+ *
519
 
+ * You should have received a copy of the GNU General Public License
520
 
+ * along with this program; if not, write to the Free Software
521
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
522
 
+ *
523
 
+ */
524
 
+
525
 
+#include "config.h"
526
 
+
527
 
+#include <stdlib.h>
528
 
+#include <stdio.h>
529
 
+#include <fcntl.h>
530
 
+#include <unistd.h>
531
 
+#include <string.h>
532
 
+#include <errno.h>
533
 
+
534
 
+#include <glib.h>
535
 
+#include <glib/gi18n.h>
536
 
+#include <gtk/gtk.h>
537
 
+#include <pulse/pulseaudio.h>
538
 
+
539
 
+#include "gvc-applet.h"
540
 
+#include "gvc-mixer-control.h"
541
 
+#include "gvc-stream-status-icon.h"
542
 
+
543
 
+#define GVC_APPLET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_APPLET, GvcAppletPrivate))
544
 
+
545
 
+#define SCALE_SIZE 128
546
 
+
547
 
+static const char *output_icon_names[] = {
548
 
+        "audio-volume-muted-symbolic",
549
 
+        "audio-volume-low-symbolic",
550
 
+        "audio-volume-medium-symbolic",
551
 
+        "audio-volume-high-symbolic",
552
 
+        NULL
553
 
+};
554
 
+
555
 
+static const char *input_icon_names[] = {
556
 
+        "audio-input-microphone-muted-symbolic",
557
 
+        "audio-input-microphone-low-symbolic",
558
 
+        "audio-input-microphone-medium-symbolic",
559
 
+        "audio-input-microphone-high-symbolic",
560
 
+        NULL
561
 
+};
562
 
+
563
 
+struct GvcAppletPrivate
564
 
+{
565
 
+        GvcStreamStatusIcon *input_status_icon;
566
 
+        GvcStreamStatusIcon *output_status_icon;
567
 
+        GvcMixerControl     *control;
568
 
+};
569
 
+
570
 
+static void     gvc_applet_class_init (GvcAppletClass *klass);
571
 
+static void     gvc_applet_init       (GvcApplet      *applet);
572
 
+static void     gvc_applet_finalize   (GObject        *object);
573
 
+
574
 
+G_DEFINE_TYPE (GvcApplet, gvc_applet, G_TYPE_OBJECT)
575
 
+
576
 
+static void
577
 
+maybe_show_status_icons (GvcApplet *applet)
578
 
+{
579
 
+        gboolean        show;
580
 
+        GvcMixerStream *stream;
581
 
+        GSList         *source_outputs, *l;
582
 
+
583
 
+        show = TRUE;
584
 
+        stream = gvc_mixer_control_get_default_sink (applet->priv->control);
585
 
+        if (stream == NULL) {
586
 
+                show = FALSE;
587
 
+        }
588
 
+        gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->output_status_icon), show);
589
 
+
590
 
+
591
 
+        show = FALSE;
592
 
+        stream = gvc_mixer_control_get_default_source (applet->priv->control);
593
 
+        source_outputs = gvc_mixer_control_get_source_outputs (applet->priv->control);
594
 
+        if (stream != NULL && source_outputs != NULL) {
595
 
+                /* Check that we're not trying to add the peak detector
596
 
+                 * as an application doing recording */
597
 
+                for (l = source_outputs ; l ; l = l->next) {
598
 
+                        GvcMixerStream *s = l->data;
599
 
+                        const char *id;
600
 
+
601
 
+                        id = gvc_mixer_stream_get_application_id (s);
602
 
+                        if (id == NULL) {
603
 
+                                show = TRUE;
604
 
+                                break;
605
 
+                        }
606
 
+
607
 
+                        if (!g_str_equal (id, "org.gnome.VolumeControl") &&
608
 
+                            !g_str_equal (id, "org.PulseAudio.pavucontrol")) {
609
 
+                                show = TRUE;
610
 
+                                break;
611
 
+                        }
612
 
+                }
613
 
+        }
614
 
+        gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->input_status_icon), show);
615
 
+
616
 
+        g_slist_free (source_outputs);
617
 
+}
618
 
+
619
 
+void
620
 
+gvc_applet_start (GvcApplet *applet)
621
 
+{
622
 
+        g_return_if_fail (GVC_IS_APPLET (applet));
623
 
+
624
 
+        maybe_show_status_icons (applet);
625
 
+}
626
 
+
627
 
+static void
628
 
+gvc_applet_dispose (GObject *object)
629
 
+{
630
 
+        GvcApplet *applet = GVC_APPLET (object);
631
 
+
632
 
+        if (applet->priv->control != NULL) {
633
 
+                g_object_unref (applet->priv->control);
634
 
+                applet->priv->control = NULL;
635
 
+        }
636
 
+
637
 
+        G_OBJECT_CLASS (gvc_applet_parent_class)->dispose (object);
638
 
+}
639
 
+
640
 
+static void
641
 
+update_default_source (GvcApplet *applet)
642
 
+{
643
 
+        GvcMixerStream *stream;
644
 
+
645
 
+        stream = gvc_mixer_control_get_default_source (applet->priv->control);
646
 
+        if (stream != NULL) {
647
 
+                gvc_stream_status_icon_set_mixer_stream (applet->priv->input_status_icon,
648
 
+                                                         stream);
649
 
+                maybe_show_status_icons(applet);
650
 
+        } else {
651
 
+                g_debug ("Unable to get default source, or no source available");
652
 
+        }
653
 
+}
654
 
+
655
 
+static void
656
 
+update_default_sink (GvcApplet *applet)
657
 
+{
658
 
+        GvcMixerStream *stream;
659
 
+
660
 
+        stream = gvc_mixer_control_get_default_sink (applet->priv->control);
661
 
+        if (stream != NULL) {
662
 
+                gvc_stream_status_icon_set_mixer_stream (applet->priv->output_status_icon,
663
 
+                                                         stream);
664
 
+                maybe_show_status_icons(applet);
665
 
+        } else {
666
 
+                g_warning ("Unable to get default sink");
667
 
+        }
668
 
+}
669
 
+
670
 
+static void
671
 
+on_control_state_changed (GvcMixerControl      *control,
672
 
+                          GvcMixerControlState  new_state,
673
 
+                          GvcApplet            *applet)
674
 
+{
675
 
+        if (new_state == GVC_STATE_READY)  {
676
 
+                update_default_sink (applet);
677
 
+                update_default_source (applet);
678
 
+        } else if (new_state == GVC_STATE_CONNECTING) {
679
 
+                g_debug ("Connecting...");
680
 
+        }
681
 
+}
682
 
+
683
 
+static void
684
 
+on_control_default_sink_changed (GvcMixerControl *control,
685
 
+                                 guint            id,
686
 
+                                 GvcApplet       *applet)
687
 
+{
688
 
+        update_default_sink (applet);
689
 
+}
690
 
+
691
 
+static void
692
 
+on_control_default_source_changed (GvcMixerControl *control,
693
 
+                                   guint            id,
694
 
+                                   GvcApplet       *applet)
695
 
+{
696
 
+        update_default_source (applet);
697
 
+}
698
 
+
699
 
+static void
700
 
+on_control_stream_removed (GvcMixerControl *control,
701
 
+                           guint            id,
702
 
+                           GvcApplet       *applet)
703
 
+{
704
 
+        maybe_show_status_icons (applet);
705
 
+}
706
 
+
707
 
+static void
708
 
+on_control_stream_added (GvcMixerControl *control,
709
 
+                         guint            id,
710
 
+                         GvcApplet       *applet)
711
 
+{
712
 
+        maybe_show_status_icons (applet);
713
 
+}
714
 
+
715
 
+static GObject *
716
 
+gvc_applet_constructor (GType                  type,
717
 
+                        guint                  n_construct_properties,
718
 
+                        GObjectConstructParam *construct_params)
719
 
+{
720
 
+        GObject   *object;
721
 
+        GvcApplet *self;
722
 
+
723
 
+        object = G_OBJECT_CLASS (gvc_applet_parent_class)->constructor (type, n_construct_properties, construct_params);
724
 
+
725
 
+        self = GVC_APPLET (object);
726
 
+
727
 
+        self->priv->control = gvc_mixer_control_new ("GNOME Volume Control Applet");
728
 
+        g_signal_connect (self->priv->control,
729
 
+                          "state-changed",
730
 
+                          G_CALLBACK (on_control_state_changed),
731
 
+                          self);
732
 
+        g_signal_connect (self->priv->control,
733
 
+                          "default-sink-changed",
734
 
+                          G_CALLBACK (on_control_default_sink_changed),
735
 
+                          self);
736
 
+        g_signal_connect (self->priv->control,
737
 
+                          "default-source-changed",
738
 
+                          G_CALLBACK (on_control_default_source_changed),
739
 
+                          self);
740
 
+        g_signal_connect (self->priv->control,
741
 
+                          "stream-added",
742
 
+                          G_CALLBACK (on_control_stream_added),
743
 
+                          self);
744
 
+        g_signal_connect (self->priv->control,
745
 
+                          "stream-removed",
746
 
+                          G_CALLBACK (on_control_stream_removed),
747
 
+                          self);
748
 
+
749
 
+        gvc_mixer_control_open (self->priv->control);
750
 
+
751
 
+        return object;
752
 
+}
753
 
+
754
 
+static void
755
 
+gvc_applet_class_init (GvcAppletClass *klass)
756
 
+{
757
 
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
758
 
+
759
 
+        object_class->finalize = gvc_applet_finalize;
760
 
+        object_class->dispose = gvc_applet_dispose;
761
 
+        object_class->constructor = gvc_applet_constructor;
762
 
+
763
 
+        g_type_class_add_private (klass, sizeof (GvcAppletPrivate));
764
 
+}
765
 
+
766
 
+static void
767
 
+gvc_applet_init (GvcApplet *applet)
768
 
+{
769
 
+        applet->priv = GVC_APPLET_GET_PRIVATE (applet);
770
 
+
771
 
+        applet->priv->output_status_icon = gvc_stream_status_icon_new (NULL,
772
 
+                                                                       output_icon_names);
773
 
+        gvc_stream_status_icon_set_display_name (applet->priv->output_status_icon,
774
 
+                                                 _("Output"));
775
 
+        gtk_status_icon_set_title (GTK_STATUS_ICON (applet->priv->output_status_icon),
776
 
+                                   _("Sound Output Volume"));
777
 
+        applet->priv->input_status_icon = gvc_stream_status_icon_new (NULL,
778
 
+                                                                      input_icon_names);
779
 
+        gvc_stream_status_icon_set_display_name (applet->priv->input_status_icon,
780
 
+                                                 _("Input"));
781
 
+        gtk_status_icon_set_title (GTK_STATUS_ICON (applet->priv->input_status_icon),
782
 
+                                   _("Microphone Volume"));
783
 
+}
784
 
+
785
 
+static void
786
 
+gvc_applet_finalize (GObject *object)
787
 
+{
788
 
+        GvcApplet *applet;
789
 
+
790
 
+        g_return_if_fail (object != NULL);
791
 
+        g_return_if_fail (GVC_IS_APPLET (object));
792
 
+
793
 
+        applet = GVC_APPLET (object);
794
 
+
795
 
+        g_return_if_fail (applet->priv != NULL);
796
 
+
797
 
+
798
 
+        G_OBJECT_CLASS (gvc_applet_parent_class)->finalize (object);
799
 
+}
800
 
+
801
 
+GvcApplet *
802
 
+gvc_applet_new (void)
803
 
+{
804
 
+        GObject *applet;
805
 
+
806
 
+        applet = g_object_new (GVC_TYPE_APPLET, NULL);
807
 
+
808
 
+        return GVC_APPLET (applet);
809
 
+}
810
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-applet.h
811
 
===================================================================
812
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
813
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-applet.h    2012-08-28 17:08:49.428516898 +0200
814
 
@@ -0,0 +1,55 @@
815
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
816
 
+ *
817
 
+ * Copyright (C) 2008 Red Hat, Inc.
818
 
+ *
819
 
+ * This program is free software; you can redistribute it and/or modify
820
 
+ * it under the terms of the GNU General Public License as published by
821
 
+ * the Free Software Foundation; either version 2 of the License, or
822
 
+ * (at your option) any later version.
823
 
+ *
824
 
+ * This program is distributed in the hope that it will be useful,
825
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
826
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
827
 
+ * GNU General Public License for more details.
828
 
+ *
829
 
+ * You should have received a copy of the GNU General Public License
830
 
+ * along with this program; if not, write to the Free Software
831
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
832
 
+ *
833
 
+ */
834
 
+
835
 
+#ifndef __GVC_APPLET_H
836
 
+#define __GVC_APPLET_H
837
 
+
838
 
+#include <glib-object.h>
839
 
+
840
 
+G_BEGIN_DECLS
841
 
+
842
 
+#define GVC_TYPE_APPLET         (gvc_applet_get_type ())
843
 
+#define GVC_APPLET(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_APPLET, GvcApplet))
844
 
+#define GVC_APPLET_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_APPLET, GvcAppletClass))
845
 
+#define GVC_IS_APPLET(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_APPLET))
846
 
+#define GVC_IS_APPLET_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_APPLET))
847
 
+#define GVC_APPLET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_APPLET, GvcAppletClass))
848
 
+
849
 
+typedef struct GvcAppletPrivate GvcAppletPrivate;
850
 
+
851
 
+typedef struct
852
 
+{
853
 
+        GObject            parent;
854
 
+        GvcAppletPrivate *priv;
855
 
+} GvcApplet;
856
 
+
857
 
+typedef struct
858
 
+{
859
 
+        GObjectClass   parent_class;
860
 
+} GvcAppletClass;
861
 
+
862
 
+GType               gvc_applet_get_type            (void);
863
 
+
864
 
+GvcApplet *         gvc_applet_new                 (void);
865
 
+void                gvc_applet_start               (GvcApplet     *applet);
866
 
+
867
 
+G_END_DECLS
868
 
+
869
 
+#endif /* __GVC_APPLET_H */
870
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-balance-bar.c
871
 
===================================================================
872
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
873
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-balance-bar.c       2012-08-28 17:08:49.432516898 +0200
874
 
@@ -0,0 +1,575 @@
875
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
876
 
+ *
877
 
+ * Copyright (C) 2008 William Jon McCann
878
 
+ *
879
 
+ * This program is free software; you can redistribute it and/or modify
880
 
+ * it under the terms of the GNU General Public License as published by
881
 
+ * the Free Software Foundation; either version 2 of the License, or
882
 
+ * (at your option) any later version.
883
 
+ *
884
 
+ * This program is distributed in the hope that it will be useful,
885
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
886
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
887
 
+ * GNU General Public License for more details.
888
 
+ *
889
 
+ * You should have received a copy of the GNU General Public License
890
 
+ * along with this program; if not, write to the Free Software
891
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
892
 
+ *
893
 
+ */
894
 
+
895
 
+#include "config.h"
896
 
+
897
 
+#include <stdlib.h>
898
 
+#include <stdio.h>
899
 
+#include <unistd.h>
900
 
+
901
 
+#include <glib.h>
902
 
+#include <glib/gi18n-lib.h>
903
 
+#include <gtk/gtk.h>
904
 
+#include <canberra-gtk.h>
905
 
+#include <pulse/pulseaudio.h>
906
 
+
907
 
+#include "gvc-balance-bar.h"
908
 
+#include "gvc-channel-map-private.h"
909
 
+
910
 
+#define SCALE_SIZE 220
911
 
+#define ADJUSTMENT_MAX_NORMAL 65536.0 /* PA_VOLUME_NORM */
912
 
+
913
 
+#define GVC_BALANCE_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_BALANCE_BAR, GvcBalanceBarPrivate))
914
 
+
915
 
+struct GvcBalanceBarPrivate
916
 
+{
917
 
+        GvcChannelMap *channel_map;
918
 
+        GvcBalanceType btype;
919
 
+        GtkWidget     *scale_box;
920
 
+        GtkWidget     *start_box;
921
 
+        GtkWidget     *end_box;
922
 
+        GtkWidget     *label;
923
 
+        GtkWidget     *scale;
924
 
+        GtkAdjustment *adjustment;
925
 
+        GtkSizeGroup  *size_group;
926
 
+        gboolean       symmetric;
927
 
+        gboolean       click_lock;
928
 
+};
929
 
+
930
 
+enum
931
 
+{
932
 
+        PROP_0,
933
 
+        PROP_CHANNEL_MAP,
934
 
+        PROP_BALANCE_TYPE,
935
 
+};
936
 
+
937
 
+static void     gvc_balance_bar_class_init (GvcBalanceBarClass *klass);
938
 
+static void     gvc_balance_bar_init       (GvcBalanceBar      *balance_bar);
939
 
+static void     gvc_balance_bar_finalize   (GObject            *object);
940
 
+
941
 
+static gboolean on_scale_button_press_event   (GtkWidget      *widget,
942
 
+                                               GdkEventButton *event,
943
 
+                                               GvcBalanceBar  *bar);
944
 
+static gboolean on_scale_button_release_event (GtkWidget      *widget,
945
 
+                                               GdkEventButton *event,
946
 
+                                               GvcBalanceBar  *bar);
947
 
+static gboolean on_scale_scroll_event         (GtkWidget      *widget,
948
 
+                                               GdkEventScroll *event,
949
 
+                                               GvcBalanceBar  *bar);
950
 
+static void on_adjustment_value_changed       (GtkAdjustment *adjustment,
951
 
+                                               GvcBalanceBar *bar);
952
 
+
953
 
+G_DEFINE_TYPE (GvcBalanceBar, gvc_balance_bar, GTK_TYPE_HBOX)
954
 
+
955
 
+static GtkWidget *
956
 
+_scale_box_new (GvcBalanceBar *bar)
957
 
+{
958
 
+        GvcBalanceBarPrivate *priv = bar->priv;
959
 
+        GtkWidget            *box;
960
 
+        GtkWidget            *sbox;
961
 
+        GtkWidget            *ebox;
962
 
+        GtkAdjustment        *adjustment = bar->priv->adjustment;
963
 
+        char                 *str_lower, *str_upper;
964
 
+        gdouble              lower, upper;
965
 
+
966
 
+        bar->priv->scale_box = box = gtk_box_new (FALSE, 6);
967
 
+        priv->scale = gtk_hscale_new (priv->adjustment);
968
 
+        gtk_widget_set_size_request (priv->scale, SCALE_SIZE, -1);
969
 
+        gtk_scale_set_has_origin (GTK_SCALE (priv->scale), FALSE);
970
 
+        gtk_widget_set_name (priv->scale, "balance-bar-scale");
971
 
+        gtk_rc_parse_string ("style \"balance-bar-scale-style\" {\n"
972
 
+                             " GtkScale::trough-side-details = 0\n"
973
 
+                             "}\n"
974
 
+                             "widget \"*.balance-bar-scale\" style : rc \"balance-bar-scale-style\"\n");
975
 
+
976
 
+        bar->priv->start_box = sbox = gtk_box_new (FALSE, 6);
977
 
+        gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0);
978
 
+
979
 
+        gtk_box_pack_start (GTK_BOX (sbox), priv->label, FALSE, FALSE, 0);
980
 
+
981
 
+        gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, TRUE, 0);
982
 
+
983
 
+        switch (bar->priv->btype) {
984
 
+        case BALANCE_TYPE_RL:
985
 
+                str_lower = g_strdup_printf ("<small>%s</small>", C_("balance", "Left"));
986
 
+                str_upper = g_strdup_printf ("<small>%s</small>", C_("balance", "Right"));
987
 
+                break;
988
 
+        case BALANCE_TYPE_FR:
989
 
+                str_lower = g_strdup_printf ("<small>%s</small>", C_("balance", "Rear"));
990
 
+                str_upper = g_strdup_printf ("<small>%s</small>", C_("balance", "Front"));
991
 
+                break;
992
 
+        case BALANCE_TYPE_LFE:
993
 
+                str_lower = g_strdup_printf ("<small>%s</small>", C_("balance", "Minimum"));
994
 
+                str_upper = g_strdup_printf ("<small>%s</small>", C_("balance", "Maximum"));
995
 
+                break;
996
 
+        default:
997
 
+                g_assert_not_reached ();
998
 
+        }
999
 
+
1000
 
+        lower = gtk_adjustment_get_lower (adjustment);
1001
 
+        gtk_scale_add_mark (GTK_SCALE (priv->scale), lower,
1002
 
+                            GTK_POS_BOTTOM, str_lower);
1003
 
+        g_free (str_lower);
1004
 
+        upper = gtk_adjustment_get_upper (adjustment);
1005
 
+        gtk_scale_add_mark (GTK_SCALE (priv->scale), upper,
1006
 
+                            GTK_POS_BOTTOM, str_upper);
1007
 
+        g_free (str_upper);
1008
 
+
1009
 
+        if (bar->priv->btype != BALANCE_TYPE_LFE) {
1010
 
+                gtk_scale_add_mark (GTK_SCALE (priv->scale),
1011
 
+                                    (upper - lower)/2 + lower,
1012
 
+                                    GTK_POS_BOTTOM, NULL);
1013
 
+        }
1014
 
+
1015
 
+        bar->priv->end_box = ebox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1016
 
+        gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0);
1017
 
+
1018
 
+        ca_gtk_widget_disable_sounds (bar->priv->scale, FALSE);
1019
 
+        gtk_widget_add_events (bar->priv->scale, GDK_SCROLL_MASK);
1020
 
+
1021
 
+        g_signal_connect (G_OBJECT (bar->priv->scale), "button-press-event",
1022
 
+                          G_CALLBACK (on_scale_button_press_event), bar);
1023
 
+        g_signal_connect (G_OBJECT (bar->priv->scale), "button-release-event",
1024
 
+                          G_CALLBACK (on_scale_button_release_event), bar);
1025
 
+        g_signal_connect (G_OBJECT (bar->priv->scale), "scroll-event",
1026
 
+                          G_CALLBACK (on_scale_scroll_event), bar);
1027
 
+
1028
 
+        if (bar->priv->size_group != NULL) {
1029
 
+                gtk_size_group_add_widget (bar->priv->size_group, sbox);
1030
 
+
1031
 
+                if (bar->priv->symmetric) {
1032
 
+                        gtk_size_group_add_widget (bar->priv->size_group, ebox);
1033
 
+                }
1034
 
+        }
1035
 
+
1036
 
+        gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE);
1037
 
+
1038
 
+        return box;
1039
 
+}
1040
 
+
1041
 
+void
1042
 
+gvc_balance_bar_set_size_group (GvcBalanceBar *bar,
1043
 
+                                GtkSizeGroup  *group,
1044
 
+                                gboolean       symmetric)
1045
 
+{
1046
 
+        g_return_if_fail (GVC_IS_BALANCE_BAR (bar));
1047
 
+
1048
 
+        bar->priv->size_group = group;
1049
 
+        bar->priv->symmetric = symmetric;
1050
 
+
1051
 
+        if (bar->priv->size_group != NULL) {
1052
 
+                gtk_size_group_add_widget (bar->priv->size_group,
1053
 
+                                           bar->priv->start_box);
1054
 
+
1055
 
+                if (bar->priv->symmetric) {
1056
 
+                        gtk_size_group_add_widget (bar->priv->size_group,
1057
 
+                                                   bar->priv->end_box);
1058
 
+                }
1059
 
+        }
1060
 
+        gtk_widget_queue_draw (GTK_WIDGET (bar));
1061
 
+}
1062
 
+
1063
 
+static const char *
1064
 
+btype_to_string (guint btype)
1065
 
+{
1066
 
+        switch (btype) {
1067
 
+        case BALANCE_TYPE_RL:
1068
 
+                return "Balance";
1069
 
+        case BALANCE_TYPE_FR:
1070
 
+                return "Fade";
1071
 
+                break;
1072
 
+        case BALANCE_TYPE_LFE:
1073
 
+                return "LFE";
1074
 
+        default:
1075
 
+                g_assert_not_reached ();
1076
 
+        }
1077
 
+        return NULL;
1078
 
+}
1079
 
+
1080
 
+static void
1081
 
+update_level_from_map (GvcBalanceBar *bar,
1082
 
+                       GvcChannelMap *map)
1083
 
+{
1084
 
+        const gdouble *volumes;
1085
 
+        gdouble val;
1086
 
+
1087
 
+        g_debug ("Volume changed (for %s bar)", btype_to_string (bar->priv->btype));
1088
 
+
1089
 
+        volumes = gvc_channel_map_get_volume (map);
1090
 
+        switch (bar->priv->btype) {
1091
 
+        case BALANCE_TYPE_RL:
1092
 
+                val = volumes[BALANCE];
1093
 
+                break;
1094
 
+        case BALANCE_TYPE_FR:
1095
 
+                val = volumes[FADE];
1096
 
+                break;
1097
 
+        case BALANCE_TYPE_LFE:
1098
 
+                val = volumes[LFE];
1099
 
+                break;
1100
 
+        default:
1101
 
+                g_assert_not_reached ();
1102
 
+        }
1103
 
+
1104
 
+        gtk_adjustment_set_value (bar->priv->adjustment, val);
1105
 
+}
1106
 
+
1107
 
+static void
1108
 
+on_channel_map_volume_changed (GvcChannelMap  *map,
1109
 
+                               gboolean        set,
1110
 
+                               GvcBalanceBar  *bar)
1111
 
+{
1112
 
+        update_level_from_map (bar, map);
1113
 
+}
1114
 
+
1115
 
+static void
1116
 
+gvc_balance_bar_set_channel_map (GvcBalanceBar *bar,
1117
 
+                                 GvcChannelMap *map)
1118
 
+{
1119
 
+        g_return_if_fail (GVC_BALANCE_BAR (bar));
1120
 
+
1121
 
+        if (bar->priv->channel_map != NULL) {
1122
 
+                g_signal_handlers_disconnect_by_func (G_OBJECT (bar->priv->channel_map),
1123
 
+                                                      on_channel_map_volume_changed, bar);
1124
 
+                g_object_unref (bar->priv->channel_map);
1125
 
+        }
1126
 
+        bar->priv->channel_map = g_object_ref (map);
1127
 
+
1128
 
+        update_level_from_map (bar, map);
1129
 
+
1130
 
+        g_signal_connect (G_OBJECT (map), "volume-changed",
1131
 
+                          G_CALLBACK (on_channel_map_volume_changed), bar);
1132
 
+
1133
 
+        g_object_notify (G_OBJECT (bar), "channel-map");
1134
 
+}
1135
 
+
1136
 
+static void
1137
 
+gvc_balance_bar_set_balance_type (GvcBalanceBar *bar,
1138
 
+                                  GvcBalanceType btype)
1139
 
+{
1140
 
+        GtkWidget *frame;
1141
 
+
1142
 
+        g_return_if_fail (GVC_BALANCE_BAR (bar));
1143
 
+
1144
 
+        bar->priv->btype = btype;
1145
 
+        if (bar->priv->btype != BALANCE_TYPE_LFE) {
1146
 
+                bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
1147
 
+                                                                            -1.0,
1148
 
+                                                                            1.0,
1149
 
+                                                                            0.5,
1150
 
+                                                                            0.5,
1151
 
+                                                                            0.0));
1152
 
+        } else {
1153
 
+                bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
1154
 
+                                                                            0.0,
1155
 
+                                                                            ADJUSTMENT_MAX_NORMAL,
1156
 
+                                                                            ADJUSTMENT_MAX_NORMAL/100.0,
1157
 
+                                                                            ADJUSTMENT_MAX_NORMAL/10.0,
1158
 
+                                                                            0.0));
1159
 
+        }
1160
 
+
1161
 
+        g_object_ref_sink (bar->priv->adjustment);
1162
 
+        g_signal_connect (bar->priv->adjustment,
1163
 
+                          "value-changed",
1164
 
+                          G_CALLBACK (on_adjustment_value_changed),
1165
 
+                          bar);
1166
 
+
1167
 
+        switch (btype) {
1168
 
+        case BALANCE_TYPE_RL:
1169
 
+                bar->priv->label = gtk_label_new_with_mnemonic (_("_Balance:"));
1170
 
+                break;
1171
 
+        case BALANCE_TYPE_FR:
1172
 
+                bar->priv->label = gtk_label_new_with_mnemonic (_("_Fade:"));
1173
 
+                break;
1174
 
+        case BALANCE_TYPE_LFE:
1175
 
+                bar->priv->label = gtk_label_new_with_mnemonic (_("_Subwoofer:"));
1176
 
+                break;
1177
 
+        default:
1178
 
+                g_assert_not_reached ();
1179
 
+        }
1180
 
+        gtk_misc_set_alignment (GTK_MISC (bar->priv->label),
1181
 
+                                0.0,
1182
 
+                                0.0);
1183
 
+        /* frame */
1184
 
+        frame = gtk_frame_new (NULL);
1185
 
+        gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
1186
 
+        gtk_container_add (GTK_CONTAINER (bar), frame);
1187
 
+
1188
 
+        /* box with scale */
1189
 
+        bar->priv->scale_box = _scale_box_new (bar);
1190
 
+        gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box);
1191
 
+        gtk_widget_show_all (frame);
1192
 
+
1193
 
+        gtk_widget_set_direction (bar->priv->scale, GTK_TEXT_DIR_LTR);
1194
 
+        gtk_label_set_mnemonic_widget (GTK_LABEL (bar->priv->label),
1195
 
+                                       bar->priv->scale);
1196
 
+
1197
 
+        g_object_notify (G_OBJECT (bar), "balance-type");
1198
 
+}
1199
 
+
1200
 
+static void
1201
 
+gvc_balance_bar_set_property (GObject       *object,
1202
 
+                              guint          prop_id,
1203
 
+                              const GValue  *value,
1204
 
+                              GParamSpec    *pspec)
1205
 
+{
1206
 
+        GvcBalanceBar *self = GVC_BALANCE_BAR (object);
1207
 
+
1208
 
+        switch (prop_id) {
1209
 
+        case PROP_CHANNEL_MAP:
1210
 
+                gvc_balance_bar_set_channel_map (self, g_value_get_object (value));
1211
 
+                break;
1212
 
+        case PROP_BALANCE_TYPE:
1213
 
+                gvc_balance_bar_set_balance_type (self, g_value_get_int (value));
1214
 
+                break;
1215
 
+        default:
1216
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1217
 
+                break;
1218
 
+        }
1219
 
+}
1220
 
+
1221
 
+static void
1222
 
+gvc_balance_bar_get_property (GObject     *object,
1223
 
+                              guint        prop_id,
1224
 
+                              GValue      *value,
1225
 
+                              GParamSpec  *pspec)
1226
 
+{
1227
 
+        GvcBalanceBar *self = GVC_BALANCE_BAR (object);
1228
 
+
1229
 
+        switch (prop_id) {
1230
 
+        case PROP_CHANNEL_MAP:
1231
 
+                g_value_set_object (value, self->priv->channel_map);
1232
 
+                break;
1233
 
+        default:
1234
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1235
 
+                break;
1236
 
+        }
1237
 
+}
1238
 
+
1239
 
+static GObject *
1240
 
+gvc_balance_bar_constructor (GType                  type,
1241
 
+                             guint                  n_construct_properties,
1242
 
+                             GObjectConstructParam *construct_params)
1243
 
+{
1244
 
+        return G_OBJECT_CLASS (gvc_balance_bar_parent_class)->constructor (type, n_construct_properties, construct_params);
1245
 
+}
1246
 
+
1247
 
+static void
1248
 
+gvc_balance_bar_class_init (GvcBalanceBarClass *klass)
1249
 
+{
1250
 
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
1251
 
+
1252
 
+        object_class->constructor = gvc_balance_bar_constructor;
1253
 
+        object_class->finalize = gvc_balance_bar_finalize;
1254
 
+        object_class->set_property = gvc_balance_bar_set_property;
1255
 
+        object_class->get_property = gvc_balance_bar_get_property;
1256
 
+
1257
 
+        g_object_class_install_property (object_class,
1258
 
+                                         PROP_CHANNEL_MAP,
1259
 
+                                         g_param_spec_object ("channel-map",
1260
 
+                                                              "channel map",
1261
 
+                                                              "The channel map",
1262
 
+                                                              GVC_TYPE_CHANNEL_MAP,
1263
 
+                                                              G_PARAM_READWRITE));
1264
 
+        g_object_class_install_property (object_class,
1265
 
+                                         PROP_BALANCE_TYPE,
1266
 
+                                         g_param_spec_int ("balance-type",
1267
 
+                                                           "balance type",
1268
 
+                                                           "Whether the balance is right-left or front-rear",
1269
 
+                                                           BALANCE_TYPE_RL, NUM_BALANCE_TYPES - 1, BALANCE_TYPE_RL,
1270
 
+                                                           G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
1271
 
+
1272
 
+        g_type_class_add_private (klass, sizeof (GvcBalanceBarPrivate));
1273
 
+}
1274
 
+
1275
 
+
1276
 
+static gboolean
1277
 
+on_scale_button_press_event (GtkWidget      *widget,
1278
 
+                             GdkEventButton *event,
1279
 
+                             GvcBalanceBar  *bar)
1280
 
+{
1281
 
+        bar->priv->click_lock = TRUE;
1282
 
+
1283
 
+        return FALSE;
1284
 
+}
1285
 
+
1286
 
+static gboolean
1287
 
+on_scale_button_release_event (GtkWidget      *widget,
1288
 
+                               GdkEventButton *event,
1289
 
+                               GvcBalanceBar  *bar)
1290
 
+{
1291
 
+        bar->priv->click_lock = FALSE;
1292
 
+
1293
 
+        return FALSE;
1294
 
+}
1295
 
+
1296
 
+static gboolean
1297
 
+on_scale_scroll_event (GtkWidget      *widget,
1298
 
+                       GdkEventScroll *event,
1299
 
+                       GvcBalanceBar  *bar)
1300
 
+{
1301
 
+        gdouble value;
1302
 
+        gdouble dx, dy;
1303
 
+
1304
 
+        value = gtk_adjustment_get_value (bar->priv->adjustment);
1305
 
+
1306
 
+        if (!gdk_event_get_scroll_deltas ((GdkEvent*)event, &dx, &dy)) {
1307
 
+                dx = 0.0;
1308
 
+                dy = 0.0;
1309
 
+
1310
 
+                switch (event->direction) {
1311
 
+                case GDK_SCROLL_UP:
1312
 
+                case GDK_SCROLL_RIGHT:
1313
 
+                        dy = 1.0;
1314
 
+                        break;
1315
 
+                case GDK_SCROLL_DOWN:
1316
 
+                case GDK_SCROLL_LEFT:
1317
 
+                        dy = -1.0;
1318
 
+                        break;
1319
 
+                default:
1320
 
+                        ;
1321
 
+                }
1322
 
+        }
1323
 
+
1324
 
+        if (bar->priv->btype == BALANCE_TYPE_LFE) {
1325
 
+                if (dy > 0) {
1326
 
+                        if (value + dy * ADJUSTMENT_MAX_NORMAL/100.0 > ADJUSTMENT_MAX_NORMAL)
1327
 
+                                value = ADJUSTMENT_MAX_NORMAL;
1328
 
+                        else
1329
 
+                                value = value + dy * ADJUSTMENT_MAX_NORMAL/100.0;
1330
 
+                } else if (dy < 0) {
1331
 
+                        if (value + dy * ADJUSTMENT_MAX_NORMAL/100.0 < 0)
1332
 
+                                value = 0.0;
1333
 
+                        else
1334
 
+                                value = value + dy * ADJUSTMENT_MAX_NORMAL/100.0;
1335
 
+                }
1336
 
+        } else {
1337
 
+                if (dy > 0) {
1338
 
+                        if (value + dy * 0.01 > 1.0)
1339
 
+                                value = 1.0;
1340
 
+                        else
1341
 
+                                value = value + dy * 0.01;
1342
 
+                } else if (dy < 0) {
1343
 
+                        if (value + dy * 0.01 < -1.0)
1344
 
+                                value = -1.0;
1345
 
+                        else
1346
 
+                                value = value + dy * 0.01;
1347
 
+                }
1348
 
+        }
1349
 
+        gtk_adjustment_set_value (bar->priv->adjustment, value);
1350
 
+
1351
 
+        return TRUE;
1352
 
+}
1353
 
+
1354
 
+/* FIXME remove when we depend on a newer PA */
1355
 
+static pa_cvolume *
1356
 
+gvc_pa_cvolume_set_position (pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t, pa_volume_t v) {
1357
 
+        unsigned c;
1358
 
+        gboolean good = FALSE;
1359
 
+
1360
 
+        g_assert(cv);
1361
 
+        g_assert(map);
1362
 
+
1363
 
+        g_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), NULL);
1364
 
+        g_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, NULL);
1365
 
+
1366
 
+        for (c = 0; c < map->channels; c++)
1367
 
+                if (map->map[c] == t) {
1368
 
+                        cv->values[c] = v;
1369
 
+                        good = TRUE;
1370
 
+                }
1371
 
+
1372
 
+        return good ? cv : NULL;
1373
 
+}
1374
 
+
1375
 
+static void
1376
 
+on_adjustment_value_changed (GtkAdjustment *adjustment,
1377
 
+                             GvcBalanceBar *bar)
1378
 
+{
1379
 
+        gdouble                val;
1380
 
+        pa_cvolume             cv;
1381
 
+        const pa_channel_map  *pa_map;
1382
 
+
1383
 
+        if (bar->priv->channel_map == NULL)
1384
 
+                return;
1385
 
+
1386
 
+        cv = *gvc_channel_map_get_cvolume (bar->priv->channel_map);
1387
 
+        val = gtk_adjustment_get_value (adjustment);
1388
 
+
1389
 
+        pa_map = gvc_channel_map_get_pa_channel_map (bar->priv->channel_map);
1390
 
+
1391
 
+        switch (bar->priv->btype) {
1392
 
+        case BALANCE_TYPE_RL:
1393
 
+                pa_cvolume_set_balance (&cv, pa_map, val);
1394
 
+                break;
1395
 
+        case BALANCE_TYPE_FR:
1396
 
+                pa_cvolume_set_fade (&cv, pa_map, val);
1397
 
+                break;
1398
 
+        case BALANCE_TYPE_LFE:
1399
 
+                gvc_pa_cvolume_set_position (&cv, pa_map, PA_CHANNEL_POSITION_LFE, val);
1400
 
+                break;
1401
 
+        }
1402
 
+
1403
 
+        gvc_channel_map_volume_changed (bar->priv->channel_map, &cv, TRUE);
1404
 
+}
1405
 
+
1406
 
+static void
1407
 
+gvc_balance_bar_init (GvcBalanceBar *bar)
1408
 
+{
1409
 
+        bar->priv = GVC_BALANCE_BAR_GET_PRIVATE (bar);
1410
 
+}
1411
 
+
1412
 
+static void
1413
 
+gvc_balance_bar_finalize (GObject *object)
1414
 
+{
1415
 
+        GvcBalanceBar *bar;
1416
 
+
1417
 
+        g_return_if_fail (object != NULL);
1418
 
+        g_return_if_fail (GVC_IS_BALANCE_BAR (object));
1419
 
+
1420
 
+        bar = GVC_BALANCE_BAR (object);
1421
 
+
1422
 
+        g_return_if_fail (bar->priv != NULL);
1423
 
+
1424
 
+        if (bar->priv->channel_map != NULL) {
1425
 
+                g_signal_handlers_disconnect_by_func (G_OBJECT (bar->priv->channel_map),
1426
 
+                                                      on_channel_map_volume_changed, bar);
1427
 
+                g_object_unref (bar->priv->channel_map);
1428
 
+        }
1429
 
+
1430
 
+        G_OBJECT_CLASS (gvc_balance_bar_parent_class)->finalize (object);
1431
 
+}
1432
 
+
1433
 
+void
1434
 
+gvc_balance_bar_set_map (GvcBalanceBar* self,
1435
 
+                         const GvcChannelMap *channel_map)
1436
 
+{
1437
 
+        g_object_set (G_OBJECT (self),
1438
 
+                      "channel-map", channel_map, NULL);
1439
 
+}                                   
1440
 
+
1441
 
+GtkWidget *
1442
 
+gvc_balance_bar_new (GvcBalanceType btype)
1443
 
+{
1444
 
+        GObject *bar;
1445
 
+        bar = g_object_new (GVC_TYPE_BALANCE_BAR,
1446
 
+                            "balance-type", btype, NULL);
1447
 
+
1448
 
+        return GTK_WIDGET (bar);
1449
 
+}
1450
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-balance-bar.h
1451
 
===================================================================
1452
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
1453
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-balance-bar.h       2012-08-28 17:08:49.432516898 +0200
1454
 
@@ -0,0 +1,70 @@
1455
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
1456
 
+ *
1457
 
+ * Copyright (C) 2008 Red Hat, Inc.
1458
 
+ *
1459
 
+ * This program is free software; you can redistribute it and/or modify
1460
 
+ * it under the terms of the GNU General Public License as published by
1461
 
+ * the Free Software Foundation; either version 2 of the License, or
1462
 
+ * (at your option) any later version.
1463
 
+ *
1464
 
+ * This program is distributed in the hope that it will be useful,
1465
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1466
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1467
 
+ * GNU General Public License for more details.
1468
 
+ *
1469
 
+ * You should have received a copy of the GNU General Public License
1470
 
+ * along with this program; if not, write to the Free Software
1471
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1472
 
+ *
1473
 
+ */
1474
 
+
1475
 
+#ifndef __GVC_BALANCE_BAR_H
1476
 
+#define __GVC_BALANCE_BAR_H
1477
 
+
1478
 
+#include <glib-object.h>
1479
 
+
1480
 
+#include "gvc-channel-map.h"
1481
 
+
1482
 
+G_BEGIN_DECLS
1483
 
+
1484
 
+#define GVC_TYPE_BALANCE_BAR         (gvc_balance_bar_get_type ())
1485
 
+#define GVC_BALANCE_BAR(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_BALANCE_BAR, GvcBalanceBar))
1486
 
+#define GVC_BALANCE_BAR_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_BALANCE_BAR, GvcBalanceBarClass))
1487
 
+#define GVC_IS_BALANCE_BAR(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_BALANCE_BAR))
1488
 
+#define GVC_IS_BALANCE_BAR_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_BALANCE_BAR))
1489
 
+#define GVC_BALANCE_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_BALANCE_BAR, GvcBalanceBarClass))
1490
 
+
1491
 
+typedef enum {
1492
 
+        BALANCE_TYPE_RL,
1493
 
+        BALANCE_TYPE_FR,
1494
 
+        BALANCE_TYPE_LFE,
1495
 
+} GvcBalanceType;
1496
 
+
1497
 
+#define NUM_BALANCE_TYPES BALANCE_TYPE_LFE + 1
1498
 
+
1499
 
+typedef struct GvcBalanceBarPrivate GvcBalanceBarPrivate;
1500
 
+
1501
 
+typedef struct
1502
 
+{
1503
 
+        GtkHBox               parent;
1504
 
+        GvcBalanceBarPrivate *priv;
1505
 
+} GvcBalanceBar;
1506
 
+
1507
 
+typedef struct
1508
 
+{
1509
 
+        GtkHBoxClass          parent_class;
1510
 
+} GvcBalanceBarClass;
1511
 
+
1512
 
+GType               gvc_balance_bar_get_type            (void);
1513
 
+GtkWidget *         gvc_balance_bar_new                 (GvcBalanceType btype);
1514
 
+
1515
 
+void                gvc_balance_bar_set_size_group      (GvcBalanceBar *bar,
1516
 
+                                                         GtkSizeGroup  *group,
1517
 
+                                                         gboolean       symmetric);
1518
 
+
1519
 
+void                gvc_balance_bar_set_map (GvcBalanceBar *self,
1520
 
+                                             const GvcChannelMap *channel_map);
1521
 
+
1522
 
+G_END_DECLS
1523
 
+
1524
 
+#endif /* __GVC_BALANCE_BAR_H */
1525
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-channel-bar.c
1526
 
===================================================================
1527
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
1528
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-channel-bar.c       2012-08-28 17:08:49.436516898 +0200
1529
 
@@ -0,0 +1,973 @@
1530
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
1531
 
+ *
1532
 
+ * Copyright (C) 2008 William Jon McCann
1533
 
+ *
1534
 
+ * This program is free software; you can redistribute it and/or modify
1535
 
+ * it under the terms of the GNU General Public License as published by
1536
 
+ * the Free Software Foundation; either version 2 of the License, or
1537
 
+ * (at your option) any later version.
1538
 
+ *
1539
 
+ * This program is distributed in the hope that it will be useful,
1540
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1541
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1542
 
+ * GNU General Public License for more details.
1543
 
+ *
1544
 
+ * You should have received a copy of the GNU General Public License
1545
 
+ * along with this program; if not, write to the Free Software
1546
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1547
 
+ *
1548
 
+ */
1549
 
+
1550
 
+#include "config.h"
1551
 
+
1552
 
+#include <stdlib.h>
1553
 
+#include <stdio.h>
1554
 
+#include <unistd.h>
1555
 
+
1556
 
+#include <pulse/pulseaudio.h>
1557
 
+
1558
 
+#include <glib.h>
1559
 
+#include <glib/gi18n-lib.h>
1560
 
+#include <gtk/gtk.h>
1561
 
+#include <canberra-gtk.h>
1562
 
+
1563
 
+#include "gvc-channel-bar.h"
1564
 
+#include "gvc-mixer-control.h"
1565
 
+
1566
 
+#define SCALE_SIZE 128
1567
 
+#define ADJUSTMENT_MAX_NORMAL gvc_mixer_control_get_vol_max_norm(NULL)
1568
 
+#define ADJUSTMENT_MAX_AMPLIFIED gvc_mixer_control_get_vol_max_amplified(NULL)
1569
 
+#define ADJUSTMENT_MAX (bar->priv->is_amplified ? ADJUSTMENT_MAX_AMPLIFIED : ADJUSTMENT_MAX_NORMAL)
1570
 
+#define SCROLLSTEP (ADJUSTMENT_MAX / 100.0 * 5.0)
1571
 
+
1572
 
+#define GVC_CHANNEL_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_CHANNEL_BAR, GvcChannelBarPrivate))
1573
 
+
1574
 
+struct GvcChannelBarPrivate
1575
 
+{
1576
 
+        GtkOrientation orientation;
1577
 
+        GtkWidget     *scale_box;
1578
 
+        GtkWidget     *start_box;
1579
 
+        GtkWidget     *end_box;
1580
 
+        GtkWidget     *image;
1581
 
+        GtkWidget     *label;
1582
 
+        GtkWidget     *low_image;
1583
 
+        GtkWidget     *scale;
1584
 
+        GtkWidget     *high_image;
1585
 
+        GtkWidget     *mute_box;
1586
 
+        GtkWidget     *mute_button;
1587
 
+        GtkAdjustment *adjustment;
1588
 
+        GtkAdjustment *zero_adjustment;
1589
 
+        gboolean       show_mute;
1590
 
+        gboolean       is_muted;
1591
 
+        char          *name;
1592
 
+        char          *icon_name;
1593
 
+        char          *low_icon_name;
1594
 
+        char          *high_icon_name;
1595
 
+        GtkSizeGroup  *size_group;
1596
 
+        gboolean       symmetric;
1597
 
+        gboolean       click_lock;
1598
 
+        gboolean       is_amplified;
1599
 
+        guint32        base_volume;
1600
 
+};
1601
 
+
1602
 
+enum
1603
 
+{
1604
 
+        PROP_0,
1605
 
+        PROP_ORIENTATION,
1606
 
+        PROP_SHOW_MUTE,
1607
 
+        PROP_IS_MUTED,
1608
 
+        PROP_ADJUSTMENT,
1609
 
+        PROP_NAME,
1610
 
+        PROP_ICON_NAME,
1611
 
+        PROP_LOW_ICON_NAME,
1612
 
+        PROP_HIGH_ICON_NAME,
1613
 
+        PROP_IS_AMPLIFIED,
1614
 
+        PROP_ELLIPSIZE
1615
 
+};
1616
 
+
1617
 
+static void     gvc_channel_bar_class_init    (GvcChannelBarClass *klass);
1618
 
+static void     gvc_channel_bar_init          (GvcChannelBar      *channel_bar);
1619
 
+static void     gvc_channel_bar_finalize      (GObject            *object);
1620
 
+
1621
 
+static gboolean on_scale_button_press_event   (GtkWidget      *widget,
1622
 
+                                               GdkEventButton *event,
1623
 
+                                               GvcChannelBar  *bar);
1624
 
+static gboolean on_scale_button_release_event (GtkWidget      *widget,
1625
 
+                                               GdkEventButton *event,
1626
 
+                                               GvcChannelBar  *bar);
1627
 
+static gboolean on_scale_scroll_event         (GtkWidget      *widget,
1628
 
+                                               GdkEventScroll *event,
1629
 
+                                               GvcChannelBar  *bar);
1630
 
+
1631
 
+G_DEFINE_TYPE (GvcChannelBar, gvc_channel_bar, GTK_TYPE_HBOX)
1632
 
+
1633
 
+static GtkWidget *
1634
 
+_scale_box_new (GvcChannelBar *bar)
1635
 
+{
1636
 
+        GvcChannelBarPrivate *priv = bar->priv;
1637
 
+        GtkWidget            *box;
1638
 
+        GtkWidget            *sbox;
1639
 
+        GtkWidget            *ebox;
1640
 
+
1641
 
+        if (priv->orientation == GTK_ORIENTATION_VERTICAL) {
1642
 
+                bar->priv->scale_box = box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1643
 
+
1644
 
+                priv->scale = gtk_vscale_new (priv->adjustment);
1645
 
+
1646
 
+                gtk_widget_set_size_request (priv->scale, -1, SCALE_SIZE);
1647
 
+                gtk_range_set_inverted (GTK_RANGE (priv->scale), TRUE);
1648
 
+
1649
 
+                bar->priv->start_box = sbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1650
 
+                gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0);
1651
 
+
1652
 
+                gtk_box_pack_start (GTK_BOX (sbox), priv->image, FALSE, FALSE, 0);
1653
 
+                gtk_box_pack_start (GTK_BOX (sbox), priv->label, FALSE, FALSE, 0);
1654
 
+
1655
 
+                gtk_box_pack_start (GTK_BOX (sbox), priv->high_image, FALSE, FALSE, 0);
1656
 
+                gtk_widget_hide (priv->high_image);
1657
 
+                gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, TRUE, 0);
1658
 
+
1659
 
+                bar->priv->end_box = ebox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1660
 
+                gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0);
1661
 
+
1662
 
+                gtk_box_pack_start (GTK_BOX (ebox), priv->low_image, FALSE, FALSE, 0);
1663
 
+                gtk_widget_hide (priv->low_image);
1664
 
+
1665
 
+                gtk_box_pack_start (GTK_BOX (ebox), priv->mute_box, FALSE, FALSE, 0);
1666
 
+        } else {
1667
 
+                bar->priv->scale_box = box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1668
 
+                gtk_box_pack_start (GTK_BOX (box), priv->image, FALSE, FALSE, 0);
1669
 
+
1670
 
+                priv->scale = gtk_hscale_new (priv->adjustment);
1671
 
+
1672
 
+                gtk_widget_set_size_request (priv->scale, SCALE_SIZE, -1);
1673
 
+
1674
 
+                bar->priv->start_box = sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1675
 
+                gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0);
1676
 
+
1677
 
+                gtk_box_pack_end (GTK_BOX (sbox), priv->low_image, FALSE, FALSE, 0);
1678
 
+                gtk_widget_show (priv->low_image);
1679
 
+
1680
 
+                gtk_box_pack_start (GTK_BOX (sbox), priv->label, TRUE, TRUE, 0);
1681
 
+                gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, TRUE, 0);
1682
 
+
1683
 
+                bar->priv->end_box = ebox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1684
 
+                gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0);
1685
 
+
1686
 
+                gtk_box_pack_start (GTK_BOX (ebox), priv->high_image, FALSE, FALSE, 0);
1687
 
+                gtk_widget_show (priv->high_image);
1688
 
+                gtk_box_pack_start (GTK_BOX (ebox), priv->mute_box, FALSE, FALSE, 0);
1689
 
+        }
1690
 
+
1691
 
+        ca_gtk_widget_disable_sounds (bar->priv->scale, FALSE);
1692
 
+        gtk_widget_add_events (bar->priv->scale, GDK_SCROLL_MASK);
1693
 
+
1694
 
+        g_signal_connect (G_OBJECT (bar->priv->scale), "button-press-event",
1695
 
+                          G_CALLBACK (on_scale_button_press_event), bar);
1696
 
+        g_signal_connect (G_OBJECT (bar->priv->scale), "button-release-event",
1697
 
+                          G_CALLBACK (on_scale_button_release_event), bar);
1698
 
+        g_signal_connect (G_OBJECT (bar->priv->scale), "scroll-event",
1699
 
+                          G_CALLBACK (on_scale_scroll_event), bar);
1700
 
+
1701
 
+        if (bar->priv->size_group != NULL) {
1702
 
+                gtk_size_group_add_widget (bar->priv->size_group, sbox);
1703
 
+
1704
 
+                if (bar->priv->symmetric) {
1705
 
+                        gtk_size_group_add_widget (bar->priv->size_group, ebox);
1706
 
+                }
1707
 
+        }
1708
 
+
1709
 
+        gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE);
1710
 
+
1711
 
+        return box;
1712
 
+}
1713
 
+
1714
 
+static void
1715
 
+update_image (GvcChannelBar *bar)
1716
 
+{
1717
 
+        gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->image),
1718
 
+                                      bar->priv->icon_name,
1719
 
+                                      GTK_ICON_SIZE_DIALOG);
1720
 
+
1721
 
+        if (bar->priv->icon_name != NULL) {
1722
 
+                gtk_widget_show (bar->priv->image);
1723
 
+        } else {
1724
 
+                gtk_widget_hide (bar->priv->image);
1725
 
+        }
1726
 
+}
1727
 
+
1728
 
+static void
1729
 
+update_label (GvcChannelBar *bar)
1730
 
+{
1731
 
+        if (bar->priv->name != NULL) {
1732
 
+                gtk_label_set_text_with_mnemonic (GTK_LABEL (bar->priv->label),
1733
 
+                                                  bar->priv->name);
1734
 
+                gtk_label_set_mnemonic_widget (GTK_LABEL (bar->priv->label),
1735
 
+                                               bar->priv->scale);
1736
 
+                gtk_widget_show (bar->priv->label);
1737
 
+        } else {
1738
 
+                gtk_label_set_text (GTK_LABEL (bar->priv->label), NULL);
1739
 
+                gtk_widget_hide (bar->priv->label);
1740
 
+        }
1741
 
+}
1742
 
+
1743
 
+static void
1744
 
+update_layout (GvcChannelBar *bar)
1745
 
+{
1746
 
+        GtkWidget *box;
1747
 
+        GtkWidget *frame;
1748
 
+
1749
 
+        if (bar->priv->scale == NULL) {
1750
 
+                return;
1751
 
+        }
1752
 
+
1753
 
+        box = bar->priv->scale_box;
1754
 
+        frame = gtk_widget_get_parent (box);
1755
 
+
1756
 
+        g_object_ref (bar->priv->image);
1757
 
+        g_object_ref (bar->priv->label);
1758
 
+        g_object_ref (bar->priv->mute_box);
1759
 
+        g_object_ref (bar->priv->low_image);
1760
 
+        g_object_ref (bar->priv->high_image);
1761
 
+
1762
 
+        gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->image);
1763
 
+        gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->label);
1764
 
+        gtk_container_remove (GTK_CONTAINER (bar->priv->end_box), bar->priv->mute_box);
1765
 
+
1766
 
+        if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
1767
 
+                gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->low_image);
1768
 
+                gtk_container_remove (GTK_CONTAINER (bar->priv->end_box), bar->priv->high_image);
1769
 
+        } else {
1770
 
+                gtk_container_remove (GTK_CONTAINER (bar->priv->end_box), bar->priv->low_image);
1771
 
+                gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->high_image);
1772
 
+        }
1773
 
+
1774
 
+        gtk_container_remove (GTK_CONTAINER (box), bar->priv->start_box);
1775
 
+        gtk_container_remove (GTK_CONTAINER (box), bar->priv->scale);
1776
 
+        gtk_container_remove (GTK_CONTAINER (box), bar->priv->end_box);
1777
 
+        gtk_container_remove (GTK_CONTAINER (frame), box);
1778
 
+
1779
 
+        bar->priv->scale_box = _scale_box_new (bar);
1780
 
+        gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box);
1781
 
+
1782
 
+        g_object_unref (bar->priv->image);
1783
 
+        g_object_unref (bar->priv->label);
1784
 
+        g_object_unref (bar->priv->mute_box);
1785
 
+        g_object_unref (bar->priv->low_image);
1786
 
+        g_object_unref (bar->priv->high_image);
1787
 
+
1788
 
+        gtk_widget_show_all (frame);
1789
 
+}
1790
 
+
1791
 
+void
1792
 
+gvc_channel_bar_set_size_group (GvcChannelBar *bar,
1793
 
+                                GtkSizeGroup  *group,
1794
 
+                                gboolean       symmetric)
1795
 
+{
1796
 
+        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
1797
 
+
1798
 
+        bar->priv->size_group = group;
1799
 
+        bar->priv->symmetric = symmetric;
1800
 
+
1801
 
+        if (bar->priv->size_group != NULL) {
1802
 
+                gtk_size_group_add_widget (bar->priv->size_group,
1803
 
+                                           bar->priv->start_box);
1804
 
+
1805
 
+                if (bar->priv->symmetric) {
1806
 
+                        gtk_size_group_add_widget (bar->priv->size_group,
1807
 
+                                                   bar->priv->end_box);
1808
 
+                }
1809
 
+        }
1810
 
+        gtk_widget_queue_draw (GTK_WIDGET (bar));
1811
 
+}
1812
 
+
1813
 
+void
1814
 
+gvc_channel_bar_set_name (GvcChannelBar  *bar,
1815
 
+                          const char     *name)
1816
 
+{
1817
 
+        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
1818
 
+
1819
 
+        g_free (bar->priv->name);
1820
 
+        bar->priv->name = g_strdup (name);
1821
 
+        update_label (bar);
1822
 
+        g_object_notify (G_OBJECT (bar), "name");
1823
 
+}
1824
 
+
1825
 
+void
1826
 
+gvc_channel_bar_set_icon_name (GvcChannelBar  *bar,
1827
 
+                               const char     *name)
1828
 
+{
1829
 
+        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
1830
 
+
1831
 
+        g_free (bar->priv->icon_name);
1832
 
+        bar->priv->icon_name = g_strdup (name);
1833
 
+        update_image (bar);
1834
 
+        g_object_notify (G_OBJECT (bar), "icon-name");
1835
 
+}
1836
 
+
1837
 
+void
1838
 
+gvc_channel_bar_set_low_icon_name   (GvcChannelBar *bar,
1839
 
+                                     const char    *name)
1840
 
+{
1841
 
+        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
1842
 
+
1843
 
+        if (name != NULL && strcmp (bar->priv->low_icon_name, name) != 0) {
1844
 
+                g_free (bar->priv->low_icon_name);
1845
 
+                bar->priv->low_icon_name = g_strdup (name);
1846
 
+                gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->low_image),
1847
 
+                                              bar->priv->low_icon_name,
1848
 
+                                              GTK_ICON_SIZE_MENU);
1849
 
+                g_object_notify (G_OBJECT (bar), "low-icon-name");
1850
 
+        }
1851
 
+}
1852
 
+
1853
 
+void
1854
 
+gvc_channel_bar_set_high_icon_name  (GvcChannelBar *bar,
1855
 
+                                     const char    *name)
1856
 
+{
1857
 
+        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
1858
 
+
1859
 
+        if (name != NULL && strcmp (bar->priv->high_icon_name, name) != 0) {
1860
 
+                g_free (bar->priv->high_icon_name);
1861
 
+                bar->priv->high_icon_name = g_strdup (name);
1862
 
+                gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->high_image),
1863
 
+                                              bar->priv->high_icon_name,
1864
 
+                                              GTK_ICON_SIZE_MENU);
1865
 
+                g_object_notify (G_OBJECT (bar), "high-icon-name");
1866
 
+        }
1867
 
+}
1868
 
+
1869
 
+void
1870
 
+gvc_channel_bar_set_orientation (GvcChannelBar  *bar,
1871
 
+                                 GtkOrientation  orientation)
1872
 
+{
1873
 
+        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
1874
 
+
1875
 
+        if (orientation != bar->priv->orientation) {
1876
 
+                bar->priv->orientation = orientation;
1877
 
+                update_layout (bar);
1878
 
+                g_object_notify (G_OBJECT (bar), "orientation");
1879
 
+        }
1880
 
+}
1881
 
+
1882
 
+static void
1883
 
+gvc_channel_bar_set_adjustment (GvcChannelBar *bar,
1884
 
+                                GtkAdjustment *adjustment)
1885
 
+{
1886
 
+        g_return_if_fail (GVC_CHANNEL_BAR (bar));
1887
 
+        g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
1888
 
+
1889
 
+        if (bar->priv->adjustment != NULL) {
1890
 
+                g_object_unref (bar->priv->adjustment);
1891
 
+        }
1892
 
+        bar->priv->adjustment = g_object_ref_sink (adjustment);
1893
 
+
1894
 
+        if (bar->priv->scale != NULL) {
1895
 
+                gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale), adjustment);
1896
 
+        }
1897
 
+
1898
 
+        g_object_notify (G_OBJECT (bar), "adjustment");
1899
 
+}
1900
 
+
1901
 
+GtkAdjustment *
1902
 
+gvc_channel_bar_get_adjustment (GvcChannelBar *bar)
1903
 
+{
1904
 
+        g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), NULL);
1905
 
+
1906
 
+        return bar->priv->adjustment;
1907
 
+}
1908
 
+
1909
 
+static gboolean
1910
 
+on_scale_button_press_event (GtkWidget      *widget,
1911
 
+                             GdkEventButton *event,
1912
 
+                             GvcChannelBar  *bar)
1913
 
+{
1914
 
+        bar->priv->click_lock = TRUE;
1915
 
+
1916
 
+        return FALSE;
1917
 
+}
1918
 
+
1919
 
+static gboolean
1920
 
+on_scale_button_release_event (GtkWidget      *widget,
1921
 
+                               GdkEventButton *event,
1922
 
+                               GvcChannelBar  *bar)
1923
 
+{
1924
 
+        GtkAdjustment *adj;
1925
 
+        gdouble value;
1926
 
+
1927
 
+        bar->priv->click_lock = FALSE;
1928
 
+
1929
 
+        adj = gtk_range_get_adjustment (GTK_RANGE (widget));
1930
 
+
1931
 
+        value = gtk_adjustment_get_value (adj);
1932
 
+
1933
 
+        /* this means the adjustment moved away from zero and
1934
 
+         * therefore we should unmute and set the volume. */
1935
 
+        gvc_channel_bar_set_is_muted (bar, (value == 0.0));
1936
 
+
1937
 
+        /* Play a sound! */
1938
 
+        ca_gtk_play_for_widget (GTK_WIDGET (bar), 0,
1939
 
+                                CA_PROP_EVENT_ID, "audio-volume-change",
1940
 
+                                CA_PROP_EVENT_DESCRIPTION, "foobar event happened",
1941
 
+                                CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl",
1942
 
+                                NULL);
1943
 
+
1944
 
+        return FALSE;
1945
 
+}
1946
 
+
1947
 
+gboolean
1948
 
+gvc_channel_bar_scroll (GvcChannelBar *bar, GdkEventScroll *event)
1949
 
+{
1950
 
+        GtkAdjustment *adj;
1951
 
+        gdouble value;
1952
 
+        GdkScrollDirection direction;
1953
 
+        gdouble dx, dy;
1954
 
+
1955
 
+        g_return_val_if_fail (bar != NULL, FALSE);
1956
 
+        g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
1957
 
+
1958
 
+        direction = event->direction;
1959
 
+
1960
 
+        if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
1961
 
+                if (direction == GDK_SCROLL_LEFT || direction == GDK_SCROLL_RIGHT)
1962
 
+                        return FALSE;
1963
 
+        } else {
1964
 
+                /* Switch direction for RTL */
1965
 
+                if (gtk_widget_get_direction (GTK_WIDGET (bar)) == GTK_TEXT_DIR_RTL) {
1966
 
+                        if (direction == GDK_SCROLL_RIGHT)
1967
 
+                                direction = GDK_SCROLL_LEFT;
1968
 
+                        else if (direction == GDK_SCROLL_LEFT)
1969
 
+                                direction = GDK_SCROLL_RIGHT;
1970
 
+                }
1971
 
+                /* Switch side scroll to vertical */
1972
 
+                if (direction == GDK_SCROLL_RIGHT)
1973
 
+                        direction = GDK_SCROLL_UP;
1974
 
+                else if (direction == GDK_SCROLL_LEFT)
1975
 
+                        direction = GDK_SCROLL_DOWN;
1976
 
+        }
1977
 
+
1978
 
+       if (!gdk_event_get_scroll_deltas ((GdkEvent*)event, &dx, &dy)) {
1979
 
+               dx = 0.0;
1980
 
+               dy = 0.0;
1981
 
+
1982
 
+               switch (direction) {
1983
 
+               case GDK_SCROLL_UP:
1984
 
+               case GDK_SCROLL_LEFT:
1985
 
+                       dy = 1.0;
1986
 
+                       break;
1987
 
+               case GDK_SCROLL_DOWN:
1988
 
+               case GDK_SCROLL_RIGHT:
1989
 
+                       dy = -1.0;
1990
 
+                       break;
1991
 
+               default:
1992
 
+                       ;
1993
 
+               }
1994
 
+       }
1995
 
+
1996
 
+        adj = gtk_range_get_adjustment (GTK_RANGE (bar->priv->scale));
1997
 
+        if (adj == bar->priv->zero_adjustment) {
1998
 
+                if (dy > 0)
1999
 
+                        gvc_channel_bar_set_is_muted (bar, FALSE);
2000
 
+                return TRUE;
2001
 
+        }
2002
 
+
2003
 
+        value = gtk_adjustment_get_value (adj);
2004
 
+
2005
 
+        if (dy > 0) {
2006
 
+                if (value + dy * SCROLLSTEP > ADJUSTMENT_MAX)
2007
 
+                        value = ADJUSTMENT_MAX;
2008
 
+                else
2009
 
+                        value = value + dy * SCROLLSTEP;
2010
 
+        } else if (dy < 0) {
2011
 
+                if (value + dy * SCROLLSTEP < 0)
2012
 
+                        value = 0.0;
2013
 
+                else
2014
 
+                        value = value + dy * SCROLLSTEP;
2015
 
+        }
2016
 
+
2017
 
+        gvc_channel_bar_set_is_muted (bar, (value == 0.0));
2018
 
+        adj = gtk_range_get_adjustment (GTK_RANGE (bar->priv->scale));
2019
 
+        gtk_adjustment_set_value (adj, value);
2020
 
+
2021
 
+        return TRUE;
2022
 
+}
2023
 
+
2024
 
+static gboolean
2025
 
+on_scale_scroll_event (GtkWidget      *widget,
2026
 
+                       GdkEventScroll *event,
2027
 
+                       GvcChannelBar  *bar)
2028
 
+{
2029
 
+        return gvc_channel_bar_scroll (bar, event);
2030
 
+}
2031
 
+
2032
 
+static void
2033
 
+on_zero_adjustment_value_changed (GtkAdjustment *adjustment,
2034
 
+                                  GvcChannelBar *bar)
2035
 
+{
2036
 
+        gdouble value;
2037
 
+
2038
 
+        if (bar->priv->click_lock != FALSE) {
2039
 
+                return;
2040
 
+        }
2041
 
+
2042
 
+        value = gtk_adjustment_get_value (bar->priv->zero_adjustment);
2043
 
+        gtk_adjustment_set_value (bar->priv->adjustment, value);
2044
 
+
2045
 
+
2046
 
+        if (bar->priv->show_mute == FALSE) {
2047
 
+                /* this means the adjustment moved away from zero and
2048
 
+                 * therefore we should unmute and set the volume. */
2049
 
+                gvc_channel_bar_set_is_muted (bar, value > 0.0);
2050
 
+        }
2051
 
+}
2052
 
+
2053
 
+static void
2054
 
+update_mute_button (GvcChannelBar *bar)
2055
 
+{
2056
 
+        if (bar->priv->show_mute) {
2057
 
+                gtk_widget_show (bar->priv->mute_button);
2058
 
+                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bar->priv->mute_button),
2059
 
+                                              bar->priv->is_muted);
2060
 
+        } else {
2061
 
+                gtk_widget_hide (bar->priv->mute_button);
2062
 
+        }
2063
 
+
2064
 
+        if (bar->priv->is_muted) {
2065
 
+                /* If we aren't showing the mute button then
2066
 
+                 * move slider to the zero.  But we don't want to
2067
 
+                 * change the adjustment.  */
2068
 
+                g_signal_handlers_block_by_func (bar->priv->zero_adjustment,
2069
 
+                                                 on_zero_adjustment_value_changed,
2070
 
+                                                 bar);
2071
 
+                gtk_adjustment_set_value (bar->priv->zero_adjustment, 0);
2072
 
+                g_signal_handlers_unblock_by_func (bar->priv->zero_adjustment,
2073
 
+                                                   on_zero_adjustment_value_changed,
2074
 
+                                                   bar);
2075
 
+                gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale),
2076
 
+                                          bar->priv->zero_adjustment);
2077
 
+        } else {
2078
 
+                /* no longer muted so restore the original adjustment
2079
 
+                 * and tell the front-end that the value changed */
2080
 
+                gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale),
2081
 
+                                          bar->priv->adjustment);
2082
 
+                gtk_adjustment_value_changed (bar->priv->adjustment);
2083
 
+        }
2084
 
+}
2085
 
+
2086
 
+void
2087
 
+gvc_channel_bar_set_is_muted (GvcChannelBar *bar,
2088
 
+                              gboolean       is_muted)
2089
 
+{
2090
 
+        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
2091
 
+
2092
 
+        if (is_muted != bar->priv->is_muted) {
2093
 
+                /* Update our internal state before telling the
2094
 
+                 * front-end about our changes */
2095
 
+                bar->priv->is_muted = is_muted;
2096
 
+                update_mute_button (bar);
2097
 
+                g_object_notify (G_OBJECT (bar), "is-muted");
2098
 
+        }
2099
 
+}
2100
 
+
2101
 
+gboolean
2102
 
+gvc_channel_bar_get_is_muted  (GvcChannelBar *bar)
2103
 
+{
2104
 
+        g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
2105
 
+        return bar->priv->is_muted;
2106
 
+}
2107
 
+
2108
 
+void
2109
 
+gvc_channel_bar_set_show_mute (GvcChannelBar *bar,
2110
 
+                               gboolean       show_mute)
2111
 
+{
2112
 
+        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
2113
 
+
2114
 
+        if (show_mute != bar->priv->show_mute) {
2115
 
+                bar->priv->show_mute = show_mute;
2116
 
+                g_object_notify (G_OBJECT (bar), "show-mute");
2117
 
+                update_mute_button (bar);
2118
 
+        }
2119
 
+}
2120
 
+
2121
 
+gboolean
2122
 
+gvc_channel_bar_get_show_mute (GvcChannelBar *bar)
2123
 
+{
2124
 
+        g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
2125
 
+        return bar->priv->show_mute;
2126
 
+}
2127
 
+
2128
 
+void
2129
 
+gvc_channel_bar_set_is_amplified (GvcChannelBar *bar, gboolean amplified)
2130
 
+{
2131
 
+        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
2132
 
+
2133
 
+        bar->priv->is_amplified = amplified;
2134
 
+        gtk_adjustment_set_upper (bar->priv->adjustment, ADJUSTMENT_MAX);
2135
 
+        gtk_adjustment_set_upper (bar->priv->zero_adjustment, ADJUSTMENT_MAX);
2136
 
+        gtk_scale_clear_marks (GTK_SCALE (bar->priv->scale));
2137
 
+
2138
 
+        if (amplified) {
2139
 
+                char *str;
2140
 
+
2141
 
+                if (bar->priv->base_volume == ADJUSTMENT_MAX_NORMAL) {
2142
 
+                        str = g_strdup_printf ("<small>%s</small>", C_("volume", "100%"));
2143
 
+                        gtk_scale_add_mark (GTK_SCALE (bar->priv->scale), ADJUSTMENT_MAX_NORMAL,
2144
 
+                                            GTK_POS_BOTTOM, str);
2145
 
+                } else {
2146
 
+                        str = g_strdup_printf ("<small>%s</small>", C_("volume", "Unamplified"));
2147
 
+                        gtk_scale_add_mark (GTK_SCALE (bar->priv->scale), bar->priv->base_volume,
2148
 
+                                            GTK_POS_BOTTOM, str);
2149
 
+                        /* Only show 100% if it's higher than the base volume */
2150
 
+                        if (bar->priv->base_volume < ADJUSTMENT_MAX_NORMAL) {
2151
 
+                                str = g_strdup_printf ("<small>%s</small>", C_("volume", "100%"));
2152
 
+                                gtk_scale_add_mark (GTK_SCALE (bar->priv->scale), ADJUSTMENT_MAX_NORMAL,
2153
 
+                                                    GTK_POS_BOTTOM, str);
2154
 
+                        }
2155
 
+                }
2156
 
+
2157
 
+                g_free (str);
2158
 
+                gtk_alignment_set (GTK_ALIGNMENT (bar->priv->mute_box), 0.5, 0, 0, 0);
2159
 
+                gtk_misc_set_alignment (GTK_MISC (bar->priv->low_image), 0.5, 0.15);
2160
 
+                gtk_misc_set_alignment (GTK_MISC (bar->priv->high_image), 0.5, 0.15);
2161
 
+                gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0, 0);
2162
 
+        } else {
2163
 
+                gtk_alignment_set (GTK_ALIGNMENT (bar->priv->mute_box), 0.5, 0.5, 0, 0);
2164
 
+                gtk_misc_set_alignment (GTK_MISC (bar->priv->low_image), 0.5, 0.5);
2165
 
+                gtk_misc_set_alignment (GTK_MISC (bar->priv->high_image), 0.5, 0.5);
2166
 
+                gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0, 0.5);
2167
 
+        }
2168
 
+}
2169
 
+
2170
 
+gboolean
2171
 
+gvc_channel_bar_get_ellipsize (GvcChannelBar *bar)
2172
 
+{
2173
 
+        g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
2174
 
+
2175
 
+        return gtk_label_get_ellipsize (GTK_LABEL (bar->priv->label)) != PANGO_ELLIPSIZE_NONE;
2176
 
+}
2177
 
+
2178
 
+void
2179
 
+gvc_channel_bar_set_ellipsize (GvcChannelBar *bar,
2180
 
+                               gboolean       ellipsized)
2181
 
+{
2182
 
+        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
2183
 
+
2184
 
+        if (ellipsized)
2185
 
+                gtk_label_set_ellipsize (GTK_LABEL (bar->priv->label), PANGO_ELLIPSIZE_END);
2186
 
+       else
2187
 
+                gtk_label_set_ellipsize (GTK_LABEL (bar->priv->label), PANGO_ELLIPSIZE_NONE);
2188
 
+}
2189
 
+
2190
 
+void
2191
 
+gvc_channel_bar_set_base_volume (GvcChannelBar *bar,
2192
 
+                                 pa_volume_t    base_volume)
2193
 
+{
2194
 
+        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
2195
 
+
2196
 
+        if (base_volume == 0) {
2197
 
+                bar->priv->base_volume = ADJUSTMENT_MAX_NORMAL;
2198
 
+                return;
2199
 
+        }
2200
 
+
2201
 
+        /* Note that you need to call _is_amplified() afterwards to update the marks */
2202
 
+        bar->priv->base_volume = base_volume;
2203
 
+}
2204
 
+
2205
 
+static void
2206
 
+gvc_channel_bar_set_property (GObject       *object,
2207
 
+                              guint          prop_id,
2208
 
+                              const GValue  *value,
2209
 
+                              GParamSpec    *pspec)
2210
 
+{
2211
 
+        GvcChannelBar *self = GVC_CHANNEL_BAR (object);
2212
 
+
2213
 
+        switch (prop_id) {
2214
 
+        case PROP_ORIENTATION:
2215
 
+                gvc_channel_bar_set_orientation (self, g_value_get_enum (value));
2216
 
+                break;
2217
 
+        case PROP_IS_MUTED:
2218
 
+                gvc_channel_bar_set_is_muted (self, g_value_get_boolean (value));
2219
 
+                break;
2220
 
+        case PROP_SHOW_MUTE:
2221
 
+                gvc_channel_bar_set_show_mute (self, g_value_get_boolean (value));
2222
 
+                break;
2223
 
+        case PROP_NAME:
2224
 
+                gvc_channel_bar_set_name (self, g_value_get_string (value));
2225
 
+                break;
2226
 
+        case PROP_ICON_NAME:
2227
 
+                gvc_channel_bar_set_icon_name (self, g_value_get_string (value));
2228
 
+                break;
2229
 
+        case PROP_LOW_ICON_NAME:
2230
 
+                gvc_channel_bar_set_low_icon_name (self, g_value_get_string (value));
2231
 
+                break;
2232
 
+        case PROP_HIGH_ICON_NAME:
2233
 
+                gvc_channel_bar_set_high_icon_name (self, g_value_get_string (value));
2234
 
+                break;
2235
 
+        case PROP_ADJUSTMENT:
2236
 
+                gvc_channel_bar_set_adjustment (self, g_value_get_object (value));
2237
 
+                break;
2238
 
+        case PROP_IS_AMPLIFIED:
2239
 
+                gvc_channel_bar_set_is_amplified (self, g_value_get_boolean (value));
2240
 
+                break;
2241
 
+        case PROP_ELLIPSIZE:
2242
 
+                gvc_channel_bar_set_ellipsize (self, g_value_get_boolean (value));
2243
 
+                break;
2244
 
+        default:
2245
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2246
 
+                break;
2247
 
+        }
2248
 
+}
2249
 
+
2250
 
+static void
2251
 
+gvc_channel_bar_get_property (GObject     *object,
2252
 
+                              guint        prop_id,
2253
 
+                              GValue      *value,
2254
 
+                              GParamSpec  *pspec)
2255
 
+{
2256
 
+        GvcChannelBar *self = GVC_CHANNEL_BAR (object);
2257
 
+        GvcChannelBarPrivate *priv = self->priv;
2258
 
+
2259
 
+        switch (prop_id) {
2260
 
+        case PROP_ORIENTATION:
2261
 
+                g_value_set_enum (value, priv->orientation);
2262
 
+                break;
2263
 
+        case PROP_IS_MUTED:
2264
 
+                g_value_set_boolean (value, priv->is_muted);
2265
 
+                break;
2266
 
+        case PROP_SHOW_MUTE:
2267
 
+                g_value_set_boolean (value, priv->show_mute);
2268
 
+                break;
2269
 
+        case PROP_NAME:
2270
 
+                g_value_set_string (value, priv->name);
2271
 
+                break;
2272
 
+        case PROP_ICON_NAME:
2273
 
+                g_value_set_string (value, priv->icon_name);
2274
 
+                break;
2275
 
+        case PROP_LOW_ICON_NAME:
2276
 
+                g_value_set_string (value, priv->low_icon_name);
2277
 
+                break;
2278
 
+        case PROP_HIGH_ICON_NAME:
2279
 
+                g_value_set_string (value, priv->high_icon_name);
2280
 
+                break;
2281
 
+        case PROP_ADJUSTMENT:
2282
 
+                g_value_set_object (value, gvc_channel_bar_get_adjustment (self));
2283
 
+                break;
2284
 
+        case PROP_IS_AMPLIFIED:
2285
 
+                g_value_set_boolean (value, priv->is_amplified);
2286
 
+                break;
2287
 
+        case PROP_ELLIPSIZE:
2288
 
+                g_value_set_boolean (value, gvc_channel_bar_get_ellipsize (self));
2289
 
+                break;
2290
 
+        default:
2291
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2292
 
+                break;
2293
 
+        }
2294
 
+}
2295
 
+
2296
 
+static GObject *
2297
 
+gvc_channel_bar_constructor (GType                  type,
2298
 
+                             guint                  n_construct_properties,
2299
 
+                             GObjectConstructParam *construct_params)
2300
 
+{
2301
 
+        GObject       *object;
2302
 
+        GvcChannelBar *self;
2303
 
+
2304
 
+        object = G_OBJECT_CLASS (gvc_channel_bar_parent_class)->constructor (type, n_construct_properties, construct_params);
2305
 
+
2306
 
+        self = GVC_CHANNEL_BAR (object);
2307
 
+
2308
 
+        update_mute_button (self);
2309
 
+
2310
 
+        return object;
2311
 
+}
2312
 
+
2313
 
+static void
2314
 
+gvc_channel_bar_class_init (GvcChannelBarClass *klass)
2315
 
+{
2316
 
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
2317
 
+
2318
 
+        object_class->constructor = gvc_channel_bar_constructor;
2319
 
+        object_class->finalize = gvc_channel_bar_finalize;
2320
 
+        object_class->set_property = gvc_channel_bar_set_property;
2321
 
+        object_class->get_property = gvc_channel_bar_get_property;
2322
 
+
2323
 
+        g_object_class_install_property (object_class,
2324
 
+                                         PROP_ORIENTATION,
2325
 
+                                         g_param_spec_enum ("orientation",
2326
 
+                                                            "Orientation",
2327
 
+                                                            "The orientation of the scale",
2328
 
+                                                            GTK_TYPE_ORIENTATION,
2329
 
+                                                            GTK_ORIENTATION_VERTICAL,
2330
 
+                                                            G_PARAM_READWRITE));
2331
 
+        g_object_class_install_property (object_class,
2332
 
+                                         PROP_IS_MUTED,
2333
 
+                                         g_param_spec_boolean ("is-muted",
2334
 
+                                                               "is muted",
2335
 
+                                                               "Whether stream is muted",
2336
 
+                                                               FALSE,
2337
 
+                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2338
 
+        g_object_class_install_property (object_class,
2339
 
+                                         PROP_SHOW_MUTE,
2340
 
+                                         g_param_spec_boolean ("show-mute",
2341
 
+                                                               "show mute",
2342
 
+                                                               "Whether stream is muted",
2343
 
+                                                               FALSE,
2344
 
+                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2345
 
+
2346
 
+        g_object_class_install_property (object_class,
2347
 
+                                         PROP_ADJUSTMENT,
2348
 
+                                         g_param_spec_object ("adjustment",
2349
 
+                                                              "Adjustment",
2350
 
+                                                              "The GtkAdjustment that contains the current value of this scale button object",
2351
 
+                                                              GTK_TYPE_ADJUSTMENT,
2352
 
+                                                              G_PARAM_READWRITE));
2353
 
+        g_object_class_install_property (object_class,
2354
 
+                                         PROP_NAME,
2355
 
+                                         g_param_spec_string ("name",
2356
 
+                                                              "Name",
2357
 
+                                                              "Name to display for this stream",
2358
 
+                                                              NULL,
2359
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2360
 
+        g_object_class_install_property (object_class,
2361
 
+                                         PROP_ICON_NAME,
2362
 
+                                         g_param_spec_string ("icon-name",
2363
 
+                                                              "Icon Name",
2364
 
+                                                              "Name of icon to display for this stream",
2365
 
+                                                              NULL,
2366
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2367
 
+        g_object_class_install_property (object_class,
2368
 
+                                         PROP_LOW_ICON_NAME,
2369
 
+                                         g_param_spec_string ("low-icon-name",
2370
 
+                                                              "Icon Name",
2371
 
+                                                              "Name of icon to display for this stream",
2372
 
+                                                              "audio-volume-low-symbolic",
2373
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2374
 
+        g_object_class_install_property (object_class,
2375
 
+                                         PROP_HIGH_ICON_NAME,
2376
 
+                                         g_param_spec_string ("high-icon-name",
2377
 
+                                                              "Icon Name",
2378
 
+                                                              "Name of icon to display for this stream",
2379
 
+                                                              "audio-volume-high-symbolic",
2380
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2381
 
+        g_object_class_install_property (object_class,
2382
 
+                                         PROP_IS_AMPLIFIED,
2383
 
+                                         g_param_spec_boolean ("is-amplified",
2384
 
+                                                               "Is amplified",
2385
 
+                                                               "Whether the stream is digitally amplified",
2386
 
+                                                               FALSE,
2387
 
+                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2388
 
+        g_object_class_install_property (object_class,
2389
 
+                                         PROP_ELLIPSIZE,
2390
 
+                                         g_param_spec_boolean ("ellipsize",
2391
 
+                                                               "Label is ellipsized",
2392
 
+                                                               "Whether the label is ellipsized",
2393
 
+                                                               FALSE,
2394
 
+                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2395
 
+        g_type_class_add_private (klass, sizeof (GvcChannelBarPrivate));
2396
 
+}
2397
 
+
2398
 
+static void
2399
 
+on_mute_button_toggled (GtkToggleButton *button,
2400
 
+                        GvcChannelBar   *bar)
2401
 
+{
2402
 
+        gboolean is_muted;
2403
 
+        is_muted = gtk_toggle_button_get_active (button);
2404
 
+        gvc_channel_bar_set_is_muted (bar, is_muted);
2405
 
+}
2406
 
+
2407
 
+static void
2408
 
+gvc_channel_bar_init (GvcChannelBar *bar)
2409
 
+{
2410
 
+        GtkWidget *frame;
2411
 
+
2412
 
+        bar->priv = GVC_CHANNEL_BAR_GET_PRIVATE (bar);
2413
 
+
2414
 
+        bar->priv->base_volume = ADJUSTMENT_MAX_NORMAL;
2415
 
+        bar->priv->low_icon_name = g_strdup ("audio-volume-low-symbolic");
2416
 
+        bar->priv->high_icon_name = g_strdup ("audio-volume-high-symbolic");
2417
 
+
2418
 
+        bar->priv->orientation = GTK_ORIENTATION_VERTICAL;
2419
 
+        bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
2420
 
+                                                                    0.0,
2421
 
+                                                                    ADJUSTMENT_MAX_NORMAL,
2422
 
+                                                                    ADJUSTMENT_MAX_NORMAL/100.0,
2423
 
+                                                                    ADJUSTMENT_MAX_NORMAL/10.0,
2424
 
+                                                                    0.0));
2425
 
+        g_object_ref_sink (bar->priv->adjustment);
2426
 
+
2427
 
+        bar->priv->zero_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
2428
 
+                                                                         0.0,
2429
 
+                                                                         ADJUSTMENT_MAX_NORMAL,
2430
 
+                                                                         ADJUSTMENT_MAX_NORMAL/100.0,
2431
 
+                                                                         ADJUSTMENT_MAX_NORMAL/10.0,
2432
 
+                                                                         0.0));
2433
 
+        g_object_ref_sink (bar->priv->zero_adjustment);
2434
 
+
2435
 
+        g_signal_connect (bar->priv->zero_adjustment,
2436
 
+                          "value-changed",
2437
 
+                          G_CALLBACK (on_zero_adjustment_value_changed),
2438
 
+                          bar);
2439
 
+
2440
 
+        bar->priv->mute_button = gtk_check_button_new_with_label (_("Mute"));
2441
 
+        gtk_widget_set_no_show_all (bar->priv->mute_button, TRUE);
2442
 
+        g_signal_connect (bar->priv->mute_button,
2443
 
+                          "toggled",
2444
 
+                          G_CALLBACK (on_mute_button_toggled),
2445
 
+                          bar);
2446
 
+        bar->priv->mute_box = gtk_alignment_new (0.5, 0.5, 0, 0);
2447
 
+        gtk_container_add (GTK_CONTAINER (bar->priv->mute_box), bar->priv->mute_button);
2448
 
+
2449
 
+        bar->priv->low_image = gtk_image_new_from_icon_name ("audio-volume-low-symbolic",
2450
 
+                                                             GTK_ICON_SIZE_MENU);
2451
 
+        gtk_widget_set_no_show_all (bar->priv->low_image, TRUE);
2452
 
+        bar->priv->high_image = gtk_image_new_from_icon_name ("audio-volume-high-symbolic",
2453
 
+                                                              GTK_ICON_SIZE_MENU);
2454
 
+        gtk_widget_set_no_show_all (bar->priv->high_image, TRUE);
2455
 
+
2456
 
+        bar->priv->image = gtk_image_new ();
2457
 
+        gtk_widget_set_no_show_all (bar->priv->image, TRUE);
2458
 
+
2459
 
+        bar->priv->label = gtk_label_new (NULL);
2460
 
+        gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0.0, 0.5);
2461
 
+        gtk_widget_set_no_show_all (bar->priv->label, TRUE);
2462
 
+
2463
 
+        /* frame */
2464
 
+        frame = gtk_frame_new (NULL);
2465
 
+        gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
2466
 
+        gtk_container_add (GTK_CONTAINER (bar), frame);
2467
 
+        gtk_widget_show_all (frame);
2468
 
+
2469
 
+        /* box with scale */
2470
 
+        bar->priv->scale_box = _scale_box_new (bar);
2471
 
+
2472
 
+        gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box);
2473
 
+}
2474
 
+
2475
 
+static void
2476
 
+gvc_channel_bar_finalize (GObject *object)
2477
 
+{
2478
 
+        GvcChannelBar *channel_bar;
2479
 
+
2480
 
+        g_return_if_fail (object != NULL);
2481
 
+        g_return_if_fail (GVC_IS_CHANNEL_BAR (object));
2482
 
+
2483
 
+        channel_bar = GVC_CHANNEL_BAR (object);
2484
 
+
2485
 
+        g_return_if_fail (channel_bar->priv != NULL);
2486
 
+
2487
 
+        g_free (channel_bar->priv->name);
2488
 
+        g_free (channel_bar->priv->icon_name);
2489
 
+        g_free (channel_bar->priv->low_icon_name);
2490
 
+        g_free (channel_bar->priv->high_icon_name);
2491
 
+
2492
 
+        G_OBJECT_CLASS (gvc_channel_bar_parent_class)->finalize (object);
2493
 
+}
2494
 
+
2495
 
+GtkWidget *
2496
 
+gvc_channel_bar_new (void)
2497
 
+{
2498
 
+        GObject *bar;
2499
 
+        bar = g_object_new (GVC_TYPE_CHANNEL_BAR,
2500
 
+                            NULL);
2501
 
+        return GTK_WIDGET (bar);
2502
 
+}
2503
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-channel-bar.h
2504
 
===================================================================
2505
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2506
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-channel-bar.h       2012-08-28 17:08:49.436516898 +0200
2507
 
@@ -0,0 +1,89 @@
2508
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2509
 
+ *
2510
 
+ * Copyright (C) 2008 Red Hat, Inc.
2511
 
+ *
2512
 
+ * This program is free software; you can redistribute it and/or modify
2513
 
+ * it under the terms of the GNU General Public License as published by
2514
 
+ * the Free Software Foundation; either version 2 of the License, or
2515
 
+ * (at your option) any later version.
2516
 
+ *
2517
 
+ * This program is distributed in the hope that it will be useful,
2518
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2519
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2520
 
+ * GNU General Public License for more details.
2521
 
+ *
2522
 
+ * You should have received a copy of the GNU General Public License
2523
 
+ * along with this program; if not, write to the Free Software
2524
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2525
 
+ *
2526
 
+ */
2527
 
+
2528
 
+#ifndef __GVC_CHANNEL_BAR_H
2529
 
+#define __GVC_CHANNEL_BAR_H
2530
 
+
2531
 
+#include <glib-object.h>
2532
 
+
2533
 
+G_BEGIN_DECLS
2534
 
+
2535
 
+#define GVC_TYPE_CHANNEL_BAR         (gvc_channel_bar_get_type ())
2536
 
+#define GVC_CHANNEL_BAR(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_CHANNEL_BAR, GvcChannelBar))
2537
 
+#define GVC_CHANNEL_BAR_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_CHANNEL_BAR, GvcChannelBarClass))
2538
 
+#define GVC_IS_CHANNEL_BAR(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_CHANNEL_BAR))
2539
 
+#define GVC_IS_CHANNEL_BAR_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_CHANNEL_BAR))
2540
 
+#define GVC_CHANNEL_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_CHANNEL_BAR, GvcChannelBarClass))
2541
 
+
2542
 
+typedef struct GvcChannelBarPrivate GvcChannelBarPrivate;
2543
 
+
2544
 
+typedef struct
2545
 
+{
2546
 
+        GtkHBox               parent;
2547
 
+        GvcChannelBarPrivate *priv;
2548
 
+} GvcChannelBar;
2549
 
+
2550
 
+typedef struct
2551
 
+{
2552
 
+        GtkHBoxClass          parent_class;
2553
 
+} GvcChannelBarClass;
2554
 
+
2555
 
+GType               gvc_channel_bar_get_type            (void);
2556
 
+
2557
 
+GtkWidget *         gvc_channel_bar_new                 (void);
2558
 
+
2559
 
+void                gvc_channel_bar_set_name            (GvcChannelBar *bar,
2560
 
+                                                         const char    *name);
2561
 
+void                gvc_channel_bar_set_icon_name       (GvcChannelBar *bar,
2562
 
+                                                         const char    *icon_name);
2563
 
+void                gvc_channel_bar_set_low_icon_name   (GvcChannelBar *bar,
2564
 
+                                                         const char    *icon_name);
2565
 
+void                gvc_channel_bar_set_high_icon_name  (GvcChannelBar *bar,
2566
 
+                                                         const char    *icon_name);
2567
 
+
2568
 
+void                gvc_channel_bar_set_orientation     (GvcChannelBar *bar,
2569
 
+                                                         GtkOrientation orientation);
2570
 
+GtkOrientation      gvc_channel_bar_get_orientation     (GvcChannelBar *bar);
2571
 
+
2572
 
+GtkAdjustment *     gvc_channel_bar_get_adjustment      (GvcChannelBar *bar);
2573
 
+
2574
 
+gboolean            gvc_channel_bar_get_is_muted        (GvcChannelBar *bar);
2575
 
+void                gvc_channel_bar_set_is_muted        (GvcChannelBar *bar,
2576
 
+                                                         gboolean       is_muted);
2577
 
+gboolean            gvc_channel_bar_get_show_mute       (GvcChannelBar *bar);
2578
 
+void                gvc_channel_bar_set_show_mute       (GvcChannelBar *bar,
2579
 
+                                                         gboolean       show_mute);
2580
 
+void                gvc_channel_bar_set_size_group      (GvcChannelBar *bar,
2581
 
+                                                         GtkSizeGroup  *group,
2582
 
+                                                         gboolean       symmetric);
2583
 
+void                gvc_channel_bar_set_is_amplified    (GvcChannelBar *bar,
2584
 
+                                                         gboolean amplified);
2585
 
+void                gvc_channel_bar_set_base_volume     (GvcChannelBar *bar,
2586
 
+                                                         guint32        base_volume);
2587
 
+gboolean            gvc_channel_bar_get_ellipsize       (GvcChannelBar *bar);
2588
 
+void                gvc_channel_bar_set_ellipsize       (GvcChannelBar *bar,
2589
 
+                                                         gboolean       ellipsized);
2590
 
+
2591
 
+gboolean            gvc_channel_bar_scroll              (GvcChannelBar  *bar,
2592
 
+                                                         GdkEventScroll *event);
2593
 
+
2594
 
+G_END_DECLS
2595
 
+
2596
 
+#endif /* __GVC_CHANNEL_BAR_H */
2597
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-channel-map-private.h
2598
 
===================================================================
2599
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2600
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-channel-map-private.h       2012-08-28 17:08:49.436516898 +0200
2601
 
@@ -0,0 +1,39 @@
2602
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2603
 
+ *
2604
 
+ * Copyright (C) 2008 Red Hat, Inc.
2605
 
+ *
2606
 
+ * This program is free software; you can redistribute it and/or modify
2607
 
+ * it under the terms of the GNU General Public License as published by
2608
 
+ * the Free Software Foundation; either version 2 of the License, or
2609
 
+ * (at your option) any later version.
2610
 
+ *
2611
 
+ * This program is distributed in the hope that it will be useful,
2612
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2613
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2614
 
+ * GNU General Public License for more details.
2615
 
+ *
2616
 
+ * You should have received a copy of the GNU General Public License
2617
 
+ * along with this program; if not, write to the Free Software
2618
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2619
 
+ *
2620
 
+ */
2621
 
+
2622
 
+#ifndef __GVC_CHANNEL_MAP_PRIVATE_H
2623
 
+#define __GVC_CHANNEL_MAP_PRIVATE_H
2624
 
+
2625
 
+#include <glib-object.h>
2626
 
+#include <pulse/pulseaudio.h>
2627
 
+
2628
 
+G_BEGIN_DECLS
2629
 
+
2630
 
+GvcChannelMap *         gvc_channel_map_new_from_pa_channel_map (const pa_channel_map *map);
2631
 
+const pa_channel_map *  gvc_channel_map_get_pa_channel_map      (const GvcChannelMap  *map);
2632
 
+
2633
 
+void                    gvc_channel_map_volume_changed          (GvcChannelMap    *map,
2634
 
+                                                                 const pa_cvolume *cv,
2635
 
+                                                                 gboolean          set);
2636
 
+const pa_cvolume *      gvc_channel_map_get_cvolume             (const GvcChannelMap  *map);
2637
 
+
2638
 
+G_END_DECLS
2639
 
+
2640
 
+#endif /* __GVC_CHANNEL_MAP_PRIVATE_H */
2641
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-channel-map.c
2642
 
===================================================================
2643
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2644
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-channel-map.c       2012-08-28 17:08:49.436516898 +0200
2645
 
@@ -0,0 +1,254 @@
2646
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2647
 
+ *
2648
 
+ * Copyright (C) 2008 William Jon McCann
2649
 
+ *
2650
 
+ * This program is free software; you can redistribute it and/or modify
2651
 
+ * it under the terms of the GNU General Public License as published by
2652
 
+ * the Free Software Foundation; either version 2 of the License, or
2653
 
+ * (at your option) any later version.
2654
 
+ *
2655
 
+ * This program is distributed in the hope that it will be useful,
2656
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2657
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2658
 
+ * GNU General Public License for more details.
2659
 
+ *
2660
 
+ * You should have received a copy of the GNU General Public License
2661
 
+ * along with this program; if not, write to the Free Software
2662
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2663
 
+ *
2664
 
+ */
2665
 
+
2666
 
+#include "config.h"
2667
 
+
2668
 
+#include <stdlib.h>
2669
 
+#include <stdio.h>
2670
 
+#include <unistd.h>
2671
 
+
2672
 
+#include <glib.h>
2673
 
+#include <glib/gi18n-lib.h>
2674
 
+
2675
 
+#include <pulse/pulseaudio.h>
2676
 
+
2677
 
+#include "gvc-channel-map.h"
2678
 
+#include "gvc-channel-map-private.h"
2679
 
+
2680
 
+#define GVC_CHANNEL_MAP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMapPrivate))
2681
 
+
2682
 
+struct GvcChannelMapPrivate
2683
 
+{
2684
 
+        pa_channel_map        pa_map;
2685
 
+        gboolean              pa_volume_is_set;
2686
 
+        pa_cvolume            pa_volume;
2687
 
+        gdouble               extern_volume[NUM_TYPES]; /* volume, balance, fade, lfe */
2688
 
+        gboolean              can_balance;
2689
 
+        gboolean              can_fade;
2690
 
+};
2691
 
+
2692
 
+enum {
2693
 
+        VOLUME_CHANGED,
2694
 
+        LAST_SIGNAL
2695
 
+};
2696
 
+
2697
 
+static guint signals [LAST_SIGNAL] = { 0, };
2698
 
+
2699
 
+static void     gvc_channel_map_class_init (GvcChannelMapClass *klass);
2700
 
+static void     gvc_channel_map_init       (GvcChannelMap      *channel_map);
2701
 
+static void     gvc_channel_map_finalize   (GObject            *object);
2702
 
+
2703
 
+G_DEFINE_TYPE (GvcChannelMap, gvc_channel_map, G_TYPE_OBJECT)
2704
 
+
2705
 
+guint
2706
 
+gvc_channel_map_get_num_channels (const GvcChannelMap *map)
2707
 
+{
2708
 
+        g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), 0);
2709
 
+
2710
 
+        if (!pa_channel_map_valid(&map->priv->pa_map))
2711
 
+                return 0;
2712
 
+
2713
 
+        return map->priv->pa_map.channels;
2714
 
+}
2715
 
+
2716
 
+const gdouble *
2717
 
+gvc_channel_map_get_volume (GvcChannelMap *map)
2718
 
+{
2719
 
+        g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
2720
 
+
2721
 
+        if (!pa_channel_map_valid(&map->priv->pa_map))
2722
 
+                return NULL;
2723
 
+
2724
 
+        map->priv->extern_volume[VOLUME] = (gdouble) pa_cvolume_max (&map->priv->pa_volume);
2725
 
+        if (gvc_channel_map_can_balance (map))
2726
 
+                map->priv->extern_volume[BALANCE] = (gdouble) pa_cvolume_get_balance (&map->priv->pa_volume, &map->priv->pa_map);
2727
 
+        else
2728
 
+                map->priv->extern_volume[BALANCE] = 0;
2729
 
+        if (gvc_channel_map_can_fade (map))
2730
 
+                map->priv->extern_volume[FADE] = (gdouble) pa_cvolume_get_fade (&map->priv->pa_volume, &map->priv->pa_map);
2731
 
+        else
2732
 
+                map->priv->extern_volume[FADE] = 0;
2733
 
+        if (gvc_channel_map_has_lfe (map))
2734
 
+                map->priv->extern_volume[LFE] = (gdouble) pa_cvolume_get_position (&map->priv->pa_volume, &map->priv->pa_map, PA_CHANNEL_POSITION_LFE);
2735
 
+        else
2736
 
+                map->priv->extern_volume[LFE] = 0;
2737
 
+
2738
 
+        return map->priv->extern_volume;
2739
 
+}
2740
 
+
2741
 
+gboolean
2742
 
+gvc_channel_map_can_balance (const GvcChannelMap  *map)
2743
 
+{
2744
 
+        g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
2745
 
+
2746
 
+        return map->priv->can_balance;
2747
 
+}
2748
 
+
2749
 
+gboolean
2750
 
+gvc_channel_map_can_fade (const GvcChannelMap  *map)
2751
 
+{
2752
 
+        g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
2753
 
+
2754
 
+        return map->priv->can_fade;
2755
 
+}
2756
 
+
2757
 
+const char *
2758
 
+gvc_channel_map_get_mapping (const GvcChannelMap  *map)
2759
 
+{
2760
 
+        g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
2761
 
+
2762
 
+        if (!pa_channel_map_valid(&map->priv->pa_map))
2763
 
+                return NULL;
2764
 
+
2765
 
+        return pa_channel_map_to_pretty_name (&map->priv->pa_map);
2766
 
+}
2767
 
+
2768
 
+/**
2769
 
+ * gvc_channel_map_has_position: (skip)
2770
 
+ *
2771
 
+ * @map:
2772
 
+ * @position:
2773
 
+ *
2774
 
+ * Returns:
2775
 
+ */
2776
 
+gboolean
2777
 
+gvc_channel_map_has_position (const GvcChannelMap  *map,
2778
 
+                              pa_channel_position_t position)
2779
 
+{
2780
 
+        g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
2781
 
+
2782
 
+        return pa_channel_map_has_position (&(map->priv->pa_map), position);
2783
 
+}
2784
 
+
2785
 
+const pa_channel_map *
2786
 
+gvc_channel_map_get_pa_channel_map (const GvcChannelMap  *map)
2787
 
+{
2788
 
+        g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
2789
 
+
2790
 
+        if (!pa_channel_map_valid(&map->priv->pa_map))
2791
 
+                return NULL;
2792
 
+
2793
 
+        return &map->priv->pa_map;
2794
 
+}
2795
 
+
2796
 
+const pa_cvolume *
2797
 
+gvc_channel_map_get_cvolume (const GvcChannelMap  *map)
2798
 
+{
2799
 
+        g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
2800
 
+
2801
 
+        if (!pa_channel_map_valid(&map->priv->pa_map))
2802
 
+                return NULL;
2803
 
+
2804
 
+        return &map->priv->pa_volume;
2805
 
+}
2806
 
+
2807
 
+static void
2808
 
+gvc_channel_map_class_init (GvcChannelMapClass *klass)
2809
 
+{
2810
 
+        GObjectClass   *gobject_class = G_OBJECT_CLASS (klass);
2811
 
+
2812
 
+        gobject_class->finalize = gvc_channel_map_finalize;
2813
 
+
2814
 
+        signals [VOLUME_CHANGED] =
2815
 
+                g_signal_new ("volume-changed",
2816
 
+                              G_TYPE_FROM_CLASS (klass),
2817
 
+                              G_SIGNAL_RUN_LAST,
2818
 
+                              G_STRUCT_OFFSET (GvcChannelMapClass, volume_changed),
2819
 
+                              NULL, NULL,
2820
 
+                              g_cclosure_marshal_VOID__BOOLEAN,
2821
 
+                              G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
2822
 
+
2823
 
+        g_type_class_add_private (klass, sizeof (GvcChannelMapPrivate));
2824
 
+}
2825
 
+
2826
 
+void
2827
 
+gvc_channel_map_volume_changed (GvcChannelMap     *map,
2828
 
+                                const pa_cvolume  *cv,
2829
 
+                                gboolean           set)
2830
 
+{
2831
 
+        g_return_if_fail (GVC_IS_CHANNEL_MAP (map));
2832
 
+        g_return_if_fail (cv != NULL);
2833
 
+        g_return_if_fail (pa_cvolume_compatible_with_channel_map(cv, &map->priv->pa_map));
2834
 
+
2835
 
+        if (pa_cvolume_equal(cv, &map->priv->pa_volume))
2836
 
+                return;
2837
 
+
2838
 
+        map->priv->pa_volume = *cv;
2839
 
+
2840
 
+        if (map->priv->pa_volume_is_set == FALSE) {
2841
 
+                map->priv->pa_volume_is_set = TRUE;
2842
 
+                return;
2843
 
+        }
2844
 
+        g_signal_emit (map, signals[VOLUME_CHANGED], 0, set);
2845
 
+}
2846
 
+
2847
 
+static void
2848
 
+gvc_channel_map_init (GvcChannelMap *map)
2849
 
+{
2850
 
+        map->priv = GVC_CHANNEL_MAP_GET_PRIVATE (map);
2851
 
+        map->priv->pa_volume_is_set = FALSE;
2852
 
+}
2853
 
+
2854
 
+static void
2855
 
+gvc_channel_map_finalize (GObject *object)
2856
 
+{
2857
 
+        GvcChannelMap *channel_map;
2858
 
+
2859
 
+        g_return_if_fail (object != NULL);
2860
 
+        g_return_if_fail (GVC_IS_CHANNEL_MAP (object));
2861
 
+
2862
 
+        channel_map = GVC_CHANNEL_MAP (object);
2863
 
+
2864
 
+        g_return_if_fail (channel_map->priv != NULL);
2865
 
+
2866
 
+        G_OBJECT_CLASS (gvc_channel_map_parent_class)->finalize (object);
2867
 
+}
2868
 
+
2869
 
+GvcChannelMap *
2870
 
+gvc_channel_map_new (void)
2871
 
+{
2872
 
+        GObject *map;
2873
 
+        map = g_object_new (GVC_TYPE_CHANNEL_MAP, NULL);
2874
 
+        return GVC_CHANNEL_MAP (map);
2875
 
+}
2876
 
+
2877
 
+static void
2878
 
+set_from_pa_map (GvcChannelMap        *map,
2879
 
+                 const pa_channel_map *pa_map)
2880
 
+{
2881
 
+        g_assert (pa_channel_map_valid(pa_map));
2882
 
+
2883
 
+        map->priv->can_balance = pa_channel_map_can_balance (pa_map);
2884
 
+        map->priv->can_fade = pa_channel_map_can_fade (pa_map);
2885
 
+
2886
 
+        map->priv->pa_map = *pa_map;
2887
 
+        pa_cvolume_set(&map->priv->pa_volume, pa_map->channels, PA_VOLUME_NORM);
2888
 
+}
2889
 
+
2890
 
+GvcChannelMap *
2891
 
+gvc_channel_map_new_from_pa_channel_map (const pa_channel_map *pa_map)
2892
 
+{
2893
 
+        GObject *map;
2894
 
+        map = g_object_new (GVC_TYPE_CHANNEL_MAP, NULL);
2895
 
+
2896
 
+        set_from_pa_map (GVC_CHANNEL_MAP (map), pa_map);
2897
 
+
2898
 
+        return GVC_CHANNEL_MAP (map);
2899
 
+}
2900
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-channel-map.h
2901
 
===================================================================
2902
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2903
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-channel-map.h       2012-08-28 17:08:49.440516899 +0200
2904
 
@@ -0,0 +1,73 @@
2905
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2906
 
+ *
2907
 
+ * Copyright (C) 2008 Red Hat, Inc.
2908
 
+ *
2909
 
+ * This program is free software; you can redistribute it and/or modify
2910
 
+ * it under the terms of the GNU General Public License as published by
2911
 
+ * the Free Software Foundation; either version 2 of the License, or
2912
 
+ * (at your option) any later version.
2913
 
+ *
2914
 
+ * This program is distributed in the hope that it will be useful,
2915
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2916
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2917
 
+ * GNU General Public License for more details.
2918
 
+ *
2919
 
+ * You should have received a copy of the GNU General Public License
2920
 
+ * along with this program; if not, write to the Free Software
2921
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2922
 
+ *
2923
 
+ */
2924
 
+
2925
 
+#ifndef __GVC_CHANNEL_MAP_H
2926
 
+#define __GVC_CHANNEL_MAP_H
2927
 
+
2928
 
+#include <glib-object.h>
2929
 
+#include <gvc-pulseaudio-fake.h>
2930
 
+
2931
 
+G_BEGIN_DECLS
2932
 
+
2933
 
+#define GVC_TYPE_CHANNEL_MAP         (gvc_channel_map_get_type ())
2934
 
+#define GVC_CHANNEL_MAP(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMap))
2935
 
+#define GVC_CHANNEL_MAP_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_CHANNEL_MAP, GvcChannelMapClass))
2936
 
+#define GVC_IS_CHANNEL_MAP(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_CHANNEL_MAP))
2937
 
+#define GVC_IS_CHANNEL_MAP_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_CHANNEL_MAP))
2938
 
+#define GVC_CHANNEL_MAP_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMapClass))
2939
 
+
2940
 
+typedef struct GvcChannelMapPrivate GvcChannelMapPrivate;
2941
 
+
2942
 
+typedef struct
2943
 
+{
2944
 
+        GObject               parent;
2945
 
+        GvcChannelMapPrivate *priv;
2946
 
+} GvcChannelMap;
2947
 
+
2948
 
+typedef struct
2949
 
+{
2950
 
+        GObjectClass           parent_class;
2951
 
+        void (*volume_changed) (GvcChannelMap *channel_map, gboolean set);
2952
 
+} GvcChannelMapClass;
2953
 
+
2954
 
+enum {
2955
 
+        VOLUME,
2956
 
+        BALANCE,
2957
 
+        FADE,
2958
 
+        LFE,
2959
 
+        NUM_TYPES
2960
 
+};
2961
 
+
2962
 
+GType                   gvc_channel_map_get_type                (void);
2963
 
+
2964
 
+GvcChannelMap *         gvc_channel_map_new                     (void);
2965
 
+guint                   gvc_channel_map_get_num_channels        (const GvcChannelMap  *map);
2966
 
+const gdouble *         gvc_channel_map_get_volume              (GvcChannelMap  *map);
2967
 
+gboolean                gvc_channel_map_can_balance             (const GvcChannelMap  *map);
2968
 
+gboolean                gvc_channel_map_can_fade                (const GvcChannelMap  *map);
2969
 
+gboolean                gvc_channel_map_has_position            (const GvcChannelMap  *map,
2970
 
+                                                                 pa_channel_position_t position);
2971
 
+#define                 gvc_channel_map_has_lfe(x)              gvc_channel_map_has_position (x, PA_CHANNEL_POSITION_LFE)
2972
 
+
2973
 
+const char *            gvc_channel_map_get_mapping             (const GvcChannelMap  *map);
2974
 
+
2975
 
+G_END_DECLS
2976
 
+
2977
 
+#endif /* __GVC_CHANNEL_MAP_H */
2978
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-combo-box.c
2979
 
===================================================================
2980
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
2981
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-combo-box.c 2012-08-28 17:08:49.440516899 +0200
2982
 
@@ -0,0 +1,410 @@
2983
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2984
 
+ *
2985
 
+ * Copyright (C) 2009 Bastien Nocera
2986
 
+ *
2987
 
+ * This program is free software; you can redistribute it and/or modify
2988
 
+ * it under the terms of the GNU General Public License as published by
2989
 
+ * the Free Software Foundation; either version 2 of the License, or
2990
 
+ * (at your option) any later version.
2991
 
+ *
2992
 
+ * This program is distributed in the hope that it will be useful,
2993
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2994
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2995
 
+ * GNU General Public License for more details.
2996
 
+ *
2997
 
+ * You should have received a copy of the GNU General Public License
2998
 
+ * along with this program; if not, write to the Free Software
2999
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3000
 
+ *
3001
 
+ */
3002
 
+
3003
 
+#include "config.h"
3004
 
+
3005
 
+#include <stdlib.h>
3006
 
+#include <stdio.h>
3007
 
+#include <unistd.h>
3008
 
+
3009
 
+#include <glib.h>
3010
 
+#include <glib/gi18n-lib.h>
3011
 
+#include <gtk/gtk.h>
3012
 
+#include <canberra-gtk.h>
3013
 
+#include <pulse/pulseaudio.h>
3014
 
+
3015
 
+#include "gvc-combo-box.h"
3016
 
+#include "gvc-mixer-stream.h"
3017
 
+#include "gvc-mixer-card.h"
3018
 
+
3019
 
+#define GVC_COMBO_BOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_COMBO_BOX, GvcComboBoxPrivate))
3020
 
+
3021
 
+struct GvcComboBoxPrivate
3022
 
+{
3023
 
+        GtkWidget     *drop_box;
3024
 
+        GtkWidget     *start_box;
3025
 
+        GtkWidget     *end_box;
3026
 
+        GtkWidget     *label;
3027
 
+        GtkWidget     *button;
3028
 
+        GtkTreeModel  *model;
3029
 
+        GtkWidget     *combobox;
3030
 
+        gboolean       set_called;
3031
 
+        GtkSizeGroup  *size_group;
3032
 
+        gboolean       symmetric;
3033
 
+};
3034
 
+
3035
 
+enum {
3036
 
+        COL_NAME,
3037
 
+        COL_HUMAN_NAME,
3038
 
+        NUM_COLS
3039
 
+};
3040
 
+
3041
 
+enum {
3042
 
+        CHANGED,
3043
 
+        BUTTON_CLICKED,
3044
 
+        LAST_SIGNAL
3045
 
+};
3046
 
+
3047
 
+enum {
3048
 
+        PROP_0,
3049
 
+        PROP_LABEL,
3050
 
+        PROP_SHOW_BUTTON,
3051
 
+        PROP_BUTTON_LABEL
3052
 
+};
3053
 
+
3054
 
+static guint signals [LAST_SIGNAL] = { 0, };
3055
 
+
3056
 
+static void     gvc_combo_box_class_init (GvcComboBoxClass *klass);
3057
 
+static void     gvc_combo_box_init       (GvcComboBox      *combo_box);
3058
 
+static void     gvc_combo_box_finalize   (GObject            *object);
3059
 
+
3060
 
+G_DEFINE_TYPE (GvcComboBox, gvc_combo_box, GTK_TYPE_HBOX)
3061
 
+
3062
 
+void
3063
 
+gvc_combo_box_set_size_group (GvcComboBox *combo_box,
3064
 
+                              GtkSizeGroup  *group,
3065
 
+                              gboolean       symmetric)
3066
 
+{
3067
 
+        g_return_if_fail (GVC_IS_COMBO_BOX (combo_box));
3068
 
+
3069
 
+        combo_box->priv->size_group = group;
3070
 
+        combo_box->priv->symmetric = symmetric;
3071
 
+
3072
 
+        if (combo_box->priv->size_group != NULL) {
3073
 
+                gtk_size_group_add_widget (combo_box->priv->size_group,
3074
 
+                                           combo_box->priv->start_box);
3075
 
+
3076
 
+                if (combo_box->priv->symmetric) {
3077
 
+                        gtk_size_group_add_widget (combo_box->priv->size_group,
3078
 
+                                                   combo_box->priv->end_box);
3079
 
+                }
3080
 
+        }
3081
 
+        gtk_widget_queue_draw (GTK_WIDGET (combo_box));
3082
 
+}
3083
 
+
3084
 
+static void
3085
 
+gvc_combo_box_set_property (GObject       *object,
3086
 
+                            guint          prop_id,
3087
 
+                            const GValue  *value,
3088
 
+                            GParamSpec    *pspec)
3089
 
+{
3090
 
+        GvcComboBox *self = GVC_COMBO_BOX (object);
3091
 
+
3092
 
+        switch (prop_id) {
3093
 
+        case PROP_LABEL:
3094
 
+                gtk_label_set_text_with_mnemonic (GTK_LABEL (self->priv->label), g_value_get_string (value));
3095
 
+                break;
3096
 
+        case PROP_BUTTON_LABEL:
3097
 
+                gtk_button_set_label (GTK_BUTTON (self->priv->button), g_value_get_string (value));
3098
 
+                break;
3099
 
+        case PROP_SHOW_BUTTON:
3100
 
+                gtk_widget_set_visible (self->priv->button, g_value_get_boolean (value));
3101
 
+                break;
3102
 
+        default:
3103
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3104
 
+                break;
3105
 
+        }
3106
 
+}
3107
 
+
3108
 
+static void
3109
 
+gvc_combo_box_get_property (GObject     *object,
3110
 
+                            guint        prop_id,
3111
 
+                            GValue      *value,
3112
 
+                            GParamSpec  *pspec)
3113
 
+{
3114
 
+        GvcComboBox *self = GVC_COMBO_BOX (object);
3115
 
+
3116
 
+        switch (prop_id) {
3117
 
+        case PROP_LABEL:
3118
 
+                g_value_set_string (value,
3119
 
+                                    gtk_label_get_text (GTK_LABEL (self->priv->label)));
3120
 
+                break;
3121
 
+        case PROP_BUTTON_LABEL:
3122
 
+                g_value_set_string (value,
3123
 
+                                    gtk_button_get_label (GTK_BUTTON (self->priv->button)));
3124
 
+                break;
3125
 
+        case PROP_SHOW_BUTTON:
3126
 
+                g_value_set_boolean (value,
3127
 
+                                     gtk_widget_get_visible (self->priv->button));
3128
 
+                break;
3129
 
+        default:
3130
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3131
 
+                break;
3132
 
+        }
3133
 
+}
3134
 
+
3135
 
+static void
3136
 
+gvc_combo_box_class_init (GvcComboBoxClass *klass)
3137
 
+{
3138
 
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
3139
 
+
3140
 
+        object_class->finalize = gvc_combo_box_finalize;
3141
 
+        object_class->set_property = gvc_combo_box_set_property;
3142
 
+        object_class->get_property = gvc_combo_box_get_property;
3143
 
+
3144
 
+        g_object_class_install_property (object_class,
3145
 
+                                         PROP_LABEL,
3146
 
+                                         g_param_spec_string ("label",
3147
 
+                                                              "label",
3148
 
+                                                              "The combo box label",
3149
 
+                                                              _("_Profile:"),
3150
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
3151
 
+        g_object_class_install_property (object_class,
3152
 
+                                         PROP_SHOW_BUTTON,
3153
 
+                                         g_param_spec_boolean ("show-button",
3154
 
+                                                               "show-button",
3155
 
+                                                               "Whether to show the button",
3156
 
+                                                               FALSE,
3157
 
+                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
3158
 
+        g_object_class_install_property (object_class,
3159
 
+                                         PROP_BUTTON_LABEL,
3160
 
+                                         g_param_spec_string ("button-label",
3161
 
+                                                              "button-label",
3162
 
+                                                              "The button's label",
3163
 
+                                                              "APPLICATION BUG",
3164
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
3165
 
+        signals [CHANGED] =
3166
 
+                g_signal_new ("changed",
3167
 
+                              G_TYPE_FROM_CLASS (klass),
3168
 
+                              G_SIGNAL_RUN_LAST,
3169
 
+                              G_STRUCT_OFFSET (GvcComboBoxClass, changed),
3170
 
+                              NULL, NULL,
3171
 
+                              g_cclosure_marshal_VOID__STRING,
3172
 
+                              G_TYPE_NONE, 1, G_TYPE_STRING);
3173
 
+        signals [BUTTON_CLICKED] =
3174
 
+                g_signal_new ("button-clicked",
3175
 
+                              G_TYPE_FROM_CLASS (klass),
3176
 
+                              G_SIGNAL_RUN_LAST,
3177
 
+                              G_STRUCT_OFFSET (GvcComboBoxClass, button_clicked),
3178
 
+                              NULL, NULL,
3179
 
+                              g_cclosure_marshal_VOID__VOID,
3180
 
+                              G_TYPE_NONE, 0, G_TYPE_NONE);
3181
 
+
3182
 
+        g_type_class_add_private (klass, sizeof (GvcComboBoxPrivate));
3183
 
+}
3184
 
+
3185
 
+void
3186
 
+gvc_combo_box_set_profiles (GvcComboBox *combo_box,
3187
 
+                            const GHashTable* profiles)
3188
 
+{
3189
 
+        g_return_if_fail (GVC_IS_COMBO_BOX (combo_box));
3190
 
+        g_return_if_fail (combo_box->priv->set_called == FALSE);
3191
 
+
3192
 
+        const GList *l;
3193
 
+        const GList *keys;
3194
 
+
3195
 
+        keys = g_hash_table_get_keys (profiles);
3196
 
+
3197
 
+        for (l = keys; l != NULL; l = l->next) {
3198
 
+                gchar* k;
3199
 
+                GvcMixerCardProfile *p;
3200
 
+                k = l->data;
3201
 
+                
3202
 
+                p = g_hash_table_lookup (profiles, k);
3203
 
+                g_debug ("set profiles - key %s \n profile %s \n human profile %s",
3204
 
+                         k,
3205
 
+                         p->profile,
3206
 
+                         p->human_profile);
3207
 
+
3208
 
+                gtk_list_store_insert_with_values (GTK_LIST_STORE (combo_box->priv->model),
3209
 
+                                                   NULL,
3210
 
+                                                   G_MAXINT,
3211
 
+                                                   COL_NAME, p->profile,
3212
 
+                                                   COL_HUMAN_NAME, p->human_profile,
3213
 
+                                                   -1);
3214
 
+        }
3215
 
+        combo_box->priv->set_called = TRUE;
3216
 
+}
3217
 
+
3218
 
+void
3219
 
+gvc_combo_box_set_ports (GvcComboBox *combo_box,
3220
 
+                         const GList       *ports)
3221
 
+{
3222
 
+        const GList *l;
3223
 
+
3224
 
+        g_return_if_fail (GVC_IS_COMBO_BOX (combo_box));
3225
 
+        g_return_if_fail (combo_box->priv->set_called == FALSE);
3226
 
+
3227
 
+        for (l = ports; l != NULL; l = l->next) {
3228
 
+                GvcMixerStreamPort *p = l->data;
3229
 
+
3230
 
+                gtk_list_store_insert_with_values (GTK_LIST_STORE (combo_box->priv->model),
3231
 
+                                                   NULL,
3232
 
+                                                   G_MAXINT,
3233
 
+                                                   COL_NAME, p->port,
3234
 
+                                                   COL_HUMAN_NAME, p->human_port,
3235
 
+                                                   -1);
3236
 
+        }
3237
 
+        combo_box->priv->set_called = TRUE;
3238
 
+}
3239
 
+
3240
 
+void
3241
 
+gvc_combo_box_set_active (GvcComboBox *combo_box,
3242
 
+                          const char  *id)
3243
 
+{
3244
 
+        GtkTreeIter iter;
3245
 
+        gboolean cont;
3246
 
+
3247
 
+        cont = gtk_tree_model_get_iter_first (combo_box->priv->model, &iter);
3248
 
+        while (cont != FALSE) {
3249
 
+                char *name;
3250
 
+
3251
 
+                gtk_tree_model_get (combo_box->priv->model, &iter,
3252
 
+                                    COL_NAME, &name,
3253
 
+                                    -1);
3254
 
+                if (g_strcmp0 (name, id) == 0) {
3255
 
+                        gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box->priv->combobox), &iter);
3256
 
+                        return;
3257
 
+                }
3258
 
+                cont = gtk_tree_model_iter_next (combo_box->priv->model, &iter);
3259
 
+        }
3260
 
+        g_warning ("Could not find id '%s' in combo box", id);
3261
 
+}
3262
 
+
3263
 
+static void
3264
 
+on_combo_box_changed (GtkComboBox *widget,
3265
 
+                      GvcComboBox *combo_box)
3266
 
+{
3267
 
+        GtkTreeIter          iter;
3268
 
+        char                *profile;
3269
 
+
3270
 
+        if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter) == FALSE) {
3271
 
+                g_warning ("Could not find an active profile or port");
3272
 
+                return;
3273
 
+        }
3274
 
+
3275
 
+        gtk_tree_model_get (combo_box->priv->model, &iter,
3276
 
+                            COL_NAME, &profile,
3277
 
+                            -1);
3278
 
+        g_signal_emit (combo_box, signals[CHANGED], 0, profile);
3279
 
+        g_free (profile);
3280
 
+}
3281
 
+
3282
 
+static void
3283
 
+on_combo_box_button_clicked (GtkButton   *button,
3284
 
+                             GvcComboBox *combo_box)
3285
 
+{
3286
 
+        g_signal_emit (combo_box, signals[BUTTON_CLICKED], 0);
3287
 
+}
3288
 
+
3289
 
+static void
3290
 
+gvc_combo_box_init (GvcComboBox *combo_box)
3291
 
+{
3292
 
+        GtkWidget *frame;
3293
 
+        GtkWidget            *box;
3294
 
+        GtkWidget            *sbox;
3295
 
+        GtkWidget            *ebox;
3296
 
+        GtkCellRenderer      *renderer;
3297
 
+
3298
 
+        combo_box->priv = GVC_COMBO_BOX_GET_PRIVATE (combo_box);
3299
 
+
3300
 
+        combo_box->priv->model = GTK_TREE_MODEL (gtk_list_store_new (NUM_COLS,
3301
 
+                                                                     G_TYPE_STRING,
3302
 
+                                                                     G_TYPE_STRING));
3303
 
+
3304
 
+        combo_box->priv->label = gtk_label_new (NULL);
3305
 
+        gtk_misc_set_alignment (GTK_MISC (combo_box->priv->label),
3306
 
+                                0.0,
3307
 
+                                0.5);
3308
 
+
3309
 
+        /* frame */
3310
 
+        frame = gtk_frame_new (NULL);
3311
 
+        gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
3312
 
+        gtk_container_add (GTK_CONTAINER (combo_box), frame);
3313
 
+
3314
 
+        combo_box->priv->drop_box = box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
3315
 
+        combo_box->priv->combobox = gtk_combo_box_new_with_model (combo_box->priv->model);
3316
 
+                
3317
 
+        renderer = gtk_cell_renderer_text_new ();
3318
 
+        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box->priv->combobox),
3319
 
+                                    renderer, TRUE);
3320
 
+        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->combobox),
3321
 
+                                       renderer,
3322
 
+                                       "text", COL_HUMAN_NAME);
3323
 
+
3324
 
+        /* Make sure that the combo box isn't too wide when human names are overly long,
3325
 
+         * but that we can still read the full length of it */
3326
 
+        g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
3327
 
+        gtk_cell_renderer_set_fixed_size (renderer, 5, -1);        
3328
 
+        g_object_set (G_OBJECT (combo_box->priv->combobox), "popup-fixed-width", FALSE, NULL);
3329
 
+
3330
 
+        combo_box->priv->start_box = sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
3331
 
+        gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0);
3332
 
+
3333
 
+        gtk_box_pack_start (GTK_BOX (sbox), combo_box->priv->label, FALSE, FALSE, 0);
3334
 
+
3335
 
+        gtk_box_pack_start (GTK_BOX (box), combo_box->priv->combobox, TRUE, TRUE, 0);
3336
 
+
3337
 
+        combo_box->priv->button = gtk_button_new_with_label ("APPLICATION BUG");
3338
 
+        gtk_button_set_use_underline (GTK_BUTTON (combo_box->priv->button), TRUE);
3339
 
+        gtk_widget_set_no_show_all (combo_box->priv->button, TRUE);
3340
 
+        gtk_box_pack_start (GTK_BOX (box), combo_box->priv->button, FALSE, FALSE, 0);
3341
 
+
3342
 
+        combo_box->priv->end_box = ebox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
3343
 
+        gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0);
3344
 
+
3345
 
+        if (combo_box->priv->size_group != NULL) {
3346
 
+                gtk_size_group_add_widget (combo_box->priv->size_group, sbox);
3347
 
+
3348
 
+                if (combo_box->priv->symmetric) {
3349
 
+                        gtk_size_group_add_widget (combo_box->priv->size_group, ebox);
3350
 
+                }
3351
 
+        }
3352
 
+
3353
 
+        gtk_container_add (GTK_CONTAINER (frame), combo_box->priv->drop_box);
3354
 
+        gtk_widget_show_all (frame);
3355
 
+
3356
 
+        gtk_label_set_mnemonic_widget (GTK_LABEL (combo_box->priv->label),
3357
 
+                                       combo_box->priv->combobox);
3358
 
+
3359
 
+        g_signal_connect (G_OBJECT (combo_box->priv->combobox), "changed",
3360
 
+                          G_CALLBACK (on_combo_box_changed), combo_box);
3361
 
+        g_signal_connect (G_OBJECT (combo_box->priv->button), "clicked",
3362
 
+                          G_CALLBACK (on_combo_box_button_clicked), combo_box);
3363
 
+}
3364
 
+
3365
 
+static void
3366
 
+gvc_combo_box_finalize (GObject *object)
3367
 
+{
3368
 
+        GvcComboBox *combo_box;
3369
 
+
3370
 
+        g_return_if_fail (object != NULL);
3371
 
+        g_return_if_fail (GVC_IS_COMBO_BOX (object));
3372
 
+
3373
 
+        combo_box = GVC_COMBO_BOX (object);
3374
 
+
3375
 
+        g_return_if_fail (combo_box->priv != NULL);
3376
 
+
3377
 
+        g_object_unref (combo_box->priv->model);
3378
 
+        combo_box->priv->model = NULL;
3379
 
+
3380
 
+        G_OBJECT_CLASS (gvc_combo_box_parent_class)->finalize (object);
3381
 
+}
3382
 
+
3383
 
+GtkWidget *
3384
 
+gvc_combo_box_new (const char *label)
3385
 
+{
3386
 
+        GObject *combo_box;
3387
 
+        combo_box = g_object_new (GVC_TYPE_COMBO_BOX,
3388
 
+                                  "label", label,
3389
 
+                                  NULL);
3390
 
+        return GTK_WIDGET (combo_box);
3391
 
+}
3392
 
+
3393
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-combo-box.h
3394
 
===================================================================
3395
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
3396
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-combo-box.h 2012-08-28 17:08:49.440516899 +0200
3397
 
@@ -0,0 +1,66 @@
3398
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3399
 
+ *
3400
 
+ * Copyright (C) 2009 Red Hat, Inc.
3401
 
+ *
3402
 
+ * This program is free software; you can redistribute it and/or modify
3403
 
+ * it under the terms of the GNU General Public License as published by
3404
 
+ * the Free Software Foundation; either version 2 of the License, or
3405
 
+ * (at your option) any later version.
3406
 
+ *
3407
 
+ * This program is distributed in the hope that it will be useful,
3408
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3409
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3410
 
+ * GNU General Public License for more details.
3411
 
+ *
3412
 
+ * You should have received a copy of the GNU General Public License
3413
 
+ * along with this program; if not, write to the Free Software
3414
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3415
 
+ *
3416
 
+ */
3417
 
+
3418
 
+#ifndef __GVC_COMBO_BOX_H
3419
 
+#define __GVC_COMBO_BOX_H
3420
 
+
3421
 
+#include <glib-object.h>
3422
 
+
3423
 
+G_BEGIN_DECLS
3424
 
+
3425
 
+#define GVC_TYPE_COMBO_BOX         (gvc_combo_box_get_type ())
3426
 
+#define GVC_COMBO_BOX(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_COMBO_BOX, GvcComboBox))
3427
 
+#define GVC_COMBO_BOX_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_COMBO_BOX, GvcComboBoxClass))
3428
 
+#define GVC_IS_COMBO_BOX(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_COMBO_BOX))
3429
 
+#define GVC_IS_COMBO_BOX_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_COMBO_BOX))
3430
 
+#define GVC_COMBO_BOX_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_COMBO_BOX, GvcComboBoxClass))
3431
 
+
3432
 
+typedef struct GvcComboBoxPrivate GvcComboBoxPrivate;
3433
 
+
3434
 
+typedef struct
3435
 
+{
3436
 
+        GtkHBox               parent;
3437
 
+        GvcComboBoxPrivate *priv;
3438
 
+} GvcComboBox;
3439
 
+
3440
 
+typedef struct
3441
 
+{
3442
 
+        GtkHBoxClass            parent_class;
3443
 
+        void (* changed)        (GvcComboBox *combobox, const char *name);
3444
 
+        void (* button_clicked) (GvcComboBox *combobox);
3445
 
+} GvcComboBoxClass;
3446
 
+
3447
 
+GType                   gvc_combo_box_get_type            (void);
3448
 
+
3449
 
+GtkWidget *             gvc_combo_box_new                 (const char   *label);
3450
 
+
3451
 
+void                    gvc_combo_box_set_size_group      (GvcComboBox  *combo_box,
3452
 
+                                                           GtkSizeGroup *group,
3453
 
+                                                           gboolean      symmetric);
3454
 
+
3455
 
+void                    gvc_combo_box_set_profiles        (GvcComboBox  *combo_box,
3456
 
+                                                          const GHashTable  *profiles);
3457
 
+void                    gvc_combo_box_set_ports           (GvcComboBox  *combo_box,
3458
 
+                                                            const GList  *ports);
3459
 
+void                    gvc_combo_box_set_active          (GvcComboBox  *combo_box,
3460
 
+                                                           const char   *id);
3461
 
+G_END_DECLS
3462
 
+
3463
 
+#endif /* __GVC_COMBO_BOX_H */
3464
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-level-bar.c
3465
 
===================================================================
3466
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
3467
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-level-bar.c 2012-08-28 17:08:49.444516900 +0200
3468
 
@@ -0,0 +1,770 @@
3469
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3470
 
+ *
3471
 
+ * Copyright (C) 2008 William Jon McCann <william.jon.mccann@gmail.com>
3472
 
+ *
3473
 
+ * This program is free software; you can redistribute it and/or modify
3474
 
+ * it under the terms of the GNU General Public License as published by
3475
 
+ * the Free Software Foundation; either version 2 of the License, or
3476
 
+ * (at your option) any later version.
3477
 
+ *
3478
 
+ * This program is distributed in the hope that it will be useful,
3479
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3480
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3481
 
+ * GNU General Public License for more details.
3482
 
+ *
3483
 
+ * You should have received a copy of the GNU General Public License
3484
 
+ * along with this program; if not, write to the Free Software
3485
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3486
 
+ *
3487
 
+ */
3488
 
+
3489
 
+#include "config.h"
3490
 
+
3491
 
+#include <stdlib.h>
3492
 
+#include <stdio.h>
3493
 
+#include <unistd.h>
3494
 
+#include <math.h>
3495
 
+
3496
 
+#include <glib.h>
3497
 
+#include <glib/gi18n-lib.h>
3498
 
+#include <gtk/gtk.h>
3499
 
+
3500
 
+#include "gvc-level-bar.h"
3501
 
+
3502
 
+#define NUM_BOXES 30
3503
 
+
3504
 
+#define GVC_LEVEL_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_LEVEL_BAR, GvcLevelBarPrivate))
3505
 
+
3506
 
+#define MIN_HORIZONTAL_BAR_WIDTH   150
3507
 
+#define HORIZONTAL_BAR_HEIGHT      6
3508
 
+#define VERTICAL_BAR_WIDTH         6
3509
 
+#define MIN_VERTICAL_BAR_HEIGHT    400
3510
 
+
3511
 
+typedef struct {
3512
 
+        int          peak_num;
3513
 
+        int          max_peak_num;
3514
 
+
3515
 
+        GdkRectangle area;
3516
 
+        int          delta;
3517
 
+        int          box_width;
3518
 
+        int          box_height;
3519
 
+        int          box_radius;
3520
 
+        double       bg_r;
3521
 
+        double       bg_g;
3522
 
+        double       bg_b;
3523
 
+        double       bdr_r;
3524
 
+        double       bdr_g;
3525
 
+        double       bdr_b;
3526
 
+        double       fl_r;
3527
 
+        double       fl_g;
3528
 
+        double       fl_b;
3529
 
+} LevelBarLayout;
3530
 
+
3531
 
+struct GvcLevelBarPrivate
3532
 
+{
3533
 
+        GtkOrientation orientation;
3534
 
+        GtkAdjustment *peak_adjustment;
3535
 
+        GtkAdjustment *rms_adjustment;
3536
 
+        int            scale;
3537
 
+        gdouble        peak_fraction;
3538
 
+        gdouble        rms_fraction;
3539
 
+        gdouble        max_peak;
3540
 
+        guint          max_peak_id;
3541
 
+        LevelBarLayout layout;
3542
 
+};
3543
 
+
3544
 
+enum
3545
 
+{
3546
 
+        PROP_0,
3547
 
+        PROP_PEAK_ADJUSTMENT,
3548
 
+        PROP_RMS_ADJUSTMENT,
3549
 
+        PROP_SCALE,
3550
 
+        PROP_ORIENTATION,
3551
 
+};
3552
 
+
3553
 
+static void     gvc_level_bar_class_init (GvcLevelBarClass *klass);
3554
 
+static void     gvc_level_bar_init       (GvcLevelBar      *level_bar);
3555
 
+static void     gvc_level_bar_finalize   (GObject            *object);
3556
 
+
3557
 
+G_DEFINE_TYPE (GvcLevelBar, gvc_level_bar, GTK_TYPE_WIDGET)
3558
 
+
3559
 
+#define check_rectangle(rectangle1, rectangle2)                          \
3560
 
+        {                                                                \
3561
 
+                /* .x and .y are always 0 */                             \
3562
 
+                if (rectangle1.width  != rectangle2.width)  return TRUE; \
3563
 
+                if (rectangle1.height != rectangle2.height) return TRUE; \
3564
 
+        }
3565
 
+
3566
 
+static gboolean
3567
 
+layout_changed (LevelBarLayout *layout1,
3568
 
+                LevelBarLayout *layout2)
3569
 
+{
3570
 
+        check_rectangle (layout1->area, layout2->area);
3571
 
+        if (layout1->delta != layout2->delta) return TRUE;
3572
 
+        if (layout1->peak_num != layout2->peak_num) return TRUE;
3573
 
+        if (layout1->max_peak_num != layout2->max_peak_num) return TRUE;
3574
 
+        if (layout1->bg_r != layout2->bg_r
3575
 
+            || layout1->bg_g != layout2->bg_g
3576
 
+            || layout1->bg_b != layout2->bg_b)
3577
 
+                return TRUE;
3578
 
+        if (layout1->bdr_r != layout2->bdr_r
3579
 
+            || layout1->bdr_g != layout2->bdr_g
3580
 
+            || layout1->bdr_b != layout2->bdr_b)
3581
 
+                return TRUE;
3582
 
+        if (layout1->fl_r != layout2->fl_r
3583
 
+            || layout1->fl_g != layout2->fl_g
3584
 
+            || layout1->fl_b != layout2->fl_b)
3585
 
+                return TRUE;
3586
 
+
3587
 
+        return FALSE;
3588
 
+}
3589
 
+
3590
 
+static gdouble
3591
 
+fraction_from_adjustment (GvcLevelBar   *bar,
3592
 
+                          GtkAdjustment *adjustment)
3593
 
+{
3594
 
+        gdouble level;
3595
 
+        gdouble fraction;
3596
 
+        gdouble min;
3597
 
+        gdouble max;
3598
 
+
3599
 
+        level = gtk_adjustment_get_value (adjustment);
3600
 
+
3601
 
+        min = gtk_adjustment_get_lower (adjustment);
3602
 
+        max = gtk_adjustment_get_upper (adjustment);
3603
 
+
3604
 
+        switch (bar->priv->scale) {
3605
 
+        case GVC_LEVEL_SCALE_LINEAR:
3606
 
+                fraction = (level - min) / (max - min);
3607
 
+                break;
3608
 
+        case GVC_LEVEL_SCALE_LOG:
3609
 
+                fraction = log10 ((level - min + 1) / (max - min + 1));
3610
 
+                break;
3611
 
+        default:
3612
 
+                g_assert_not_reached ();
3613
 
+        }
3614
 
+
3615
 
+        return fraction;
3616
 
+}
3617
 
+
3618
 
+static gboolean
3619
 
+reset_max_peak (GvcLevelBar *bar)
3620
 
+{
3621
 
+        gdouble min;
3622
 
+
3623
 
+        min = gtk_adjustment_get_lower (bar->priv->peak_adjustment);
3624
 
+        bar->priv->max_peak = min;
3625
 
+        bar->priv->layout.max_peak_num = 0;
3626
 
+        gtk_widget_queue_draw (GTK_WIDGET (bar));
3627
 
+        bar->priv->max_peak_id = 0;
3628
 
+        return FALSE;
3629
 
+}
3630
 
+
3631
 
+static void
3632
 
+bar_calc_layout (GvcLevelBar *bar)
3633
 
+{
3634
 
+        GdkColor color;
3635
 
+        int      peak_level;
3636
 
+        int      max_peak_level;
3637
 
+        GtkAllocation allocation;
3638
 
+        GtkStyle *style;
3639
 
+
3640
 
+        gtk_widget_get_allocation (GTK_WIDGET (bar), &allocation);
3641
 
+        bar->priv->layout.area.width = allocation.width - 2;
3642
 
+        bar->priv->layout.area.height = allocation.height - 2;
3643
 
+
3644
 
+        style = gtk_widget_get_style (GTK_WIDGET (bar));
3645
 
+        color = style->bg [GTK_STATE_NORMAL];
3646
 
+        bar->priv->layout.bg_r = (float)color.red / 65535.0;
3647
 
+        bar->priv->layout.bg_g = (float)color.green / 65535.0;
3648
 
+        bar->priv->layout.bg_b = (float)color.blue / 65535.0;
3649
 
+        color = style->dark [GTK_STATE_NORMAL];
3650
 
+        bar->priv->layout.bdr_r = (float)color.red / 65535.0;
3651
 
+        bar->priv->layout.bdr_g = (float)color.green / 65535.0;
3652
 
+        bar->priv->layout.bdr_b = (float)color.blue / 65535.0;
3653
 
+        color = style->bg [GTK_STATE_SELECTED];
3654
 
+        bar->priv->layout.fl_r = (float)color.red / 65535.0;
3655
 
+        bar->priv->layout.fl_g = (float)color.green / 65535.0;
3656
 
+        bar->priv->layout.fl_b = (float)color.blue / 65535.0;
3657
 
+
3658
 
+        if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
3659
 
+                peak_level = bar->priv->peak_fraction * bar->priv->layout.area.height;
3660
 
+                max_peak_level = bar->priv->max_peak * bar->priv->layout.area.height;
3661
 
+
3662
 
+                bar->priv->layout.delta = bar->priv->layout.area.height / NUM_BOXES;
3663
 
+                bar->priv->layout.area.x = 0;
3664
 
+                bar->priv->layout.area.y = 0;
3665
 
+                bar->priv->layout.box_height = bar->priv->layout.delta / 2;
3666
 
+                bar->priv->layout.box_width = bar->priv->layout.area.width;
3667
 
+                bar->priv->layout.box_radius = bar->priv->layout.box_width / 2;
3668
 
+        } else {
3669
 
+                peak_level = bar->priv->peak_fraction * bar->priv->layout.area.width;
3670
 
+                max_peak_level = bar->priv->max_peak * bar->priv->layout.area.width;
3671
 
+
3672
 
+                bar->priv->layout.delta = bar->priv->layout.area.width / NUM_BOXES;
3673
 
+                bar->priv->layout.area.x = 0;
3674
 
+                bar->priv->layout.area.y = 0;
3675
 
+                bar->priv->layout.box_width = bar->priv->layout.delta / 2;
3676
 
+                bar->priv->layout.box_height = bar->priv->layout.area.height;
3677
 
+                bar->priv->layout.box_radius = bar->priv->layout.box_height / 2;
3678
 
+        }
3679
 
+
3680
 
+        /* This can happen if the level bar isn't realized */
3681
 
+        if (bar->priv->layout.delta == 0)
3682
 
+                return;
3683
 
+
3684
 
+        bar->priv->layout.peak_num = peak_level / bar->priv->layout.delta;
3685
 
+        bar->priv->layout.max_peak_num = max_peak_level / bar->priv->layout.delta;
3686
 
+}
3687
 
+
3688
 
+static void
3689
 
+update_peak_value (GvcLevelBar *bar)
3690
 
+{
3691
 
+        gdouble        val;
3692
 
+        LevelBarLayout layout;
3693
 
+
3694
 
+        layout = bar->priv->layout;
3695
 
+
3696
 
+        val = fraction_from_adjustment (bar, bar->priv->peak_adjustment);
3697
 
+        bar->priv->peak_fraction = val;
3698
 
+
3699
 
+        if (val > bar->priv->max_peak) {
3700
 
+                if (bar->priv->max_peak_id > 0) {
3701
 
+                        g_source_remove (bar->priv->max_peak_id);
3702
 
+                }
3703
 
+                bar->priv->max_peak_id = g_timeout_add_seconds (1, (GSourceFunc)reset_max_peak, bar);
3704
 
+                bar->priv->max_peak = val;
3705
 
+        }
3706
 
+
3707
 
+        bar_calc_layout (bar);
3708
 
+
3709
 
+        if (layout_changed (&bar->priv->layout, &layout)) {
3710
 
+                gtk_widget_queue_draw (GTK_WIDGET (bar));
3711
 
+        }
3712
 
+}
3713
 
+
3714
 
+static void
3715
 
+update_rms_value (GvcLevelBar *bar)
3716
 
+{
3717
 
+        gdouble val;
3718
 
+
3719
 
+        val = fraction_from_adjustment (bar, bar->priv->rms_adjustment);
3720
 
+        bar->priv->rms_fraction = val;
3721
 
+}
3722
 
+
3723
 
+GtkOrientation
3724
 
+gvc_level_bar_get_orientation (GvcLevelBar *bar)
3725
 
+{
3726
 
+        g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), 0);
3727
 
+        return bar->priv->orientation;
3728
 
+}
3729
 
+
3730
 
+void
3731
 
+gvc_level_bar_set_orientation (GvcLevelBar   *bar,
3732
 
+                               GtkOrientation orientation)
3733
 
+{
3734
 
+        g_return_if_fail (GVC_IS_LEVEL_BAR (bar));
3735
 
+
3736
 
+        if (orientation != bar->priv->orientation) {
3737
 
+                bar->priv->orientation = orientation;
3738
 
+                gtk_widget_queue_draw (GTK_WIDGET (bar));
3739
 
+                g_object_notify (G_OBJECT (bar), "orientation");
3740
 
+        }
3741
 
+}
3742
 
+
3743
 
+static void
3744
 
+on_peak_adjustment_value_changed (GtkAdjustment *adjustment,
3745
 
+                                  GvcLevelBar   *bar)
3746
 
+{
3747
 
+        update_peak_value (bar);
3748
 
+}
3749
 
+
3750
 
+static void
3751
 
+on_rms_adjustment_value_changed (GtkAdjustment *adjustment,
3752
 
+                                 GvcLevelBar   *bar)
3753
 
+{
3754
 
+        update_rms_value (bar);
3755
 
+}
3756
 
+
3757
 
+void
3758
 
+gvc_level_bar_set_peak_adjustment (GvcLevelBar   *bar,
3759
 
+                                   GtkAdjustment *adjustment)
3760
 
+{
3761
 
+        g_return_if_fail (GVC_LEVEL_BAR (bar));
3762
 
+        g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
3763
 
+
3764
 
+        if (bar->priv->peak_adjustment != NULL) {
3765
 
+                g_signal_handlers_disconnect_by_func (bar->priv->peak_adjustment,
3766
 
+                                                      G_CALLBACK (on_peak_adjustment_value_changed),
3767
 
+                                                      bar);
3768
 
+                g_object_unref (bar->priv->peak_adjustment);
3769
 
+        }
3770
 
+
3771
 
+        bar->priv->peak_adjustment = g_object_ref_sink (adjustment);
3772
 
+
3773
 
+        g_signal_connect (bar->priv->peak_adjustment,
3774
 
+                          "value-changed",
3775
 
+                          G_CALLBACK (on_peak_adjustment_value_changed),
3776
 
+                          bar);
3777
 
+
3778
 
+        update_peak_value (bar);
3779
 
+
3780
 
+        g_object_notify (G_OBJECT (bar), "peak-adjustment");
3781
 
+}
3782
 
+
3783
 
+void
3784
 
+gvc_level_bar_set_rms_adjustment (GvcLevelBar   *bar,
3785
 
+                                  GtkAdjustment *adjustment)
3786
 
+{
3787
 
+        g_return_if_fail (GVC_LEVEL_BAR (bar));
3788
 
+        g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
3789
 
+
3790
 
+        if (bar->priv->rms_adjustment != NULL) {
3791
 
+                g_signal_handlers_disconnect_by_func (bar->priv->peak_adjustment,
3792
 
+                                                      G_CALLBACK (on_rms_adjustment_value_changed),
3793
 
+                                                      bar);
3794
 
+                g_object_unref (bar->priv->rms_adjustment);
3795
 
+        }
3796
 
+
3797
 
+        bar->priv->rms_adjustment = g_object_ref_sink (adjustment);
3798
 
+
3799
 
+
3800
 
+        g_signal_connect (bar->priv->peak_adjustment,
3801
 
+                          "value-changed",
3802
 
+                          G_CALLBACK (on_peak_adjustment_value_changed),
3803
 
+                          bar);
3804
 
+
3805
 
+        update_rms_value (bar);
3806
 
+
3807
 
+        g_object_notify (G_OBJECT (bar), "rms-adjustment");
3808
 
+}
3809
 
+
3810
 
+GtkAdjustment *
3811
 
+gvc_level_bar_get_peak_adjustment (GvcLevelBar *bar)
3812
 
+{
3813
 
+        g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), NULL);
3814
 
+
3815
 
+        return bar->priv->peak_adjustment;
3816
 
+}
3817
 
+
3818
 
+GtkAdjustment *
3819
 
+gvc_level_bar_get_rms_adjustment (GvcLevelBar *bar)
3820
 
+{
3821
 
+        g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), NULL);
3822
 
+
3823
 
+        return bar->priv->rms_adjustment;
3824
 
+}
3825
 
+
3826
 
+void
3827
 
+gvc_level_bar_set_scale (GvcLevelBar  *bar,
3828
 
+                         GvcLevelScale scale)
3829
 
+{
3830
 
+        g_return_if_fail (GVC_IS_LEVEL_BAR (bar));
3831
 
+
3832
 
+        if (scale != bar->priv->scale) {
3833
 
+                bar->priv->scale = scale;
3834
 
+
3835
 
+                update_peak_value (bar);
3836
 
+                update_rms_value (bar);
3837
 
+
3838
 
+                g_object_notify (G_OBJECT (bar), "scale");
3839
 
+        }
3840
 
+}
3841
 
+
3842
 
+static void
3843
 
+gvc_level_bar_set_property (GObject       *object,
3844
 
+                              guint          prop_id,
3845
 
+                              const GValue  *value,
3846
 
+                              GParamSpec    *pspec)
3847
 
+{
3848
 
+        GvcLevelBar *self = GVC_LEVEL_BAR (object);
3849
 
+
3850
 
+        switch (prop_id) {
3851
 
+        case PROP_SCALE:
3852
 
+                gvc_level_bar_set_scale (self, g_value_get_int (value));
3853
 
+                break;
3854
 
+        case PROP_ORIENTATION:
3855
 
+                gvc_level_bar_set_orientation (self, g_value_get_enum (value));
3856
 
+                break;
3857
 
+        case PROP_PEAK_ADJUSTMENT:
3858
 
+                gvc_level_bar_set_peak_adjustment (self, g_value_get_object (value));
3859
 
+                break;
3860
 
+        case PROP_RMS_ADJUSTMENT:
3861
 
+                gvc_level_bar_set_rms_adjustment (self, g_value_get_object (value));
3862
 
+                break;
3863
 
+        default:
3864
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3865
 
+                break;
3866
 
+        }
3867
 
+}
3868
 
+
3869
 
+static void
3870
 
+gvc_level_bar_get_property (GObject     *object,
3871
 
+                              guint        prop_id,
3872
 
+                              GValue      *value,
3873
 
+                              GParamSpec  *pspec)
3874
 
+{
3875
 
+        GvcLevelBar *self = GVC_LEVEL_BAR (object);
3876
 
+
3877
 
+        switch (prop_id) {
3878
 
+        case PROP_SCALE:
3879
 
+                g_value_set_int (value, self->priv->scale);
3880
 
+                break;
3881
 
+        case PROP_ORIENTATION:
3882
 
+                g_value_set_enum (value, self->priv->orientation);
3883
 
+                break;
3884
 
+        case PROP_PEAK_ADJUSTMENT:
3885
 
+                g_value_set_object (value, self->priv->peak_adjustment);
3886
 
+                break;
3887
 
+        case PROP_RMS_ADJUSTMENT:
3888
 
+                g_value_set_object (value, self->priv->rms_adjustment);
3889
 
+                break;
3890
 
+        default:
3891
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3892
 
+                break;
3893
 
+        }
3894
 
+}
3895
 
+
3896
 
+static GObject *
3897
 
+gvc_level_bar_constructor (GType                  type,
3898
 
+                           guint                  n_construct_properties,
3899
 
+                           GObjectConstructParam *construct_params)
3900
 
+{
3901
 
+        return G_OBJECT_CLASS (gvc_level_bar_parent_class)->constructor (type, n_construct_properties, construct_params);
3902
 
+}
3903
 
+
3904
 
+static void
3905
 
+gvc_level_bar_size_request (GtkWidget      *widget,
3906
 
+                            GtkRequisition *requisition)
3907
 
+{
3908
 
+        GvcLevelBar *bar = GVC_LEVEL_BAR (widget);
3909
 
+
3910
 
+        switch (bar->priv->orientation) {
3911
 
+        case GTK_ORIENTATION_VERTICAL:
3912
 
+                requisition->width = VERTICAL_BAR_WIDTH;
3913
 
+                requisition->height = MIN_VERTICAL_BAR_HEIGHT;
3914
 
+                break;
3915
 
+        case GTK_ORIENTATION_HORIZONTAL:
3916
 
+                requisition->width = MIN_HORIZONTAL_BAR_WIDTH;
3917
 
+                requisition->height = HORIZONTAL_BAR_HEIGHT;
3918
 
+                break;
3919
 
+        default:
3920
 
+                g_assert_not_reached ();
3921
 
+                break;
3922
 
+        }
3923
 
+}
3924
 
+
3925
 
+static void
3926
 
+gvc_level_bar_get_preferred_width (GtkWidget *widget,
3927
 
+                                   gint      *minimum,
3928
 
+                                   gint      *natural)
3929
 
+{
3930
 
+        GtkRequisition requisition;
3931
 
+
3932
 
+        gvc_level_bar_size_request (widget, &requisition);
3933
 
+
3934
 
+        if (minimum != NULL) {
3935
 
+                *minimum = requisition.width;
3936
 
+        }
3937
 
+        if (natural != NULL) {
3938
 
+                *natural = requisition.width;
3939
 
+        }
3940
 
+}
3941
 
+
3942
 
+static void
3943
 
+gvc_level_bar_get_preferred_height (GtkWidget *widget,
3944
 
+                                    gint      *minimum,
3945
 
+                                    gint      *natural)
3946
 
+{
3947
 
+        GtkRequisition requisition;
3948
 
+
3949
 
+        gvc_level_bar_size_request (widget, &requisition);
3950
 
+
3951
 
+        if (minimum != NULL) {
3952
 
+                *minimum = requisition.height;
3953
 
+        }
3954
 
+        if (natural != NULL) {
3955
 
+                *natural = requisition.height;
3956
 
+        }
3957
 
+}
3958
 
+
3959
 
+static void
3960
 
+gvc_level_bar_size_allocate (GtkWidget     *widget,
3961
 
+                             GtkAllocation *allocation)
3962
 
+{
3963
 
+        GvcLevelBar *bar;
3964
 
+
3965
 
+        g_return_if_fail (GVC_IS_LEVEL_BAR (widget));
3966
 
+        g_return_if_fail (allocation != NULL);
3967
 
+
3968
 
+        bar = GVC_LEVEL_BAR (widget);
3969
 
+
3970
 
+        /* FIXME: add height property, labels, etc */
3971
 
+        GTK_WIDGET_CLASS (gvc_level_bar_parent_class)->size_allocate (widget, allocation);
3972
 
+
3973
 
+        gtk_widget_set_allocation (widget, allocation);
3974
 
+        gtk_widget_get_allocation (widget, allocation);
3975
 
+
3976
 
+        if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
3977
 
+                allocation->height = MIN (allocation->height, MIN_VERTICAL_BAR_HEIGHT);
3978
 
+                allocation->width = MAX (allocation->width, VERTICAL_BAR_WIDTH);
3979
 
+        } else {
3980
 
+                allocation->width = MIN (allocation->width, MIN_HORIZONTAL_BAR_WIDTH);
3981
 
+                allocation->height = MAX (allocation->height, HORIZONTAL_BAR_HEIGHT);
3982
 
+        }
3983
 
+
3984
 
+        bar_calc_layout (bar);
3985
 
+}
3986
 
+
3987
 
+static void
3988
 
+curved_rectangle (cairo_t *cr,
3989
 
+                  double   x0,
3990
 
+                  double   y0,
3991
 
+                  double   width,
3992
 
+                  double   height,
3993
 
+                  double   radius)
3994
 
+{
3995
 
+        double x1;
3996
 
+        double y1;
3997
 
+
3998
 
+        x1 = x0 + width;
3999
 
+        y1 = y0 + height;
4000
 
+
4001
 
+        if (!width || !height) {
4002
 
+                return;
4003
 
+        }
4004
 
+
4005
 
+        if (width / 2 < radius) {
4006
 
+                if (height / 2 < radius) {
4007
 
+                        cairo_move_to  (cr, x0, (y0 + y1) / 2);
4008
 
+                        cairo_curve_to (cr, x0 ,y0, x0, y0, (x0 + x1) / 2, y0);
4009
 
+                        cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
4010
 
+                        cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
4011
 
+                        cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
4012
 
+                } else {
4013
 
+                        cairo_move_to  (cr, x0, y0 + radius);
4014
 
+                        cairo_curve_to (cr, x0, y0, x0, y0, (x0 + x1) / 2, y0);
4015
 
+                        cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
4016
 
+                        cairo_line_to (cr, x1, y1 - radius);
4017
 
+                        cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
4018
 
+                        cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
4019
 
+                }
4020
 
+        } else {
4021
 
+                if (height / 2 < radius) {
4022
 
+                        cairo_move_to  (cr, x0, (y0 + y1) / 2);
4023
 
+                        cairo_curve_to (cr, x0, y0, x0 , y0, x0 + radius, y0);
4024
 
+                        cairo_line_to (cr, x1 - radius, y0);
4025
 
+                        cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
4026
 
+                        cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
4027
 
+                        cairo_line_to (cr, x0 + radius, y1);
4028
 
+                        cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
4029
 
+                } else {
4030
 
+                        cairo_move_to  (cr, x0, y0 + radius);
4031
 
+                        cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + radius, y0);
4032
 
+                        cairo_line_to (cr, x1 - radius, y0);
4033
 
+                        cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
4034
 
+                        cairo_line_to (cr, x1, y1 - radius);
4035
 
+                        cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
4036
 
+                        cairo_line_to (cr, x0 + radius, y1);
4037
 
+                        cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
4038
 
+                }
4039
 
+        }
4040
 
+
4041
 
+        cairo_close_path (cr);
4042
 
+}
4043
 
+
4044
 
+static int
4045
 
+gvc_level_bar_draw (GtkWidget *widget,
4046
 
+                    cairo_t   *cr)
4047
 
+{
4048
 
+        GvcLevelBar     *bar;
4049
 
+
4050
 
+        g_return_val_if_fail (GVC_IS_LEVEL_BAR (widget), FALSE);
4051
 
+
4052
 
+        bar = GVC_LEVEL_BAR (widget);
4053
 
+
4054
 
+        if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
4055
 
+                int i;
4056
 
+                int by;
4057
 
+
4058
 
+                for (i = 0; i < NUM_BOXES; i++) {
4059
 
+                        by = i * bar->priv->layout.delta;
4060
 
+                        curved_rectangle (cr,
4061
 
+                                          bar->priv->layout.area.x + 0.5,
4062
 
+                                          by + 0.5,
4063
 
+                                          bar->priv->layout.box_width - 1,
4064
 
+                                          bar->priv->layout.box_height - 1,
4065
 
+                                          bar->priv->layout.box_radius);
4066
 
+                        if ((bar->priv->layout.max_peak_num - 1) == i) {
4067
 
+                                /* fill peak foreground */
4068
 
+                                cairo_set_source_rgb (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b);
4069
 
+                                cairo_fill_preserve (cr);
4070
 
+                        } else if ((bar->priv->layout.peak_num - 1) >= i) {
4071
 
+                                /* fill background */
4072
 
+                                cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
4073
 
+                                cairo_fill_preserve (cr);
4074
 
+                                /* fill foreground */
4075
 
+                                cairo_set_source_rgba (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b, 0.5);
4076
 
+                                cairo_fill_preserve (cr);
4077
 
+                        } else {
4078
 
+                                /* fill background */
4079
 
+                                cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
4080
 
+                                cairo_fill_preserve (cr);
4081
 
+                        }
4082
 
+
4083
 
+                        /* stroke border */
4084
 
+                        cairo_set_source_rgb (cr, bar->priv->layout.bdr_r, bar->priv->layout.bdr_g, bar->priv->layout.bdr_b);
4085
 
+                        cairo_set_line_width (cr, 1);
4086
 
+                        cairo_stroke (cr);
4087
 
+                }
4088
 
+
4089
 
+        } else {
4090
 
+                int i;
4091
 
+                int bx;
4092
 
+
4093
 
+                for (i = 0; i < NUM_BOXES; i++) {
4094
 
+                        bx = i * bar->priv->layout.delta;
4095
 
+                        curved_rectangle (cr,
4096
 
+                                          bx + 0.5,
4097
 
+                                          bar->priv->layout.area.y + 0.5,
4098
 
+                                          bar->priv->layout.box_width - 1,
4099
 
+                                          bar->priv->layout.box_height - 1,
4100
 
+                                          bar->priv->layout.box_radius);
4101
 
+
4102
 
+                        if ((bar->priv->layout.max_peak_num - 1) == i) {
4103
 
+                                /* fill peak foreground */
4104
 
+                                cairo_set_source_rgb (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b);
4105
 
+                                cairo_fill_preserve (cr);
4106
 
+                        } else if ((bar->priv->layout.peak_num - 1) >= i) {
4107
 
+                                /* fill background */
4108
 
+                                cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
4109
 
+                                cairo_fill_preserve (cr);
4110
 
+                                /* fill foreground */
4111
 
+                                cairo_set_source_rgba (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b, 0.5);
4112
 
+                                cairo_fill_preserve (cr);
4113
 
+                        } else {
4114
 
+                                /* fill background */
4115
 
+                                cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
4116
 
+                                cairo_fill_preserve (cr);
4117
 
+                        }
4118
 
+
4119
 
+                        /* stroke border */
4120
 
+                        cairo_set_source_rgb (cr, bar->priv->layout.bdr_r, bar->priv->layout.bdr_g, bar->priv->layout.bdr_b);
4121
 
+                        cairo_set_line_width (cr, 1);
4122
 
+                        cairo_stroke (cr);
4123
 
+                }
4124
 
+        }
4125
 
+
4126
 
+        return FALSE;
4127
 
+}
4128
 
+
4129
 
+static void
4130
 
+gvc_level_bar_class_init (GvcLevelBarClass *klass)
4131
 
+{
4132
 
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
4133
 
+        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
4134
 
+
4135
 
+        object_class->constructor = gvc_level_bar_constructor;
4136
 
+        object_class->finalize = gvc_level_bar_finalize;
4137
 
+        object_class->set_property = gvc_level_bar_set_property;
4138
 
+        object_class->get_property = gvc_level_bar_get_property;
4139
 
+
4140
 
+        widget_class->draw = gvc_level_bar_draw;
4141
 
+        widget_class->get_preferred_width = gvc_level_bar_get_preferred_width;
4142
 
+        widget_class->get_preferred_height = gvc_level_bar_get_preferred_height;
4143
 
+        widget_class->size_allocate = gvc_level_bar_size_allocate;
4144
 
+
4145
 
+        g_object_class_install_property (object_class,
4146
 
+                                         PROP_ORIENTATION,
4147
 
+                                         g_param_spec_enum ("orientation",
4148
 
+                                                            "Orientation",
4149
 
+                                                            "The orientation of the bar",
4150
 
+                                                            GTK_TYPE_ORIENTATION,
4151
 
+                                                            GTK_ORIENTATION_HORIZONTAL,
4152
 
+                                                            G_PARAM_READWRITE));
4153
 
+        g_object_class_install_property (object_class,
4154
 
+                                         PROP_PEAK_ADJUSTMENT,
4155
 
+                                         g_param_spec_object ("peak-adjustment",
4156
 
+                                                              "Peak Adjustment",
4157
 
+                                                              "The GtkAdjustment that contains the current peak value",
4158
 
+                                                              GTK_TYPE_ADJUSTMENT,
4159
 
+                                                              G_PARAM_READWRITE));
4160
 
+        g_object_class_install_property (object_class,
4161
 
+                                         PROP_RMS_ADJUSTMENT,
4162
 
+                                         g_param_spec_object ("rms-adjustment",
4163
 
+                                                              "RMS Adjustment",
4164
 
+                                                              "The GtkAdjustment that contains the current rms value",
4165
 
+                                                              GTK_TYPE_ADJUSTMENT,
4166
 
+                                                              G_PARAM_READWRITE));
4167
 
+        g_object_class_install_property (object_class,
4168
 
+                                         PROP_SCALE,
4169
 
+                                         g_param_spec_int ("scale",
4170
 
+                                                           "Scale",
4171
 
+                                                           "Scale",
4172
 
+                                                           0,
4173
 
+                                                           G_MAXINT,
4174
 
+                                                           GVC_LEVEL_SCALE_LINEAR,
4175
 
+                                                           G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
4176
 
+
4177
 
+        g_type_class_add_private (klass, sizeof (GvcLevelBarPrivate));
4178
 
+}
4179
 
+
4180
 
+static void
4181
 
+gvc_level_bar_init (GvcLevelBar *bar)
4182
 
+{
4183
 
+        bar->priv = GVC_LEVEL_BAR_GET_PRIVATE (bar);
4184
 
+
4185
 
+        bar->priv->peak_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
4186
 
+                                                                         0.0,
4187
 
+                                                                         1.0,
4188
 
+                                                                         0.05,
4189
 
+                                                                         0.1,
4190
 
+                                                                         0.1));
4191
 
+        g_object_ref_sink (bar->priv->peak_adjustment);
4192
 
+        g_signal_connect (bar->priv->peak_adjustment,
4193
 
+                          "value-changed",
4194
 
+                          G_CALLBACK (on_peak_adjustment_value_changed),
4195
 
+                          bar);
4196
 
+
4197
 
+        bar->priv->rms_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
4198
 
+                                                                        0.0,
4199
 
+                                                                        1.0,
4200
 
+                                                                        0.05,
4201
 
+                                                                        0.1,
4202
 
+                                                                        0.1));
4203
 
+        g_object_ref_sink (bar->priv->rms_adjustment);
4204
 
+        g_signal_connect (bar->priv->rms_adjustment,
4205
 
+                          "value-changed",
4206
 
+                          G_CALLBACK (on_rms_adjustment_value_changed),
4207
 
+                          bar);
4208
 
+
4209
 
+        gtk_widget_set_has_window (GTK_WIDGET (bar), FALSE);
4210
 
+}
4211
 
+
4212
 
+static void
4213
 
+gvc_level_bar_finalize (GObject *object)
4214
 
+{
4215
 
+        GvcLevelBar *bar;
4216
 
+
4217
 
+        g_return_if_fail (object != NULL);
4218
 
+        g_return_if_fail (GVC_IS_LEVEL_BAR (object));
4219
 
+
4220
 
+        bar = GVC_LEVEL_BAR (object);
4221
 
+
4222
 
+        if (bar->priv->max_peak_id > 0) {
4223
 
+                g_source_remove (bar->priv->max_peak_id);
4224
 
+        }
4225
 
+
4226
 
+        g_return_if_fail (bar->priv != NULL);
4227
 
+
4228
 
+        G_OBJECT_CLASS (gvc_level_bar_parent_class)->finalize (object);
4229
 
+}
4230
 
+
4231
 
+GtkWidget *
4232
 
+gvc_level_bar_new (void)
4233
 
+{
4234
 
+        GObject *bar;
4235
 
+        bar = g_object_new (GVC_TYPE_LEVEL_BAR,
4236
 
+                            NULL);
4237
 
+        return GTK_WIDGET (bar);
4238
 
+}
4239
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-level-bar.h
4240
 
===================================================================
4241
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
4242
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-level-bar.h 2012-08-28 17:08:49.444516900 +0200
4243
 
@@ -0,0 +1,75 @@
4244
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
4245
 
+ *
4246
 
+ * Copyright (C) 2008 William Jon McCann <william.jon.mccann@gmail.com>
4247
 
+ *
4248
 
+ * This program is free software; you can redistribute it and/or modify
4249
 
+ * it under the terms of the GNU General Public License as published by
4250
 
+ * the Free Software Foundation; either version 2 of the License, or
4251
 
+ * (at your option) any later version.
4252
 
+ *
4253
 
+ * This program is distributed in the hope that it will be useful,
4254
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4255
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4256
 
+ * GNU General Public License for more details.
4257
 
+ *
4258
 
+ * You should have received a copy of the GNU General Public License
4259
 
+ * along with this program; if not, write to the Free Software
4260
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4261
 
+ *
4262
 
+ */
4263
 
+
4264
 
+#ifndef __GVC_LEVEL_BAR_H
4265
 
+#define __GVC_LEVEL_BAR_H
4266
 
+
4267
 
+#include <glib-object.h>
4268
 
+#include <gtk/gtk.h>
4269
 
+
4270
 
+G_BEGIN_DECLS
4271
 
+
4272
 
+#define GVC_TYPE_LEVEL_BAR         (gvc_level_bar_get_type ())
4273
 
+#define GVC_LEVEL_BAR(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_LEVEL_BAR, GvcLevelBar))
4274
 
+#define GVC_LEVEL_BAR_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_LEVEL_BAR, GvcLevelBarClass))
4275
 
+#define GVC_IS_LEVEL_BAR(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_LEVEL_BAR))
4276
 
+#define GVC_IS_LEVEL_BAR_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_LEVEL_BAR))
4277
 
+#define GVC_LEVEL_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_LEVEL_BAR, GvcLevelBarClass))
4278
 
+
4279
 
+typedef struct GvcLevelBarPrivate GvcLevelBarPrivate;
4280
 
+
4281
 
+typedef struct
4282
 
+{
4283
 
+        GtkWidget           parent;
4284
 
+        GvcLevelBarPrivate *priv;
4285
 
+} GvcLevelBar;
4286
 
+
4287
 
+typedef struct
4288
 
+{
4289
 
+        GtkWidgetClass      parent_class;
4290
 
+} GvcLevelBarClass;
4291
 
+
4292
 
+typedef enum
4293
 
+{
4294
 
+    GVC_LEVEL_SCALE_LINEAR,
4295
 
+    GVC_LEVEL_SCALE_LOG,
4296
 
+    GVC_LEVEL_SCALE_LAST
4297
 
+} GvcLevelScale;
4298
 
+
4299
 
+GType               gvc_level_bar_get_type            (void);
4300
 
+
4301
 
+GtkWidget *         gvc_level_bar_new                 (void);
4302
 
+void                gvc_level_bar_set_orientation     (GvcLevelBar   *bar,
4303
 
+                                                       GtkOrientation orientation);
4304
 
+GtkOrientation      gvc_level_bar_get_orientation     (GvcLevelBar   *bar);
4305
 
+
4306
 
+void                gvc_level_bar_set_peak_adjustment (GvcLevelBar   *bar,
4307
 
+                                                       GtkAdjustment *adjustment);
4308
 
+GtkAdjustment *     gvc_level_bar_get_peak_adjustment (GvcLevelBar   *bar);
4309
 
+void                gvc_level_bar_set_rms_adjustment  (GvcLevelBar   *bar,
4310
 
+                                                       GtkAdjustment *adjustment);
4311
 
+GtkAdjustment *     gvc_level_bar_get_rms_adjustment  (GvcLevelBar   *bar);
4312
 
+void                gvc_level_bar_set_scale           (GvcLevelBar   *bar,
4313
 
+                                                       GvcLevelScale  scale);
4314
 
+
4315
 
+
4316
 
+G_END_DECLS
4317
 
+
4318
 
+#endif /* __GVC_LEVEL_BAR_H */
4319
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-log.c
4320
 
===================================================================
4321
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
4322
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-log.c       2012-08-28 17:08:49.444516900 +0200
4323
 
@@ -0,0 +1,64 @@
4324
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
4325
 
+ *
4326
 
+ * Copyright (C) 2009 Red Hat, Inc.
4327
 
+ *
4328
 
+ * This program is free software; you can redistribute it and/or modify
4329
 
+ * it under the terms of the GNU General Public License as published by
4330
 
+ * the Free Software Foundation; either version 2 of the License, or
4331
 
+ * (at your option) any later version.
4332
 
+ *
4333
 
+ * This program is distributed in the hope that it will be useful,
4334
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4335
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4336
 
+ * GNU General Public License for more details.
4337
 
+ *
4338
 
+ * You should have received a copy of the GNU General Public License
4339
 
+ * along with this program; if not, write to the Free Software
4340
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4341
 
+ *
4342
 
+ */
4343
 
+
4344
 
+
4345
 
+#include "config.h"
4346
 
+
4347
 
+#include <glib.h>
4348
 
+#include <glib/gstdio.h>
4349
 
+
4350
 
+#include "gvc-log.h"
4351
 
+
4352
 
+
4353
 
+static int log_levels = G_LOG_LEVEL_CRITICAL |
4354
 
+                        G_LOG_LEVEL_ERROR    |
4355
 
+                        G_LOG_LEVEL_WARNING  |
4356
 
+                        G_LOG_LEVEL_MESSAGE  |
4357
 
+                        G_LOG_LEVEL_INFO     |
4358
 
+                        G_LOG_LEVEL_DEBUG;
4359
 
+
4360
 
+static void
4361
 
+gvc_log_default_handler (const gchar    *log_domain,
4362
 
+                         GLogLevelFlags  log_level,
4363
 
+                         const gchar    *message,
4364
 
+                         gpointer        unused_data)
4365
 
+{
4366
 
+        if ((log_level & log_levels) == 0)
4367
 
+                return;
4368
 
+
4369
 
+        g_log_default_handler (log_domain, log_level, message, unused_data);
4370
 
+}
4371
 
+
4372
 
+void
4373
 
+gvc_log_init (void)
4374
 
+{
4375
 
+        g_log_set_default_handler (gvc_log_default_handler, NULL);
4376
 
+}
4377
 
+
4378
 
+void
4379
 
+gvc_log_set_debug (gboolean debug)
4380
 
+{
4381
 
+        if (debug) {
4382
 
+                log_levels |= (G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_INFO);
4383
 
+                g_debug ("Enabling debugging");
4384
 
+        } else {
4385
 
+                log_levels &= ~ (G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_INFO);
4386
 
+        }
4387
 
+}
4388
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-log.h
4389
 
===================================================================
4390
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
4391
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-log.h       2012-08-28 17:08:49.444516900 +0200
4392
 
@@ -0,0 +1,35 @@
4393
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
4394
 
+ *
4395
 
+ * Copyright (C) 2009 Red Hat, Inc.
4396
 
+ *
4397
 
+ * This program is free software; you can redistribute it and/or modify
4398
 
+ * it under the terms of the GNU General Public License as published by
4399
 
+ * the Free Software Foundation; either version 2 of the License, or
4400
 
+ * (at your option) any later version.
4401
 
+ *
4402
 
+ * This program is distributed in the hope that it will be useful,
4403
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4404
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4405
 
+ * GNU General Public License for more details.
4406
 
+ *
4407
 
+ * You should have received a copy of the GNU General Public License
4408
 
+ * along with this program; if not, write to the Free Software
4409
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4410
 
+ *
4411
 
+ */
4412
 
+
4413
 
+#ifndef __GVC_LOG_H
4414
 
+#define __GVC_LOG_H
4415
 
+
4416
 
+#include <glib.h>
4417
 
+
4418
 
+G_BEGIN_DECLS
4419
 
+
4420
 
+
4421
 
+void gvc_log_init      (void);
4422
 
+void gvc_log_set_debug (gboolean debug);
4423
 
+
4424
 
+
4425
 
+G_END_DECLS
4426
 
+
4427
 
+#endif /* __GVC_LOG_H */
4428
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-card-private.h
4429
 
===================================================================
4430
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
4431
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-card-private.h        2012-08-28 17:08:49.444516900 +0200
4432
 
@@ -0,0 +1,35 @@
4433
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
4434
 
+ *
4435
 
+ * Copyright (C) 2008-2009 Red Hat, Inc.
4436
 
+ *
4437
 
+ * This program is free software; you can redistribute it and/or modify
4438
 
+ * it under the terms of the GNU General Public License as published by
4439
 
+ * the Free Software Foundation; either version 2 of the License, or
4440
 
+ * (at your option) any later version.
4441
 
+ *
4442
 
+ * This program is distributed in the hope that it will be useful,
4443
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4444
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4445
 
+ * GNU General Public License for more details.
4446
 
+ *
4447
 
+ * You should have received a copy of the GNU General Public License
4448
 
+ * along with this program; if not, write to the Free Software
4449
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4450
 
+ *
4451
 
+ */
4452
 
+
4453
 
+#ifndef __GVC_MIXER_CARD_PRIVATE_H
4454
 
+#define __GVC_MIXER_CARD_PRIVATE_H
4455
 
+
4456
 
+#include <pulse/pulseaudio.h>
4457
 
+#include "gvc-mixer-card.h"
4458
 
+
4459
 
+G_BEGIN_DECLS
4460
 
+
4461
 
+GvcMixerCard *        gvc_mixer_card_new               (pa_context   *context,
4462
 
+                                                        guint         index);
4463
 
+pa_context *          gvc_mixer_card_get_pa_context    (GvcMixerCard *card);
4464
 
+
4465
 
+G_END_DECLS
4466
 
+
4467
 
+#endif /* __GVC_MIXER_CARD_PRIVATE_H */
4468
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-card.c
4469
 
===================================================================
4470
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
4471
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-card.c        2012-08-28 17:08:49.444516900 +0200
4472
 
@@ -0,0 +1,550 @@
4473
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
4474
 
+ *
4475
 
+ * Copyright (C) 2008 William Jon McCann
4476
 
+ * Copyright (C) 2009 Bastien Nocera
4477
 
+ * Copyright (C) Conor Curran 2011 <conor.curran@canonical.com>
4478
 
+ *
4479
 
+ * This program is free software; you can redistribute it and/or modify
4480
 
+ * it under the terms of the GNU General Public License as published by
4481
 
+ * the Free Software Foundation; either version 2 of the License, or
4482
 
+ * (at your option) any later version.
4483
 
+ *
4484
 
+ * This program is distributed in the hope that it will be useful,
4485
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4486
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4487
 
+ * GNU General Public License for more details.
4488
 
+ *
4489
 
+ * You should have received a copy of the GNU General Public License
4490
 
+ * along with this program; if not, write to the Free Software
4491
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4492
 
+ *
4493
 
+ */
4494
 
+
4495
 
+#include "config.h"
4496
 
+
4497
 
+#include <stdlib.h>
4498
 
+#include <stdio.h>
4499
 
+#include <unistd.h>
4500
 
+
4501
 
+#include <glib.h>
4502
 
+#include <glib/gi18n-lib.h>
4503
 
+
4504
 
+#include <pulse/pulseaudio.h>
4505
 
+
4506
 
+#include "gvc-mixer-card.h"
4507
 
+#include "gvc-mixer-card-private.h"
4508
 
+
4509
 
+#define GVC_MIXER_CARD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_CARD, GvcMixerCardPrivate))
4510
 
+
4511
 
+static guint32 card_serial = 1;
4512
 
+
4513
 
+struct GvcMixerCardPrivate
4514
 
+{
4515
 
+        pa_context    *pa_context;
4516
 
+        guint          id;
4517
 
+        guint          index;
4518
 
+        char          *name;
4519
 
+        char          *icon_name;
4520
 
+        char          *profile;
4521
 
+        char          *target_profile;
4522
 
+        char          *human_profile;
4523
 
+        GList         *profiles;
4524
 
+        pa_operation  *profile_op;
4525
 
+        GList        *ports;        
4526
 
+};
4527
 
+
4528
 
+enum
4529
 
+{
4530
 
+        PROP_0,
4531
 
+        PROP_ID,
4532
 
+        PROP_PA_CONTEXT,
4533
 
+        PROP_INDEX,
4534
 
+        PROP_NAME,
4535
 
+        PROP_ICON_NAME,
4536
 
+        PROP_PROFILE,
4537
 
+        PROP_HUMAN_PROFILE,
4538
 
+};
4539
 
+
4540
 
+static void     gvc_mixer_card_class_init (GvcMixerCardClass *klass);
4541
 
+static void     gvc_mixer_card_init       (GvcMixerCard      *mixer_card);
4542
 
+static void     gvc_mixer_card_finalize   (GObject            *object);
4543
 
+
4544
 
+G_DEFINE_TYPE (GvcMixerCard, gvc_mixer_card, G_TYPE_OBJECT)
4545
 
+
4546
 
+static guint32
4547
 
+get_next_card_serial (void)
4548
 
+{
4549
 
+        guint32 serial;
4550
 
+
4551
 
+        serial = card_serial++;
4552
 
+
4553
 
+        if ((gint32)card_serial < 0) {
4554
 
+                card_serial = 1;
4555
 
+        }
4556
 
+
4557
 
+        return serial;
4558
 
+}
4559
 
+
4560
 
+pa_context *
4561
 
+gvc_mixer_card_get_pa_context (GvcMixerCard *card)
4562
 
+{
4563
 
+        g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
4564
 
+        return card->priv->pa_context;
4565
 
+}
4566
 
+
4567
 
+guint
4568
 
+gvc_mixer_card_get_index (GvcMixerCard *card)
4569
 
+{
4570
 
+        g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
4571
 
+        return card->priv->index;
4572
 
+}
4573
 
+
4574
 
+guint
4575
 
+gvc_mixer_card_get_id (GvcMixerCard *card)
4576
 
+{
4577
 
+        g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
4578
 
+        return card->priv->id;
4579
 
+}
4580
 
+
4581
 
+const char *
4582
 
+gvc_mixer_card_get_name (GvcMixerCard *card)
4583
 
+{
4584
 
+        g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
4585
 
+        return card->priv->name;
4586
 
+}
4587
 
+
4588
 
+gboolean
4589
 
+gvc_mixer_card_set_name (GvcMixerCard *card,
4590
 
+                         const char     *name)
4591
 
+{
4592
 
+        g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
4593
 
+
4594
 
+        g_free (card->priv->name);
4595
 
+        card->priv->name = g_strdup (name);
4596
 
+        g_object_notify (G_OBJECT (card), "name");
4597
 
+
4598
 
+        return TRUE;
4599
 
+}
4600
 
+
4601
 
+const char *
4602
 
+gvc_mixer_card_get_icon_name (GvcMixerCard *card)
4603
 
+{
4604
 
+        g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
4605
 
+        return card->priv->icon_name;
4606
 
+}
4607
 
+
4608
 
+gboolean
4609
 
+gvc_mixer_card_set_icon_name (GvcMixerCard *card,
4610
 
+                              const char     *icon_name)
4611
 
+{
4612
 
+        g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
4613
 
+
4614
 
+        g_free (card->priv->icon_name);
4615
 
+        card->priv->icon_name = g_strdup (icon_name);
4616
 
+        g_object_notify (G_OBJECT (card), "icon-name");
4617
 
+
4618
 
+        return TRUE;
4619
 
+}
4620
 
+
4621
 
+/**
4622
 
+ * gvc_mixer_card_get_profile: (skip)
4623
 
+ *
4624
 
+ * @card:
4625
 
+ *
4626
 
+ * Returns:
4627
 
+ */
4628
 
+GvcMixerCardProfile *
4629
 
+gvc_mixer_card_get_profile (GvcMixerCard *card)
4630
 
+{
4631
 
+        GList *l;
4632
 
+
4633
 
+        g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
4634
 
+        g_return_val_if_fail (card->priv->profiles != NULL, NULL);
4635
 
+
4636
 
+        for (l = card->priv->profiles; l != NULL; l = l->next) {
4637
 
+                GvcMixerCardProfile *p = l->data;
4638
 
+                if (g_str_equal (card->priv->profile, p->profile)) {
4639
 
+                        return p;
4640
 
+                }
4641
 
+        }
4642
 
+
4643
 
+        g_assert_not_reached ();
4644
 
+
4645
 
+        return NULL;
4646
 
+}
4647
 
+
4648
 
+gboolean
4649
 
+gvc_mixer_card_set_profile (GvcMixerCard *card,
4650
 
+                            const char     *profile)
4651
 
+{
4652
 
+        GList *l;
4653
 
+
4654
 
+        g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
4655
 
+        g_return_val_if_fail (card->priv->profiles != NULL, FALSE);
4656
 
+
4657
 
+        g_free (card->priv->profile);
4658
 
+        card->priv->profile = g_strdup (profile);
4659
 
+
4660
 
+        g_free (card->priv->human_profile);
4661
 
+        card->priv->human_profile = NULL;
4662
 
+
4663
 
+        for (l = card->priv->profiles; l != NULL; l = l->next) {
4664
 
+                GvcMixerCardProfile *p = l->data;
4665
 
+                if (g_str_equal (card->priv->profile, p->profile)) {
4666
 
+                        card->priv->human_profile = g_strdup (p->human_profile);
4667
 
+                        break;
4668
 
+                }
4669
 
+        }
4670
 
+
4671
 
+        g_object_notify (G_OBJECT (card), "profile");
4672
 
+
4673
 
+        return TRUE;
4674
 
+}
4675
 
+
4676
 
+static void
4677
 
+_pa_context_set_card_profile_by_index_cb (pa_context                       *context,
4678
 
+                                          int                               success,
4679
 
+                                          void                             *userdata)
4680
 
+{
4681
 
+        GvcMixerCard *card = GVC_MIXER_CARD (userdata);
4682
 
+
4683
 
+        g_assert (card->priv->target_profile);
4684
 
+
4685
 
+        if (success > 0) {
4686
 
+                gvc_mixer_card_set_profile (card, card->priv->target_profile);
4687
 
+        } else {
4688
 
+                g_debug ("Failed to switch profile on '%s' from '%s' to '%s'",
4689
 
+                         card->priv->name,
4690
 
+                         card->priv->profile,
4691
 
+                         card->priv->target_profile);
4692
 
+        }
4693
 
+        g_free (card->priv->target_profile);
4694
 
+        card->priv->target_profile = NULL;
4695
 
+
4696
 
+        pa_operation_unref (card->priv->profile_op);
4697
 
+        card->priv->profile_op = NULL;
4698
 
+}
4699
 
+
4700
 
+gboolean
4701
 
+gvc_mixer_card_change_profile (GvcMixerCard *card,
4702
 
+                               const char *profile)
4703
 
+{
4704
 
+        g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
4705
 
+        g_return_val_if_fail (card->priv->profiles != NULL, FALSE);
4706
 
+
4707
 
+        /* Same profile, or already requested? */
4708
 
+        if (g_strcmp0 (card->priv->profile, profile) == 0)
4709
 
+                return TRUE;
4710
 
+        if (g_strcmp0 (profile, card->priv->target_profile) == 0)
4711
 
+                return TRUE;
4712
 
+        if (card->priv->profile_op != NULL) {
4713
 
+                pa_operation_cancel (card->priv->profile_op);
4714
 
+                pa_operation_unref (card->priv->profile_op);
4715
 
+                card->priv->profile_op = NULL;
4716
 
+        }
4717
 
+
4718
 
+        if (card->priv->profile != NULL) {
4719
 
+                g_free (card->priv->target_profile);
4720
 
+                card->priv->target_profile = g_strdup (profile);
4721
 
+
4722
 
+                card->priv->profile_op = pa_context_set_card_profile_by_index (card->priv->pa_context,
4723
 
+                                                                               card->priv->index,
4724
 
+                                                                               card->priv->target_profile,
4725
 
+                                                                               _pa_context_set_card_profile_by_index_cb,
4726
 
+                                                                               card);
4727
 
+
4728
 
+                if (card->priv->profile_op == NULL) {
4729
 
+                        g_warning ("pa_context_set_card_profile_by_index() failed");
4730
 
+                        return FALSE;
4731
 
+                }
4732
 
+        } else {
4733
 
+                g_assert (card->priv->human_profile == NULL);
4734
 
+                card->priv->profile = g_strdup (profile);
4735
 
+        }
4736
 
+
4737
 
+        return TRUE;
4738
 
+}
4739
 
+
4740
 
+/**
4741
 
+ * gvc_mixer_card_get_profiles:
4742
 
+ *
4743
 
+ * Return value: (transfer none) (element-type GvcMixerCardProfile):
4744
 
+ */
4745
 
+const GList *
4746
 
+gvc_mixer_card_get_profiles (GvcMixerCard *card)
4747
 
+{
4748
 
+        g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
4749
 
+        return card->priv->profiles;
4750
 
+}
4751
 
+
4752
 
+
4753
 
+/**
4754
 
+ * gvc_mixer_card_get_ports:
4755
 
+ *
4756
 
+ * Return value: (transfer none) (element-type GvcMixerCardPort):
4757
 
+ */
4758
 
+const GList *
4759
 
+gvc_mixer_card_get_ports (GvcMixerCard *card)
4760
 
+{
4761
 
+        g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
4762
 
+        return card->priv->ports;
4763
 
+}
4764
 
+
4765
 
+/**
4766
 
+ * gvc_mixer_card_set_profiles:
4767
 
+ * @profiles: (transfer full) (element-type GvcMixerCardProfile):
4768
 
+ */
4769
 
+gboolean
4770
 
+gvc_mixer_card_set_profiles (GvcMixerCard *card,
4771
 
+                             GList        *profiles)
4772
 
+{
4773
 
+        g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
4774
 
+        g_return_val_if_fail (card->priv->profiles == NULL, FALSE);
4775
 
+
4776
 
+        card->priv->profiles = g_list_sort (profiles, (GCompareFunc) sort_profiles);
4777
 
+
4778
 
+        return TRUE;
4779
 
+}
4780
 
+
4781
 
+/**
4782
 
+ * gvc_mixer_card_get_gicon:
4783
 
+ *
4784
 
+ * Return value: (transfer full) (element-type GIcon):
4785
 
+ */
4786
 
+GIcon *
4787
 
+gvc_mixer_card_get_gicon (GvcMixerCard *card)
4788
 
+{
4789
 
+        g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
4790
 
+        if (card->priv->icon_name == NULL)
4791
 
+                return NULL;
4792
 
+        return g_themed_icon_new_with_default_fallbacks (card->priv->icon_name);
4793
 
+}
4794
 
+
4795
 
+/**
4796
 
+ * gvc_mixer_card_set_ports:
4797
 
+ * @profiles: (transfer full) (element-type GvcMixerCardPort):
4798
 
+ */
4799
 
+gboolean              
4800
 
+gvc_mixer_card_set_ports (GvcMixerCard *card,
4801
 
+                          GList          *ports)
4802
 
+{
4803
 
+        g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
4804
 
+        g_return_val_if_fail (card->priv->ports == NULL, FALSE);
4805
 
+
4806
 
+        card->priv->ports = ports;
4807
 
+
4808
 
+        return TRUE;   
4809
 
+}                                                     
4810
 
+
4811
 
+static void
4812
 
+gvc_mixer_card_set_property (GObject       *object,
4813
 
+                             guint          prop_id,
4814
 
+                             const GValue  *value,
4815
 
+                             GParamSpec    *pspec)
4816
 
+{
4817
 
+        GvcMixerCard *self = GVC_MIXER_CARD (object);
4818
 
+
4819
 
+        switch (prop_id) {
4820
 
+        case PROP_PA_CONTEXT:
4821
 
+                self->priv->pa_context = g_value_get_pointer (value);
4822
 
+                break;
4823
 
+        case PROP_INDEX:
4824
 
+                self->priv->index = g_value_get_ulong (value);
4825
 
+                break;
4826
 
+        case PROP_ID:
4827
 
+                self->priv->id = g_value_get_ulong (value);
4828
 
+                break;
4829
 
+        case PROP_NAME:
4830
 
+                gvc_mixer_card_set_name (self, g_value_get_string (value));
4831
 
+                break;
4832
 
+        case PROP_ICON_NAME:
4833
 
+                gvc_mixer_card_set_icon_name (self, g_value_get_string (value));
4834
 
+                break;
4835
 
+        case PROP_PROFILE:
4836
 
+                gvc_mixer_card_set_profile (self, g_value_get_string (value));
4837
 
+                break;
4838
 
+        default:
4839
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4840
 
+                break;
4841
 
+        }
4842
 
+}
4843
 
+
4844
 
+static void
4845
 
+gvc_mixer_card_get_property (GObject     *object,
4846
 
+                             guint        prop_id,
4847
 
+                             GValue      *value,
4848
 
+                             GParamSpec  *pspec)
4849
 
+{
4850
 
+        GvcMixerCard *self = GVC_MIXER_CARD (object);
4851
 
+
4852
 
+        switch (prop_id) {
4853
 
+        case PROP_PA_CONTEXT:
4854
 
+                g_value_set_pointer (value, self->priv->pa_context);
4855
 
+                break;
4856
 
+        case PROP_INDEX:
4857
 
+                g_value_set_ulong (value, self->priv->index);
4858
 
+                break;
4859
 
+        case PROP_ID:
4860
 
+                g_value_set_ulong (value, self->priv->id);
4861
 
+                break;
4862
 
+        case PROP_NAME:
4863
 
+                g_value_set_string (value, self->priv->name);
4864
 
+                break;
4865
 
+        case PROP_ICON_NAME:
4866
 
+                g_value_set_string (value, self->priv->icon_name);
4867
 
+                break;
4868
 
+        case PROP_PROFILE:
4869
 
+                g_value_set_string (value, self->priv->profile);
4870
 
+                break;
4871
 
+        case PROP_HUMAN_PROFILE:
4872
 
+                g_value_set_string (value, self->priv->human_profile);
4873
 
+                break;
4874
 
+        default:
4875
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4876
 
+                break;
4877
 
+        }
4878
 
+}
4879
 
+
4880
 
+static GObject *
4881
 
+gvc_mixer_card_constructor (GType                  type,
4882
 
+                            guint                  n_construct_properties,
4883
 
+                            GObjectConstructParam *construct_params)
4884
 
+{
4885
 
+        GObject       *object;
4886
 
+        GvcMixerCard *self;
4887
 
+
4888
 
+        object = G_OBJECT_CLASS (gvc_mixer_card_parent_class)->constructor (type, n_construct_properties, construct_params);
4889
 
+
4890
 
+        self = GVC_MIXER_CARD (object);
4891
 
+
4892
 
+        self->priv->id = get_next_card_serial ();
4893
 
+
4894
 
+        return object;
4895
 
+}
4896
 
+
4897
 
+static void
4898
 
+gvc_mixer_card_class_init (GvcMixerCardClass *klass)
4899
 
+{
4900
 
+        GObjectClass   *gobject_class = G_OBJECT_CLASS (klass);
4901
 
+
4902
 
+        gobject_class->constructor = gvc_mixer_card_constructor;
4903
 
+        gobject_class->finalize = gvc_mixer_card_finalize;
4904
 
+
4905
 
+        gobject_class->set_property = gvc_mixer_card_set_property;
4906
 
+        gobject_class->get_property = gvc_mixer_card_get_property;
4907
 
+
4908
 
+        g_object_class_install_property (gobject_class,
4909
 
+                                         PROP_INDEX,
4910
 
+                                         g_param_spec_ulong ("index",
4911
 
+                                                             "Index",
4912
 
+                                                             "The index for this card",
4913
 
+                                                             0, G_MAXULONG, 0,
4914
 
+                                                             G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
4915
 
+        g_object_class_install_property (gobject_class,
4916
 
+                                         PROP_ID,
4917
 
+                                         g_param_spec_ulong ("id",
4918
 
+                                                             "id",
4919
 
+                                                             "The id for this card",
4920
 
+                                                             0, G_MAXULONG, 0,
4921
 
+                                                             G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
4922
 
+        g_object_class_install_property (gobject_class,
4923
 
+                                         PROP_PA_CONTEXT,
4924
 
+                                         g_param_spec_pointer ("pa-context",
4925
 
+                                                               "PulseAudio context",
4926
 
+                                                               "The PulseAudio context for this card",
4927
 
+                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
4928
 
+        g_object_class_install_property (gobject_class,
4929
 
+                                         PROP_NAME,
4930
 
+                                         g_param_spec_string ("name",
4931
 
+                                                              "Name",
4932
 
+                                                              "Name to display for this card",
4933
 
+                                                              NULL,
4934
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
4935
 
+        g_object_class_install_property (gobject_class,
4936
 
+                                         PROP_ICON_NAME,
4937
 
+                                         g_param_spec_string ("icon-name",
4938
 
+                                                              "Icon Name",
4939
 
+                                                              "Name of icon to display for this card",
4940
 
+                                                              NULL,
4941
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
4942
 
+        g_object_class_install_property (gobject_class,
4943
 
+                                         PROP_PROFILE,
4944
 
+                                         g_param_spec_string ("profile",
4945
 
+                                                              "Profile",
4946
 
+                                                              "Name of current profile for this card",
4947
 
+                                                              NULL,
4948
 
+                                                              G_PARAM_READWRITE));
4949
 
+        g_object_class_install_property (gobject_class,
4950
 
+                                         PROP_HUMAN_PROFILE,
4951
 
+                                         g_param_spec_string ("human-profile",
4952
 
+                                                              "Profile (Human readable)",
4953
 
+                                                              "Name of current profile for this card in human readable form",
4954
 
+                                                              NULL,
4955
 
+                                                              G_PARAM_READABLE));
4956
 
+
4957
 
+        g_type_class_add_private (klass, sizeof (GvcMixerCardPrivate));
4958
 
+}
4959
 
+
4960
 
+static void
4961
 
+gvc_mixer_card_init (GvcMixerCard *card)
4962
 
+{
4963
 
+        card->priv = GVC_MIXER_CARD_GET_PRIVATE (card);
4964
 
+}
4965
 
+
4966
 
+
4967
 
+GvcMixerCard *
4968
 
+gvc_mixer_card_new (pa_context *context,
4969
 
+                    guint       index)
4970
 
+{
4971
 
+        GObject *object;
4972
 
+
4973
 
+        object = g_object_new (GVC_TYPE_MIXER_CARD,
4974
 
+                               "index", index,
4975
 
+                               "pa-context", context,
4976
 
+                               NULL);
4977
 
+        return GVC_MIXER_CARD (object);
4978
 
+}
4979
 
+
4980
 
+static void
4981
 
+free_profile (GvcMixerCardProfile *p)
4982
 
+{
4983
 
+        g_free (p->profile);
4984
 
+        g_free (p->human_profile);
4985
 
+        g_free (p->status);
4986
 
+        g_free (p);
4987
 
+}
4988
 
+
4989
 
+static void
4990
 
+gvc_mixer_card_finalize (GObject *object)
4991
 
+{
4992
 
+        GvcMixerCard *mixer_card;
4993
 
+
4994
 
+        g_return_if_fail (object != NULL);
4995
 
+        g_return_if_fail (GVC_IS_MIXER_CARD (object));
4996
 
+
4997
 
+        mixer_card = GVC_MIXER_CARD (object);
4998
 
+
4999
 
+        g_return_if_fail (mixer_card->priv != NULL);
5000
 
+
5001
 
+        g_free (mixer_card->priv->name);
5002
 
+        mixer_card->priv->name = NULL;
5003
 
+
5004
 
+        g_free (mixer_card->priv->icon_name);
5005
 
+        mixer_card->priv->icon_name = NULL;
5006
 
+
5007
 
+        g_free (mixer_card->priv->target_profile);
5008
 
+        mixer_card->priv->target_profile = NULL;
5009
 
+
5010
 
+        g_free (mixer_card->priv->profile);
5011
 
+        mixer_card->priv->profile = NULL;
5012
 
+
5013
 
+        g_free (mixer_card->priv->human_profile);
5014
 
+        mixer_card->priv->human_profile = NULL;
5015
 
+
5016
 
+        g_list_foreach (mixer_card->priv->profiles, (GFunc) free_profile, NULL);
5017
 
+        g_list_free (mixer_card->priv->profiles);
5018
 
+        mixer_card->priv->profiles = NULL;
5019
 
+
5020
 
+        G_OBJECT_CLASS (gvc_mixer_card_parent_class)->finalize (object);
5021
 
+}
5022
 
+
5023
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-card.h
5024
 
===================================================================
5025
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
5026
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-card.h        2012-08-28 17:08:49.444516900 +0200
5027
 
@@ -0,0 +1,109 @@
5028
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
5029
 
+ *
5030
 
+ * Copyright (C) 2008-2009 Red Hat, Inc.
5031
 
+ * Copyright (C) Conor Curran 2011 <conor.curran@canonical.com>
5032
 
5033
 
+ * This program is free software; you can redistribute it and/or modify
5034
 
+ * it under the terms of the GNU General Public License as published by
5035
 
+ * the Free Software Foundation; either version 2 of the License, or
5036
 
+ * (at your option) any later version.
5037
 
+ *
5038
 
+ * This program is distributed in the hope that it will be useful,
5039
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
5040
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5041
 
+ * GNU General Public License for more details.
5042
 
+ *
5043
 
+ * You should have received a copy of the GNU General Public License
5044
 
+ * along with this program; if not, write to the Free Software
5045
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
5046
 
+ *
5047
 
+ */
5048
 
+
5049
 
+#ifndef __GVC_MIXER_CARD_H
5050
 
+#define __GVC_MIXER_CARD_H
5051
 
+
5052
 
+#include <glib-object.h>
5053
 
+#include <gio/gio.h>
5054
 
+
5055
 
+G_BEGIN_DECLS
5056
 
+
5057
 
+#define GVC_TYPE_MIXER_CARD         (gvc_mixer_card_get_type ())
5058
 
+#define GVC_MIXER_CARD(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_CARD, GvcMixerCard))
5059
 
+#define GVC_MIXER_CARD_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_CARD, GvcMixerCardClass))
5060
 
+#define GVC_IS_MIXER_CARD(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_CARD))
5061
 
+#define GVC_IS_MIXER_CARD_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_CARD))
5062
 
+#define GVC_MIXER_CARD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_CARD, GvcMixerCardClass))
5063
 
+
5064
 
+typedef struct GvcMixerCardPrivate GvcMixerCardPrivate;
5065
 
+
5066
 
+typedef struct
5067
 
+{
5068
 
+        GObject                parent;
5069
 
+        GvcMixerCardPrivate   *priv;
5070
 
+} GvcMixerCard;
5071
 
+
5072
 
+typedef struct
5073
 
+{
5074
 
+        GObjectClass           parent_class;
5075
 
+
5076
 
+        /* vtable */
5077
 
+} GvcMixerCardClass;
5078
 
+
5079
 
+typedef struct
5080
 
+{
5081
 
+        char *profile;
5082
 
+        char *human_profile;
5083
 
+        char *status;
5084
 
+        guint priority;
5085
 
+        guint n_sinks, n_sources;
5086
 
+} GvcMixerCardProfile;
5087
 
+
5088
 
+typedef struct
5089
 
+{
5090
 
+        char *port;
5091
 
+        char *human_port;
5092
 
+        guint priority;
5093
 
+        gint  available;
5094
 
+        gint  direction;
5095
 
+        GList *profiles;
5096
 
+} GvcMixerCardPort;
5097
 
+
5098
 
+GType                 gvc_mixer_card_get_type          (void);
5099
 
+
5100
 
+guint                 gvc_mixer_card_get_id            (GvcMixerCard *card);
5101
 
+guint                 gvc_mixer_card_get_index         (GvcMixerCard *card);
5102
 
+const char *          gvc_mixer_card_get_name          (GvcMixerCard *card);
5103
 
+const char *          gvc_mixer_card_get_icon_name     (GvcMixerCard *card);
5104
 
+GvcMixerCardProfile * gvc_mixer_card_get_profile       (GvcMixerCard *card);
5105
 
+const GList *         gvc_mixer_card_get_profiles      (GvcMixerCard *card);
5106
 
+const GList *         gvc_mixer_card_get_ports         (GvcMixerCard *card);
5107
 
+gboolean              gvc_mixer_card_change_profile    (GvcMixerCard *card,
5108
 
+                                                        const char *profile);
5109
 
+GIcon *                      gvc_mixer_card_get_gicon         (GvcMixerCard *card);
5110
 
+
5111
 
+/* private */
5112
 
+gboolean              gvc_mixer_card_set_name          (GvcMixerCard *card,
5113
 
+                                                        const char   *name);
5114
 
+gboolean              gvc_mixer_card_set_icon_name     (GvcMixerCard *card,
5115
 
+                                                        const char   *name);
5116
 
+gboolean              gvc_mixer_card_set_profile       (GvcMixerCard *card,
5117
 
+                                                        const char   *profile);
5118
 
+gboolean              gvc_mixer_card_set_profiles      (GvcMixerCard *card,
5119
 
+                                                        GList        *profiles);
5120
 
+gboolean              gvc_mixer_card_set_ports         (GvcMixerCard *stream,
5121
 
+                                                        GList        *ports);
5122
 
+
5123
 
+static int
5124
 
+sort_profiles (GvcMixerCardProfile *a,
5125
 
+               GvcMixerCardProfile *b)
5126
 
+{
5127
 
+        if (a->priority == b->priority)
5128
 
+                return 0;
5129
 
+        if (a->priority > b->priority)
5130
 
+                return 1;
5131
 
+        return -1;
5132
 
+}
5133
 
+
5134
 
+G_END_DECLS
5135
 
+
5136
 
+#endif /* __GVC_MIXER_CARD_H */
5137
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-control-private.h
5138
 
===================================================================
5139
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
5140
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-control-private.h     2012-08-28 17:08:49.444516900 +0200
5141
 
@@ -0,0 +1,35 @@
5142
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
5143
 
+ *
5144
 
+ * Copyright (C) 2008 Red Hat, Inc.
5145
 
+ *
5146
 
+ * This program is free software; you can redistribute it and/or modify
5147
 
+ * it under the terms of the GNU General Public License as published by
5148
 
+ * the Free Software Foundation; either version 2 of the License, or
5149
 
+ * (at your option) any later version.
5150
 
+ *
5151
 
+ * This program is distributed in the hope that it will be useful,
5152
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
5153
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5154
 
+ * GNU General Public License for more details.
5155
 
+ *
5156
 
+ * You should have received a copy of the GNU General Public License
5157
 
+ * along with this program; if not, write to the Free Software
5158
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
5159
 
+ *
5160
 
+ */
5161
 
+
5162
 
+#ifndef __GVC_MIXER_CONTROL_PRIVATE_H
5163
 
+#define __GVC_MIXER_CONTROL_PRIVATE_H
5164
 
+
5165
 
+#include <glib-object.h>
5166
 
+#include <pulse/pulseaudio.h>
5167
 
+#include "gvc-mixer-stream.h"
5168
 
+#include "gvc-mixer-card.h"
5169
 
+
5170
 
+G_BEGIN_DECLS
5171
 
+
5172
 
+pa_context *        gvc_mixer_control_get_pa_context      (GvcMixerControl *control);
5173
 
+
5174
 
+G_END_DECLS
5175
 
+
5176
 
+#endif /* __GVC_MIXER_CONTROL_PRIVATE_H */
5177
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-control.c
5178
 
===================================================================
5179
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
5180
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-control.c     2012-08-28 17:08:49.452516900 +0200
5181
 
@@ -0,0 +1,3374 @@
5182
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
5183
 
+ *
5184
 
+ * Copyright (C) 2006-2008 Lennart Poettering
5185
 
+ * Copyright (C) 2008 Sjoerd Simons <sjoerd@luon.net>
5186
 
+ * Copyright (C) 2008 William Jon McCann
5187
 
+ * Copyright (C) 2012 Conor Curran
5188
 
+ *
5189
 
+ * This program is free software; you can redistribute it and/or modify
5190
 
+ * it under the terms of the GNU General Public License as published by
5191
 
+ * the Free Software Foundation; either version 2 of the License, or
5192
 
+ * (at your option) any later version.
5193
 
+ *
5194
 
+ * This program is distributed in the hope that it will be useful,
5195
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
5196
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5197
 
+ * GNU General Public License for more details.
5198
 
+ *
5199
 
+ * You should have received a copy of the GNU General Public License
5200
 
+ * along with this program; if not, write to the Free Software
5201
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
5202
 
+ */
5203
 
+
5204
 
+#include "config.h"
5205
 
+
5206
 
+#include <stdlib.h>
5207
 
+#include <stdio.h>
5208
 
+#include <unistd.h>
5209
 
+
5210
 
+#include <glib.h>
5211
 
+#include <glib/gi18n-lib.h>
5212
 
+
5213
 
+#include <pulse/pulseaudio.h>
5214
 
+#include <pulse/glib-mainloop.h>
5215
 
+#include <pulse/ext-stream-restore.h>
5216
 
+
5217
 
+#include "gvc-mixer-control.h"
5218
 
+#include "gvc-mixer-sink.h"
5219
 
+#include "gvc-mixer-source.h"
5220
 
+#include "gvc-mixer-sink-input.h"
5221
 
+#include "gvc-mixer-source-output.h"
5222
 
+#include "gvc-mixer-event-role.h"
5223
 
+#include "gvc-mixer-card.h"
5224
 
+#include "gvc-mixer-card-private.h"
5225
 
+#include "gvc-channel-map-private.h"
5226
 
+#include "gvc-mixer-control-private.h"
5227
 
+
5228
 
+#define GVC_MIXER_CONTROL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControlPrivate))
5229
 
+
5230
 
+#define RECONNECT_DELAY 5
5231
 
+
5232
 
+enum {
5233
 
+        PROP_0,
5234
 
+        PROP_NAME
5235
 
+};
5236
 
+
5237
 
+struct GvcMixerControlPrivate
5238
 
+{
5239
 
+        pa_glib_mainloop *pa_mainloop;
5240
 
+        pa_mainloop_api  *pa_api;
5241
 
+        pa_context       *pa_context;
5242
 
+        int               n_outstanding;
5243
 
+        guint             reconnect_id;
5244
 
+        char             *name;
5245
 
+
5246
 
+        gboolean          default_sink_is_set;
5247
 
+        guint             default_sink_id;
5248
 
+        guint             active_output_id;
5249
 
+        char             *default_sink_name;
5250
 
+        gboolean          default_source_is_set;
5251
 
+        guint             default_source_id;
5252
 
+        char             *default_source_name;
5253
 
+
5254
 
+        gboolean          event_sink_input_is_set;
5255
 
+        guint             event_sink_input_id;
5256
 
+
5257
 
+        GHashTable       *all_streams;
5258
 
+        GHashTable       *sinks; /* fixed outputs */
5259
 
+        GHashTable       *sources; /* fixed inputs */
5260
 
+        GHashTable       *sink_inputs; /* routable output streams */
5261
 
+        GHashTable       *source_outputs; /* routable input streams */
5262
 
+        GHashTable       *clients;
5263
 
+        GHashTable       *cards;
5264
 
+        GHashTable       *ui_outputs; /* Ui visible outputs */
5265
 
+        GHashTable       *ui_inputs; /* Ui visible inputs */      
5266
 
+        GvcMixerStream   *new_default_stream; /* new default stream, used in gvc_mixer_control_set_default_sink/source () */
5267
 
+        gboolean          new_default_is_source; /* true if currently setting the default source, false if setting the default sink */
5268
 
+
5269
 
+        /*
5270
 
+        When we change profile on a device that is not the server default sink,
5271
 
+        it will jump back to the default sink set by the server to prevent the audio setup from being 'outputless'.
5272
 
+        All well and good but then when we get the new stream created for the new profile how do we know 
5273
 
+        that this is the intended default or selected device the user wishes to use.
5274
 
+        */        
5275
 
+        guint            profile_swapping_device_id;
5276
 
+        GvcMixerControlState state;
5277
 
+};
5278
 
+
5279
 
+enum {
5280
 
+        STATE_CHANGED,
5281
 
+        STREAM_ADDED,
5282
 
+        STREAM_REMOVED,
5283
 
+        CARD_ADDED,
5284
 
+        CARD_REMOVED,
5285
 
+        DEFAULT_SINK_CHANGED,
5286
 
+        DEFAULT_SOURCE_CHANGED,
5287
 
+        OUTPUT_ADDED,
5288
 
+        ACTIVE_OUTPUT_UPDATE,        
5289
 
+        ACTIVE_INPUT_UPDATE,        
5290
 
+        INPUT_ADDED,
5291
 
+        OUTPUT_REMOVED,
5292
 
+        INPUT_REMOVED,
5293
 
+        LAST_SIGNAL
5294
 
+};
5295
 
+
5296
 
+static guint signals [LAST_SIGNAL] = { 0, };
5297
 
+
5298
 
+static void                     gvc_mixer_control_class_init (GvcMixerControlClass *klass);
5299
 
+static void                     gvc_mixer_control_init       (GvcMixerControl      *mixer_control);
5300
 
+static void                     gvc_mixer_control_finalize   (GObject              *object);
5301
 
+
5302
 
+G_DEFINE_TYPE (GvcMixerControl, gvc_mixer_control, G_TYPE_OBJECT)
5303
 
+
5304
 
+pa_context *
5305
 
+gvc_mixer_control_get_pa_context (GvcMixerControl *control)
5306
 
+{
5307
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5308
 
+        return control->priv->pa_context;
5309
 
+}
5310
 
+
5311
 
+/**
5312
 
+ * gvc_mixer_control_get_event_sink_input:
5313
 
+ *
5314
 
+ * @control:
5315
 
+ *
5316
 
+ * Returns: (transfer none):
5317
 
+ */
5318
 
+GvcMixerStream *
5319
 
+gvc_mixer_control_get_event_sink_input (GvcMixerControl *control)
5320
 
+{
5321
 
+        GvcMixerStream *stream;
5322
 
+
5323
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5324
 
+
5325
 
+        stream = g_hash_table_lookup (control->priv->all_streams,
5326
 
+                                      GUINT_TO_POINTER (control->priv->event_sink_input_id));
5327
 
+
5328
 
+        return stream;
5329
 
+}
5330
 
+
5331
 
+static void
5332
 
+gvc_mixer_control_stream_restore_cb (pa_context *c,
5333
 
+                                     const pa_ext_stream_restore_info *info,
5334
 
+                                     int eol,
5335
 
+                                     void *userdata)
5336
 
+{
5337
 
+        pa_operation *o;
5338
 
+        char *prefix;
5339
 
+        GvcMixerControl *control = (GvcMixerControl *) userdata;
5340
 
+        pa_ext_stream_restore_info new_info;
5341
 
+
5342
 
+        if (eol || control->priv->new_default_stream == NULL)
5343
 
+                return;
5344
 
+
5345
 
+        /* Don't change inputs to outputs and vice versa */
5346
 
+        prefix = control->priv->new_default_is_source ? "source-output-by" : "sink-input-by";
5347
 
+        if (!g_str_has_prefix(info->name, prefix))
5348
 
+                return;
5349
 
+
5350
 
+        new_info.name = info->name;
5351
 
+        new_info.channel_map = info->channel_map;
5352
 
+        new_info.volume = info->volume;
5353
 
+        new_info.mute = info->mute;
5354
 
+
5355
 
+        new_info.device = gvc_mixer_stream_get_name (control->priv->new_default_stream);
5356
 
+
5357
 
+        o = pa_ext_stream_restore_write (control->priv->pa_context,
5358
 
+                                         PA_UPDATE_REPLACE,
5359
 
+                                         &new_info, 1,
5360
 
+                                         TRUE, NULL, NULL);
5361
 
+
5362
 
+        if (o == NULL) {
5363
 
+                g_warning ("pa_ext_stream_restore_write() failed: %s",
5364
 
+                           pa_strerror (pa_context_errno (control->priv->pa_context)));
5365
 
+                return;
5366
 
+        }
5367
 
+
5368
 
+        g_debug ("Changed default device for %s to %s", info->name, new_info.device);
5369
 
+
5370
 
+        pa_operation_unref (o);
5371
 
+}
5372
 
+
5373
 
+/**
5374
 
+ * gvc_mixer_control_lookup_device_from_stream:
5375
 
+ * @control:
5376
 
+ * @stream:
5377
 
+ * Returns: GvcUIDevice (transfer none) or NULL:
5378
 
+ */
5379
 
+static GvcMixerUIDevice *
5380
 
+gvc_mixer_control_lookup_device_from_stream (GvcMixerControl *control,
5381
 
+                                             GvcMixerStream *stream)
5382
 
+{
5383
 
+       GList                   *devices;
5384
 
+       GList                   *d;
5385
 
+       GvcMixerUIDevice        *device;                        
5386
 
+
5387
 
+        if (GVC_IS_MIXER_SOURCE (stream))
5388
 
+               devices = g_hash_table_get_values (control->priv->ui_inputs);                
5389
 
+        else{
5390
 
+               devices = g_hash_table_get_values (control->priv->ui_outputs);
5391
 
+        }
5392
 
+
5393
 
+        gboolean is_network_stream;
5394
 
+        const GList *ports;
5395
 
+        ports = gvc_mixer_stream_get_ports (stream);
5396
 
+
5397
 
+        // really this should be called 'is_network_or_bluetooth_stream'
5398
 
+        is_network_stream = ports == NULL;
5399
 
+
5400
 
+       for (d = devices; d != NULL; d = d->next) {             
5401
 
+               device = d->data;
5402
 
+               gint stream_id = -2;
5403
 
+
5404
 
+               g_object_get (G_OBJECT (device),
5405
 
+                            "stream-id", &stream_id,
5406
 
+                             NULL);
5407
 
+
5408
 
+                if (is_network_stream) {
5409
 
+                        if (stream_id == gvc_mixer_stream_get_id (stream)) {
5410
 
+                                g_debug ("\n lookup device from stream - %s - it is a network_stream \n",
5411
 
+                                        gvc_mixer_ui_device_get_description (device));
5412
 
+                                return device;
5413
 
+                        }       
5414
 
+                }
5415
 
+                else {
5416
 
+                        const GvcMixerStreamPort *port;
5417
 
+                        port = gvc_mixer_stream_get_port (stream);
5418
 
+
5419
 
+                       if (stream_id == gvc_mixer_stream_get_id (stream) &&
5420
 
+                            g_strcmp0 (gvc_mixer_ui_device_get_port(device),
5421
 
+                                       port->port) == 0) {
5422
 
+                                g_debug ("\n \n lookup-device-from-stream found device  \n device description %s \n device port = %s \n device stream id %i \n AND \n stream port = %s stream id %u and stream description %s \n",
5423
 
+                                         gvc_mixer_ui_device_get_description (device),
5424
 
+                                         gvc_mixer_ui_device_get_port(device),                                 
5425
 
+                                         stream_id,
5426
 
+                                         port->port,
5427
 
+                                         gvc_mixer_stream_get_id (stream),
5428
 
+                                         gvc_mixer_stream_get_description (stream));
5429
 
+                               return device;
5430
 
+                       }
5431
 
+                }
5432
 
+       }
5433
 
+       g_debug ("\n gvc_mixer_control_lookup_device_from_stream - Could not find a device ?  %s \n",gvc_mixer_stream_get_description (stream));                 
5434
 
+       return NULL;
5435
 
+}
5436
 
+
5437
 
+gboolean
5438
 
+gvc_mixer_control_set_default_sink (GvcMixerControl *control,
5439
 
+                                    GvcMixerStream  *stream)
5440
 
+{
5441
 
+        pa_operation *o;
5442
 
+
5443
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE);
5444
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
5445
 
+
5446
 
+        g_debug ("\n about to set default sink on server \n");
5447
 
+        o = pa_context_set_default_sink (control->priv->pa_context,
5448
 
+                                         gvc_mixer_stream_get_name (stream),
5449
 
+                                         NULL,
5450
 
+                                         NULL);
5451
 
+        if (o == NULL) {
5452
 
+                g_warning ("pa_context_set_default_sink() failed: %s",
5453
 
+                           pa_strerror (pa_context_errno (control->priv->pa_context)));
5454
 
+                return FALSE;
5455
 
+        }
5456
 
+
5457
 
+        pa_operation_unref (o);
5458
 
+
5459
 
+        control->priv->new_default_stream = stream;
5460
 
+        control->priv->new_default_is_source = FALSE;
5461
 
+        g_object_add_weak_pointer (G_OBJECT (stream), (gpointer *) &control->priv->new_default_stream);
5462
 
+
5463
 
+        o = pa_ext_stream_restore_read (control->priv->pa_context,
5464
 
+                                        gvc_mixer_control_stream_restore_cb,
5465
 
+                                        control);
5466
 
+
5467
 
+        if (o == NULL) {
5468
 
+                g_warning ("pa_ext_stream_restore_read() failed: %s",
5469
 
+                           pa_strerror (pa_context_errno (control->priv->pa_context)));
5470
 
+                return FALSE;
5471
 
+        }
5472
 
+
5473
 
+        pa_operation_unref (o);
5474
 
+        
5475
 
+        return TRUE;
5476
 
+}
5477
 
+
5478
 
+gboolean
5479
 
+gvc_mixer_control_set_default_source (GvcMixerControl *control,
5480
 
+                                      GvcMixerStream  *stream)
5481
 
+{
5482
 
+        pa_operation *o;
5483
 
+
5484
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE);
5485
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
5486
 
+
5487
 
+        o = pa_context_set_default_source (control->priv->pa_context,
5488
 
+                                           gvc_mixer_stream_get_name (stream),
5489
 
+                                           NULL,
5490
 
+                                           NULL);
5491
 
+        if (o == NULL) {
5492
 
+                g_warning ("pa_context_set_default_source() failed");
5493
 
+                return FALSE;
5494
 
+        }
5495
 
+
5496
 
+        pa_operation_unref (o);
5497
 
+
5498
 
+        control->priv->new_default_stream = stream;
5499
 
+        control->priv->new_default_is_source = TRUE;
5500
 
+        g_object_add_weak_pointer (G_OBJECT (stream), (gpointer *) &control->priv->new_default_stream);
5501
 
+
5502
 
+        o = pa_ext_stream_restore_read (control->priv->pa_context,
5503
 
+                                        gvc_mixer_control_stream_restore_cb,
5504
 
+                                        control);
5505
 
+
5506
 
+        if (o == NULL) {
5507
 
+                g_warning ("pa_ext_stream_restore_read() failed: %s",
5508
 
+                           pa_strerror (pa_context_errno (control->priv->pa_context)));
5509
 
+                return FALSE;
5510
 
+        }
5511
 
+
5512
 
+        pa_operation_unref (o);
5513
 
+
5514
 
+        // source change successfull => update the UI.
5515
 
+        GvcMixerUIDevice* input;
5516
 
+        input = gvc_mixer_control_lookup_device_from_stream (control, stream);
5517
 
+        g_signal_emit (G_OBJECT (control),
5518
 
+                       signals[ACTIVE_INPUT_UPDATE],
5519
 
+                       0,
5520
 
+                       gvc_mixer_ui_device_get_id (input));             
5521
 
+
5522
 
+        return TRUE;
5523
 
+}
5524
 
+
5525
 
+/**
5526
 
+ * gvc_mixer_control_get_default_sink:
5527
 
+ *
5528
 
+ * @control:
5529
 
+ *
5530
 
+ * Returns: (transfer none):
5531
 
+ */
5532
 
+GvcMixerStream *
5533
 
+gvc_mixer_control_get_default_sink (GvcMixerControl *control)
5534
 
+{
5535
 
+        GvcMixerStream *stream;
5536
 
+
5537
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5538
 
+
5539
 
+        if (control->priv->default_sink_is_set) {
5540
 
+                stream = g_hash_table_lookup (control->priv->all_streams,
5541
 
+                                              GUINT_TO_POINTER (control->priv->default_sink_id));
5542
 
+        } else {
5543
 
+                stream = NULL;
5544
 
+        }
5545
 
+
5546
 
+        return stream;
5547
 
+}
5548
 
+
5549
 
+/**
5550
 
+ * gvc_mixer_control_get_default_source:
5551
 
+ *
5552
 
+ * @control:
5553
 
+ *
5554
 
+ * Returns: (transfer none):
5555
 
+ */
5556
 
+GvcMixerStream *
5557
 
+gvc_mixer_control_get_default_source (GvcMixerControl *control)
5558
 
+{
5559
 
+        GvcMixerStream *stream;
5560
 
+
5561
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5562
 
+
5563
 
+        if (control->priv->default_source_is_set) {
5564
 
+                stream = g_hash_table_lookup (control->priv->all_streams,
5565
 
+                                              GUINT_TO_POINTER (control->priv->default_source_id));
5566
 
+        } else {
5567
 
+                stream = NULL;
5568
 
+        }
5569
 
+
5570
 
+        return stream;
5571
 
+}
5572
 
+
5573
 
+static gpointer
5574
 
+gvc_mixer_control_lookup_id (GHashTable *hash_table,
5575
 
+                             guint       id)
5576
 
+{
5577
 
+        return g_hash_table_lookup (hash_table,
5578
 
+                                    GUINT_TO_POINTER (id));
5579
 
+}
5580
 
+
5581
 
+/**
5582
 
+ * gvc_mixer_control_lookup_stream_id:
5583
 
+ *
5584
 
+ * @control:
5585
 
+ * @id:
5586
 
+ *
5587
 
+ * Returns: (transfer none):
5588
 
+ */
5589
 
+GvcMixerStream *
5590
 
+gvc_mixer_control_lookup_stream_id (GvcMixerControl *control,
5591
 
+                                    guint            id)
5592
 
+{
5593
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5594
 
+
5595
 
+        return gvc_mixer_control_lookup_id (control->priv->all_streams, id);
5596
 
+}
5597
 
+
5598
 
+/**
5599
 
+ * gvc_mixer_control_lookup_card_id:
5600
 
+ *
5601
 
+ * @control:
5602
 
+ * @id:
5603
 
+ *
5604
 
+ * Returns: (transfer none):
5605
 
+ */
5606
 
+GvcMixerCard *
5607
 
+gvc_mixer_control_lookup_card_id (GvcMixerControl *control,
5608
 
+                                  guint            id)
5609
 
+{
5610
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5611
 
+        return gvc_mixer_control_lookup_id (control->priv->cards, id);
5612
 
+}
5613
 
+
5614
 
+/**
5615
 
+ * gvc_mixer_control_lookup_output_id:
5616
 
+ * @control:
5617
 
+ * @id:
5618
 
+ * Returns: (transfer none):
5619
 
+ */
5620
 
+GvcMixerUIDevice*      
5621
 
+gvc_mixer_control_lookup_output_id (GvcMixerControl *control,
5622
 
+                                   guint            id)
5623
 
+{
5624
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5625
 
+
5626
 
+        return gvc_mixer_control_lookup_id (control->priv->ui_outputs, id);    
5627
 
+}
5628
 
+
5629
 
+/**
5630
 
+ * gvc_mixer_control_lookup_input_id:
5631
 
+ * @control:
5632
 
+ * @id:
5633
 
+ * Returns: (transfer none):
5634
 
+ */
5635
 
+GvcMixerUIDevice*       
5636
 
+gvc_mixer_control_lookup_input_id (GvcMixerControl *control,
5637
 
+                                    guint            id)
5638
 
+{
5639
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5640
 
+
5641
 
+        return gvc_mixer_control_lookup_id (control->priv->ui_inputs, id);     
5642
 
+}
5643
 
+
5644
 
+/**
5645
 
+ * gvc_mixer_control_get_active_profile_from_ui_device:
5646
 
+ * @control: GvcMixerControl*
5647
 
+ * @device: GvcMixerUIDevice*
5648
 
+ * Returns: (transfer container) (element-type gchar*):
5649
 
+   The profile full name stored in that device
5650
 
+   TODO: This belongs within the GvcMixerUIDevice.
5651
 
+ */
5652
 
+const gchar*
5653
 
+gvc_mixer_control_get_active_profile_from_ui_device (GvcMixerControl* control,
5654
 
+                                                     GvcMixerUIDevice* device)
5655
 
+{
5656
 
+        guint card_id;
5657
 
+        g_object_get (G_OBJECT (device), "card-id", &card_id, NULL);
5658
 
+        if (card_id == GVC_MIXER_UI_DEVICE_INVALID){
5659
 
+                g_warning ("device did not have an appropriate card id");
5660
 
+                return NULL;
5661
 
+        }
5662
 
+        GvcMixerCard *card;
5663
 
+        card = gvc_mixer_control_lookup_card_id (control, card_id);
5664
 
+        GvcMixerCardProfile *profile;
5665
 
+        profile = gvc_mixer_card_get_profile (card);
5666
 
+        return gvc_mixer_ui_device_get_matching_profile(device, profile->profile);
5667
 
+}
5668
 
+
5669
 
+/**
5670
 
+ * gvc_mixer_control_get_stream_from_device:
5671
 
+ * @control:
5672
 
+ * @dev
5673
 
+ * Returns: (transfer container) (element-type Gvc.MixerStream):
5674
 
+ */
5675
 
+GvcMixerStream*
5676
 
+gvc_mixer_control_get_stream_from_device (GvcMixerControl *control,
5677
 
+                                          GvcMixerUIDevice *dev)
5678
 
+{
5679
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5680
 
+        g_return_val_if_fail (GVC_IS_MIXER_UI_DEVICE (dev), NULL);
5681
 
+        
5682
 
+        gint stream_id = gvc_mixer_ui_device_get_stream_id (dev);
5683
 
+        
5684
 
+        if (stream_id == GVC_MIXER_UI_DEVICE_INVALID) {
5685
 
+                g_debug ("gvc_mixer_control_get_stream_from_device - device has a null stream");
5686
 
+                return NULL;
5687
 
+        }       
5688
 
+        return gvc_mixer_control_lookup_stream_id (control, stream_id);
5689
 
+}                                                             
5690
 
+/**
5691
 
+ * gvc_mixer_control_change_profile_on_selected_device:
5692
 
+ * @control:
5693
 
+ * @device:
5694
 
+ * @param profile Can be null if any profile present on this port is okay
5695
 
+ * Returns: (transfer container) (element-type gboolean):
5696
 
+   This method will attempt to swap the profile on the card of the device with given profile name
5697
 
+   If successfull it will set the preferred profile on that device so as we know the next time the user
5698
 
+   moves to that device it should have this profile active. 
5699
 
+ */
5700
 
+gboolean
5701
 
+gvc_mixer_control_change_profile_on_selected_device (GvcMixerControl *control,
5702
 
+                                                     GvcMixerUIDevice *device,
5703
 
+                                                     const gchar* profile)                                                    
5704
 
+{
5705
 
+        guint card_id;
5706
 
+        const gchar *best_profile;
5707
 
+        GvcMixerCardProfile *current_profile;
5708
 
+        g_object_get ( G_OBJECT(device), "card-id", &card_id, NULL);
5709
 
+        
5710
 
+        if (card_id == GVC_MIXER_UI_DEVICE_INVALID){
5711
 
+                g_warning ("gvc_mixer_control_change_profile - no card => different profile but cant find a valid card id ?");
5712
 
+                return;
5713
 
+        }
5714
 
+        GvcMixerCard *card;
5715
 
+        card = gvc_mixer_control_lookup_card_id (control, card_id);     
5716
 
+        current_profile = gvc_mixer_card_get_profile (card);
5717
 
+        
5718
 
+        if (current_profile)
5719
 
+                best_profile = gvc_mixer_ui_device_get_best_profile (device, profile, current_profile->profile);
5720
 
+        else
5721
 
+                best_profile = profile;
5722
 
+        
5723
 
+        g_assert(best_profile);
5724
 
+
5725
 
+        g_debug ("Selected '%s', moving to profile '%s' on card '%s' on stream id %i \n",
5726
 
+                profile ? profile : "(any)", best_profile,
5727
 
+                gvc_mixer_card_get_name (card),
5728
 
+                gvc_mixer_ui_device_get_stream_id (device));
5729
 
+        
5730
 
+        g_debug ("\n default sink name = %s \n and default sink id %u",
5731
 
+                 control->priv->default_sink_name,
5732
 
+                 control->priv->default_sink_id);
5733
 
+
5734
 
+        control->priv->profile_swapping_device_id = gvc_mixer_ui_device_get_id (device);
5735
 
+
5736
 
+        if (gvc_mixer_card_change_profile (card, best_profile)) {
5737
 
+                gvc_mixer_ui_device_set_user_preferred_profile (device, best_profile);
5738
 
+                return TRUE;
5739
 
+        }
5740
 
+        return FALSE;
5741
 
+}                                                     
5742
 
+
5743
 
+/**
5744
 
+ * gvc_mixer_control_change_output:
5745
 
+ * @control:
5746
 
+ * @output:
5747
 
+ This method is called from the UI when the user selects a previously unselected device.
5748
 
+ - Firstly it queries the stream from the device.
5749
 
+   - It assumes that if the stream is null that it cannot be a bluetooth or network stream (they never show unless they have valid sinks and sources)
5750
 
+   In the scenario of a NULL stream on the device
5751
 
+        - It fetches the device's preferred profile or if NUll the profile with the highest priority on that device.
5752
 
+        - It then caches this device in control->priv->cached_desired_output_id so that when the update_sink triggered
5753
 
+          from when we attempt to change profile we will know exactly what device to highlight on that stream.
5754
 
+        - It attempts to swap the profile on the card from that device and returns.
5755
 
+ - Next, it handles network or bluetooth streams that only require their stream to be made the default.
5756
 
+ - Next it deals with port changes so if the stream's active port is not the same as the port on the device
5757
 
+   it will attempt to change the port on that stream to be same as the device. If this fails it will return.
5758
 
+ - Finally it will set this new stream to be the default stream and emit a signal for the UI confirming the active output device.
5759
 
+ */                                                 
5760
 
+void
5761
 
+gvc_mixer_control_change_output (GvcMixerControl *control,
5762
 
+                                 GvcMixerUIDevice* output)
5763
 
+{
5764
 
+        g_debug ("\n control change output \n");
5765
 
+        GvcMixerStream *stream;
5766
 
+        GvcMixerStream *default_stream;
5767
 
+
5768
 
+        stream = gvc_mixer_control_get_stream_from_device (control, output);
5769
 
+        if (stream == NULL){
5770
 
+                gvc_mixer_control_change_profile_on_selected_device (control,
5771
 
+                        output, NULL);
5772
 
+                return;
5773
 
+        }
5774
 
+
5775
 
+        // Handle a network sink => a portless or cardless device
5776
 
+        if (gvc_mixer_ui_device_is_software (output) || gvc_mixer_ui_device_is_bluetooth (output)){
5777
 
+                g_debug ("Did we try to move to a software/bluetooth sink ? \n");
5778
 
+                if (gvc_mixer_control_set_default_sink (control, stream)) {
5779
 
+                        // sink change successfull => update the UI.
5780
 
+                        g_signal_emit (G_OBJECT (control),
5781
 
+                                       signals[ACTIVE_OUTPUT_UPDATE],
5782
 
+                                       0,
5783
 
+                                       gvc_mixer_ui_device_get_id (output));             
5784
 
+                }
5785
 
+                else{
5786
 
+                        g_warning ("Failed to set default sink with stream from output %s \n",
5787
 
+                                   gvc_mixer_ui_device_get_description (output));
5788
 
+                }
5789
 
+                return;
5790
 
+        }
5791
 
+
5792
 
+       const GvcMixerStreamPort* active_port = gvc_mixer_stream_get_port (stream);
5793
 
+       const gchar* output_port = gvc_mixer_ui_device_get_port (output);
5794
 
+        // First ensure the correct port is active on the sink
5795
 
+       if (g_strcmp0 (active_port->port, output_port) != 0){
5796
 
+               g_debug ("\n Port change, switch to = %s \n", 
5797
 
+                         output_port); 
5798
 
+               if (gvc_mixer_stream_change_port (stream, output_port) == FALSE){
5799
 
+                        g_warning ("\n Could not change port ! \n");
5800
 
+                        return;
5801
 
+               }
5802
 
+        }
5803
 
+
5804
 
+        default_stream = gvc_mixer_control_get_default_sink (control);  
5805
 
+        
5806
 
+        // Finally if we are not on the correct stream, swap over.
5807
 
+       if (stream != default_stream){
5808
 
+                g_debug ("\n\n !!!!Attempting to swap over to stream %s \n",
5809
 
+                         gvc_mixer_stream_get_description(stream));
5810
 
+                GvcMixerUIDevice* output;
5811
 
+                if (gvc_mixer_control_set_default_sink (control, stream)){
5812
 
+                        output = gvc_mixer_control_lookup_device_from_stream (control, stream);
5813
 
+                        g_signal_emit (G_OBJECT (control),
5814
 
+                                       signals[ACTIVE_OUTPUT_UPDATE],
5815
 
+                                       0,
5816
 
+                                       gvc_mixer_ui_device_get_id (output));                                  
5817
 
+                }
5818
 
+                else{
5819
 
+                        // If the move failed for some reason reset the UI.
5820
 
+                        output = gvc_mixer_control_lookup_device_from_stream (control, default_stream);
5821
 
+                        g_signal_emit (G_OBJECT (control),
5822
 
+                                       signals[ACTIVE_OUTPUT_UPDATE],
5823
 
+                                       0,
5824
 
+                                       gvc_mixer_ui_device_get_id (output));                                  
5825
 
+                        
5826
 
+                }
5827
 
+        }
5828
 
+}
5829
 
+
5830
 
+
5831
 
+/**
5832
 
+ * gvc_mixer_control_change_input:
5833
 
+ * @control:
5834
 
+ * @input:
5835
 
+ This method is called from the UI when the user selects a previously unselected device.
5836
 
+ - Firstly it queries the stream from the device.
5837
 
+   - It assumes that if the stream is null that it cannot be a bluetooth or network stream (they never show unless they have valid sinks and sources)
5838
 
+   In the scenario of a NULL stream on the device
5839
 
+        - It fetches the device's preferred profile or if NUll the profile with the highest priority on that device.
5840
 
+        - It then caches this device in control->priv->cached_desired_input_id so that when the update_source triggered
5841
 
+          from when we attempt to change profile we will know exactly what device to highlight on that stream.
5842
 
+        - It attempts to swap the profile on the card from that device and returns.
5843
 
+ - Next, it handles network or bluetooth streams that only require their stream to be made the default.
5844
 
+ - Next it deals with port changes so if the stream's active port is not the same as the port on the device
5845
 
+   it will attempt to change the port on that stream to be same as the device. If this fails it will return.
5846
 
+ - Finally it will set this new stream to be the default stream and emit a signal for the UI confirming the active input device.
5847
 
+ */
5848
 
+void
5849
 
+gvc_mixer_control_change_input (GvcMixerControl *control,
5850
 
+                                GvcMixerUIDevice* input)
5851
 
+{
5852
 
+        GvcMixerStream *stream;
5853
 
+        GvcMixerStream *default_stream;
5854
 
+
5855
 
+        stream = gvc_mixer_control_get_stream_from_device (control, input);
5856
 
+        if (stream == NULL){
5857
 
+                gvc_mixer_control_change_profile_on_selected_device (control,
5858
 
+                        input, NULL);
5859
 
+                return;
5860
 
+        }
5861
 
+
5862
 
+        // Handle a network sink => a portless/cardless device
5863
 
+        if (gvc_mixer_ui_device_is_software (input) || gvc_mixer_ui_device_is_bluetooth (input)){
5864
 
+                g_debug ("\n Did we try to move to a software/bluetooth source ? \n");
5865
 
+                if (! gvc_mixer_control_set_default_source (control, stream)) {
5866
 
+                        g_warning ("Failed to set default source with stream from input %s \n",
5867
 
+                                   gvc_mixer_ui_device_get_description (input));
5868
 
+                }
5869
 
+                return;
5870
 
+        }
5871
 
+
5872
 
+        const GvcMixerStreamPort* active_port = gvc_mixer_stream_get_port (stream);
5873
 
+        const gchar* input_port = gvc_mixer_ui_device_get_port (input);
5874
 
+        // First ensure the correct port is active on the sink
5875
 
+        if (g_strcmp0 (active_port->port, input_port) != 0){
5876
 
+                g_debug ("\n Port change, switch to = %s \n", 
5877
 
+                          input_port); 
5878
 
+                if (gvc_mixer_stream_change_port (stream, input_port) == FALSE){
5879
 
+                        g_warning ("\n Could not change port ! \n");
5880
 
+                        return;
5881
 
+                }
5882
 
+        }
5883
 
+
5884
 
+        default_stream = gvc_mixer_control_get_default_source (control);   
5885
 
+        
5886
 
+        // Finally if we are not on the correct stream, swap over.              
5887
 
+        if (stream != default_stream){
5888
 
+                g_debug ("\n change-input - attempting to swap over to stream %s \n",
5889
 
+                         gvc_mixer_stream_get_description(stream));
5890
 
+                gvc_mixer_control_set_default_source (control, stream);
5891
 
+        }
5892
 
+}
5893
 
+
5894
 
+
5895
 
+static void
5896
 
+listify_hash_values_hfunc (gpointer key,
5897
 
+                           gpointer value,
5898
 
+                           gpointer user_data)
5899
 
+{
5900
 
+        GSList **list = user_data;
5901
 
+
5902
 
+        *list = g_slist_prepend (*list, value);
5903
 
+}
5904
 
+
5905
 
+static int
5906
 
+gvc_name_collate (const char *namea,
5907
 
+                  const char *nameb)
5908
 
+{
5909
 
+        if (nameb == NULL && namea == NULL)
5910
 
+                return 0;
5911
 
+        if (nameb == NULL)
5912
 
+                return 1;
5913
 
+        if (namea == NULL)
5914
 
+                return -1;
5915
 
+
5916
 
+        return g_utf8_collate (namea, nameb);
5917
 
+}
5918
 
+
5919
 
+static int
5920
 
+gvc_card_collate (GvcMixerCard *a,
5921
 
+                  GvcMixerCard *b)
5922
 
+{
5923
 
+        const char *namea;
5924
 
+        const char *nameb;
5925
 
+
5926
 
+        g_return_val_if_fail (a == NULL || GVC_IS_MIXER_CARD (a), 0);
5927
 
+        g_return_val_if_fail (b == NULL || GVC_IS_MIXER_CARD (b), 0);
5928
 
+
5929
 
+        namea = gvc_mixer_card_get_name (a);
5930
 
+        nameb = gvc_mixer_card_get_name (b);
5931
 
+
5932
 
+        return gvc_name_collate (namea, nameb);
5933
 
+}
5934
 
+
5935
 
+/**
5936
 
+ * gvc_mixer_control_get_cards:
5937
 
+ *
5938
 
+ * @control:
5939
 
+ *
5940
 
+ * Returns: (transfer container) (element-type Gvc.MixerCard):
5941
 
+ */
5942
 
+GSList *
5943
 
+gvc_mixer_control_get_cards (GvcMixerControl *control)
5944
 
+{
5945
 
+        GSList *retval;
5946
 
+
5947
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5948
 
+
5949
 
+        retval = NULL;
5950
 
+        g_hash_table_foreach (control->priv->cards,
5951
 
+                              listify_hash_values_hfunc,
5952
 
+                              &retval);
5953
 
+        return g_slist_sort (retval, (GCompareFunc) gvc_card_collate);
5954
 
+}
5955
 
+
5956
 
+static int
5957
 
+gvc_stream_collate (GvcMixerStream *a,
5958
 
+                    GvcMixerStream *b)
5959
 
+{
5960
 
+        const char *namea;
5961
 
+        const char *nameb;
5962
 
+
5963
 
+        g_return_val_if_fail (a == NULL || GVC_IS_MIXER_STREAM (a), 0);
5964
 
+        g_return_val_if_fail (b == NULL || GVC_IS_MIXER_STREAM (b), 0);
5965
 
+
5966
 
+        namea = gvc_mixer_stream_get_name (a);
5967
 
+        nameb = gvc_mixer_stream_get_name (b);
5968
 
+
5969
 
+        return gvc_name_collate (namea, nameb);
5970
 
+}
5971
 
+
5972
 
+/**
5973
 
+ * gvc_mixer_control_get_streams:
5974
 
+ *
5975
 
+ * @control:
5976
 
+ *
5977
 
+ * Returns: (transfer container) (element-type Gvc.MixerStream):
5978
 
+ */
5979
 
+GSList *
5980
 
+gvc_mixer_control_get_streams (GvcMixerControl *control)
5981
 
+{
5982
 
+        GSList *retval;
5983
 
+
5984
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5985
 
+
5986
 
+        retval = NULL;
5987
 
+        g_hash_table_foreach (control->priv->all_streams,
5988
 
+                              listify_hash_values_hfunc,
5989
 
+                              &retval);
5990
 
+        return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate);
5991
 
+}
5992
 
+
5993
 
+
5994
 
+/**
5995
 
+ * gvc_mixer_control_get_sinks:
5996
 
+ *
5997
 
+ * @control:
5998
 
+ *
5999
 
+ * Returns: (transfer container) (element-type Gvc.MixerSink):
6000
 
+ */
6001
 
+GSList *
6002
 
+gvc_mixer_control_get_sinks (GvcMixerControl *control)
6003
 
+{
6004
 
+        GSList *retval;
6005
 
+
6006
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
6007
 
+
6008
 
+        retval = NULL;
6009
 
+        g_hash_table_foreach (control->priv->sinks,
6010
 
+                              listify_hash_values_hfunc,
6011
 
+                              &retval);
6012
 
+        return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate);
6013
 
+}
6014
 
+
6015
 
+/**
6016
 
+ * gvc_mixer_control_get_sources:
6017
 
+ *
6018
 
+ * @control:
6019
 
+ *
6020
 
+ * Returns: (transfer container) (element-type Gvc.MixerSource):
6021
 
+ */
6022
 
+GSList *
6023
 
+gvc_mixer_control_get_sources (GvcMixerControl *control)
6024
 
+{
6025
 
+        GSList *retval;
6026
 
+
6027
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
6028
 
+
6029
 
+        retval = NULL;
6030
 
+        g_hash_table_foreach (control->priv->sources,
6031
 
+                              listify_hash_values_hfunc,
6032
 
+                              &retval);
6033
 
+        return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate);
6034
 
+}
6035
 
+
6036
 
+/**
6037
 
+ * gvc_mixer_control_get_sink_inputs:
6038
 
+ *
6039
 
+ * @control:
6040
 
+ *
6041
 
+ * Returns: (transfer container) (element-type Gvc.MixerSinkInput):
6042
 
+ */
6043
 
+GSList *
6044
 
+gvc_mixer_control_get_sink_inputs (GvcMixerControl *control)
6045
 
+{
6046
 
+        GSList *retval;
6047
 
+
6048
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
6049
 
+
6050
 
+        retval = NULL;
6051
 
+        g_hash_table_foreach (control->priv->sink_inputs,
6052
 
+                              listify_hash_values_hfunc,
6053
 
+                              &retval);
6054
 
+        return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate);
6055
 
+}
6056
 
+
6057
 
+/**
6058
 
+ * gvc_mixer_control_get_source_outputs:
6059
 
+ *
6060
 
+ * @control:
6061
 
+ *
6062
 
+ * Returns: (transfer container) (element-type Gvc.MixerSourceOutput):
6063
 
+ */
6064
 
+GSList *
6065
 
+gvc_mixer_control_get_source_outputs (GvcMixerControl *control)
6066
 
+{
6067
 
+        GSList *retval;
6068
 
+
6069
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
6070
 
+
6071
 
+        retval = NULL;
6072
 
+        g_hash_table_foreach (control->priv->source_outputs,
6073
 
+                              listify_hash_values_hfunc,
6074
 
+                              &retval);
6075
 
+        return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate);
6076
 
+}
6077
 
+
6078
 
+static void
6079
 
+dec_outstanding (GvcMixerControl *control)
6080
 
+{
6081
 
+        if (control->priv->n_outstanding <= 0) {
6082
 
+                return;
6083
 
+        }
6084
 
+
6085
 
+        if (--control->priv->n_outstanding <= 0) {
6086
 
+                control->priv->state = GVC_STATE_READY;
6087
 
+                g_signal_emit (G_OBJECT (control), signals[STATE_CHANGED], 0, GVC_STATE_READY);
6088
 
+        }
6089
 
+}
6090
 
+
6091
 
+GvcMixerControlState
6092
 
+gvc_mixer_control_get_state (GvcMixerControl *control)
6093
 
+{
6094
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE);
6095
 
+
6096
 
+        return control->priv->state;
6097
 
+}
6098
 
+
6099
 
+static void
6100
 
+on_default_source_port_notify (GObject        *object,
6101
 
+                               GParamSpec     *pspec,
6102
 
+                               GvcMixerControl *control)
6103
 
+{
6104
 
+        char *port;
6105
 
+        g_object_get (object, "port", &port, NULL);
6106
 
+        GvcMixerUIDevice* input;
6107
 
+        input = gvc_mixer_control_lookup_device_from_stream (control,
6108
 
+                                                             GVC_MIXER_STREAM (object));
6109
 
+                                                                      
6110
 
+        g_debug ("\n\n on_default_source_port_notify - moved to port %s \n which SHOULD ?? correspond to output \n %s \n",
6111
 
+                 port,
6112
 
+                 gvc_mixer_ui_device_get_description (input));
6113
 
+
6114
 
+        g_signal_emit (G_OBJECT (control),
6115
 
+                       signals[ACTIVE_INPUT_UPDATE],
6116
 
+                       0,
6117
 
+                       gvc_mixer_ui_device_get_id (input));       
6118
 
+
6119
 
+        g_free (port);
6120
 
+}
6121
 
+
6122
 
+
6123
 
+static void
6124
 
+_set_default_source (GvcMixerControl *control,
6125
 
+                     GvcMixerStream  *stream)
6126
 
+{
6127
 
+        guint new_id;
6128
 
+
6129
 
+        if (stream == NULL) {
6130
 
+                control->priv->default_source_id = 0;
6131
 
+                control->priv->default_source_is_set = FALSE;
6132
 
+                g_signal_emit (control,
6133
 
+                               signals[DEFAULT_SOURCE_CHANGED],
6134
 
+                               0,
6135
 
+                               PA_INVALID_INDEX);
6136
 
+                return;
6137
 
+        }
6138
 
+
6139
 
+        new_id = gvc_mixer_stream_get_id (stream);
6140
 
+
6141
 
+        if (control->priv->default_source_id != new_id) {
6142
 
+                control->priv->default_source_id = new_id;
6143
 
+                control->priv->default_source_is_set = TRUE;
6144
 
+                g_signal_emit (control,
6145
 
+                               signals[DEFAULT_SOURCE_CHANGED],
6146
 
+                               0,
6147
 
+                               new_id);
6148
 
+
6149
 
+                if (control->priv->default_source_is_set){
6150
 
+                        g_signal_handlers_disconnect_by_func (gvc_mixer_control_get_default_source (control),
6151
 
+                                                              on_default_source_port_notify,
6152
 
+                                                              control);                        
6153
 
+                }
6154
 
+
6155
 
+                g_signal_connect (stream,
6156
 
+                                  "notify::port",
6157
 
+                                  G_CALLBACK (on_default_source_port_notify),
6158
 
+                                  control);
6159
 
+
6160
 
+                GvcMixerUIDevice* input;
6161
 
+                input = gvc_mixer_control_lookup_device_from_stream (control, stream);
6162
 
+
6163
 
+                g_signal_emit (G_OBJECT (control),
6164
 
+                               signals[ACTIVE_INPUT_UPDATE],
6165
 
+                               0,
6166
 
+                               gvc_mixer_ui_device_get_id (input));
6167
 
+
6168
 
+        }
6169
 
+}
6170
 
+
6171
 
+static void
6172
 
+on_default_sink_port_notify (GObject        *object,
6173
 
+                             GParamSpec     *pspec,
6174
 
+                             GvcMixerControl *control)
6175
 
+{
6176
 
+        char *port;
6177
 
+        g_object_get (object, "port", &port, NULL);
6178
 
+        GvcMixerUIDevice* output;
6179
 
+        output = gvc_mixer_control_lookup_device_from_stream (control,
6180
 
+                                                              GVC_MIXER_STREAM (object));
6181
 
+        if (output != NULL){
6182
 
+                g_debug ("\n\n on_default_sink_port_notify - moved to port %s \n which SHOULD correspond to output %s \n",
6183
 
+                         port,
6184
 
+                         gvc_mixer_ui_device_get_description (output));
6185
 
+                g_signal_emit (G_OBJECT (control),
6186
 
+                               signals[ACTIVE_OUTPUT_UPDATE],
6187
 
+                               0,
6188
 
+                               gvc_mixer_ui_device_get_id (output));
6189
 
+        }
6190
 
+        g_free(port);
6191
 
+}
6192
 
+
6193
 
+
6194
 
+static void
6195
 
+_set_default_sink (GvcMixerControl *control,
6196
 
+                   GvcMixerStream  *stream)
6197
 
+{
6198
 
+        guint new_id;
6199
 
+
6200
 
+        if (stream == NULL) {
6201
 
+                /* Don't tell front-ends about an unset default
6202
 
+                 * sink if it's already unset */
6203
 
+                if (control->priv->default_sink_is_set == FALSE)
6204
 
+                        return;
6205
 
+                control->priv->default_sink_id = 0;
6206
 
+                control->priv->default_sink_is_set = FALSE;
6207
 
+                g_signal_emit (control,
6208
 
+                               signals[DEFAULT_SINK_CHANGED],
6209
 
+                               0,
6210
 
+                               PA_INVALID_INDEX);
6211
 
+                return;
6212
 
+        }
6213
 
+
6214
 
+        new_id = gvc_mixer_stream_get_id (stream);
6215
 
+
6216
 
+        if (control->priv->default_sink_id != new_id) {                
6217
 
+                if (control->priv->default_sink_is_set){
6218
 
+                        g_signal_handlers_disconnect_by_func (gvc_mixer_control_get_default_sink (control),
6219
 
+                                                              on_default_sink_port_notify,
6220
 
+                                                              control);                        
6221
 
+                }
6222
 
+
6223
 
+                control->priv->default_sink_id = new_id;
6224
 
+
6225
 
+                control->priv->default_sink_is_set = TRUE;
6226
 
+                g_signal_emit (control,
6227
 
+                               signals[DEFAULT_SINK_CHANGED],
6228
 
+                               0,
6229
 
+                               new_id);
6230
 
+                               
6231
 
+                g_signal_connect (stream,
6232
 
+                                  "notify::port",
6233
 
+                                  G_CALLBACK (on_default_sink_port_notify),
6234
 
+                                  control);
6235
 
+
6236
 
+                GvcMixerUIDevice* output;                
6237
 
+                output = gvc_mixer_control_lookup_device_from_stream (control, stream);
6238
 
+
6239
 
+                g_debug ("active_sink change \n");
6240
 
+
6241
 
+                g_signal_emit (G_OBJECT (control),
6242
 
+                               signals[ACTIVE_OUTPUT_UPDATE],
6243
 
+                               0,
6244
 
+                               gvc_mixer_ui_device_get_id (output));                       
6245
 
+        }
6246
 
+}
6247
 
+
6248
 
+static gboolean
6249
 
+_stream_has_name (gpointer        key,
6250
 
+                  GvcMixerStream *stream,
6251
 
+                  const char     *name)
6252
 
+{
6253
 
+        const char *t_name;
6254
 
+
6255
 
+        t_name = gvc_mixer_stream_get_name (stream);
6256
 
+
6257
 
+        if (t_name != NULL
6258
 
+            && name != NULL
6259
 
+            && strcmp (t_name, name) == 0) {
6260
 
+                return TRUE;
6261
 
+        }
6262
 
+
6263
 
+        return FALSE;
6264
 
+}
6265
 
+
6266
 
+static GvcMixerStream  *
6267
 
+find_stream_for_name (GvcMixerControl *control,
6268
 
+                      const char      *name)
6269
 
+{
6270
 
+        GvcMixerStream *stream;
6271
 
+
6272
 
+        stream = g_hash_table_find (control->priv->all_streams,
6273
 
+                                    (GHRFunc)_stream_has_name,
6274
 
+                                    (char *)name);
6275
 
+        return stream;
6276
 
+}
6277
 
+
6278
 
+static void
6279
 
+update_default_source_from_name (GvcMixerControl *control,
6280
 
+                                 const char      *name)
6281
 
+{
6282
 
+        gboolean changed = FALSE;
6283
 
+
6284
 
+        if ((control->priv->default_source_name == NULL
6285
 
+             && name != NULL)
6286
 
+            || (control->priv->default_source_name != NULL
6287
 
+                && name == NULL)
6288
 
+            || (name != NULL && strcmp (control->priv->default_source_name, name) != 0)) {
6289
 
+                changed = TRUE;
6290
 
+        }
6291
 
+
6292
 
+        if (changed) {
6293
 
+                GvcMixerStream *stream;
6294
 
+
6295
 
+                g_free (control->priv->default_source_name);
6296
 
+                control->priv->default_source_name = g_strdup (name);
6297
 
+
6298
 
+                stream = find_stream_for_name (control, name);
6299
 
+                _set_default_source (control, stream);
6300
 
+        }
6301
 
+}
6302
 
+
6303
 
+static void
6304
 
+update_default_sink_from_name (GvcMixerControl *control,
6305
 
+                               const char      *name)
6306
 
+{
6307
 
+        gboolean changed = FALSE;
6308
 
+
6309
 
+        if ((control->priv->default_sink_name == NULL
6310
 
+             && name != NULL)
6311
 
+            || (control->priv->default_sink_name != NULL
6312
 
+                && name == NULL)
6313
 
+            || (name != NULL && strcmp (control->priv->default_sink_name, name) != 0)) {
6314
 
+                changed = TRUE;
6315
 
+        }
6316
 
+
6317
 
+        if (changed) {
6318
 
+                GvcMixerStream *stream;
6319
 
+                g_free (control->priv->default_sink_name);
6320
 
+                control->priv->default_sink_name = g_strdup (name);
6321
 
+
6322
 
+                stream = find_stream_for_name (control, name);
6323
 
+                _set_default_sink (control, stream);
6324
 
+        }
6325
 
+}
6326
 
+
6327
 
+static void
6328
 
+update_server (GvcMixerControl      *control,
6329
 
+               const pa_server_info *info)
6330
 
+{
6331
 
+        if (info->default_source_name != NULL) {
6332
 
+                update_default_source_from_name (control, info->default_source_name);
6333
 
+        }
6334
 
+        if (info->default_sink_name != NULL) {
6335
 
+                g_debug ("\n update server");
6336
 
+                update_default_sink_from_name (control, info->default_sink_name);
6337
 
+        }
6338
 
+}
6339
 
+
6340
 
+static void
6341
 
+remove_stream (GvcMixerControl *control,
6342
 
+               GvcMixerStream  *stream)
6343
 
+{
6344
 
+        guint id;
6345
 
+
6346
 
+        g_object_ref (stream);
6347
 
+
6348
 
+        id = gvc_mixer_stream_get_id (stream);
6349
 
+                
6350
 
+        if (id == control->priv->default_sink_id) {
6351
 
+                _set_default_sink (control, NULL);
6352
 
+        } else if (id == control->priv->default_source_id) {
6353
 
+                _set_default_source (control, NULL);
6354
 
+        }
6355
 
+
6356
 
+        g_hash_table_remove (control->priv->all_streams,
6357
 
+                             GUINT_TO_POINTER (id));
6358
 
+        g_signal_emit (G_OBJECT (control),
6359
 
+                       signals[STREAM_REMOVED],
6360
 
+                       0,
6361
 
+                       gvc_mixer_stream_get_id (stream));
6362
 
+        g_object_unref (stream);
6363
 
+}
6364
 
+
6365
 
+static void
6366
 
+add_stream (GvcMixerControl *control,
6367
 
+            GvcMixerStream  *stream)
6368
 
+{
6369
 
+        g_hash_table_insert (control->priv->all_streams,
6370
 
+                             GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)),
6371
 
+                             stream);
6372
 
+        g_signal_emit (G_OBJECT (control),
6373
 
+                       signals[STREAM_ADDED],
6374
 
+                       0,
6375
 
+                       gvc_mixer_stream_get_id (stream));
6376
 
+}
6377
 
+
6378
 
+/*
6379
 
+This method will match individual stream ports against it's corresponding device
6380
 
+It does this by:
6381
 
+- iterates through our devices and finds the one where the card-id on the device is the same as the card-id on the stream
6382
 
+  && the port-name on the device is the same as the streamport-name.
6383
 
+This should always find a match and is used exclusively by @sync_devices.
6384
 
+*/ 
6385
 
+static gboolean
6386
 
+match_stream_with_devices (GvcMixerControl *control,
6387
 
+                          GvcMixerStreamPort* stream_port,
6388
 
+                           GvcMixerStream* stream)
6389
 
+{
6390
 
+       GList                   *devices;
6391
 
+       GList                   *d;
6392
 
+       GvcMixerUIDevice        *device;
6393
 
+        guint                   stream_card_id;
6394
 
+        guint                   stream_id;
6395
 
+                               
6396
 
+       stream_id      =  gvc_mixer_stream_get_id (stream);
6397
 
+        stream_card_id =  gvc_mixer_stream_get_card_index (stream);
6398
 
+
6399
 
+        devices  = g_hash_table_get_values (GVC_IS_MIXER_SOURCE (stream) ? control->priv->ui_inputs : control->priv->ui_outputs);                       
6400
 
+       gboolean in_possession  = FALSE;
6401
 
+
6402
 
+       for (d = devices; d != NULL; d = d->next) {                             
6403
 
+               device = d->data;
6404
 
+
6405
 
+               gint  device_stream_id;
6406
 
+               gchar *device_port_name;
6407
 
+               gchar *origin;
6408
 
+               gchar *description;
6409
 
+               gint  card_id;
6410
 
+               
6411
 
+               g_object_get (G_OBJECT (device),
6412
 
+                            "stream-id", &device_stream_id,
6413
 
+                            "card-id", &card_id,
6414
 
+                            "origin", &origin,
6415
 
+                            "description", &description,
6416
 
+                            "port-name", &device_port_name,
6417
 
+                             NULL);
6418
 
+
6419
 
+               g_debug ("\n Attempt to match_stream update_with_existing_outputs \n Try description : %s \n, origin : %s \n device port name : %s \n card id : %i \n AGAINST stream port: %s \n sink card id %i \n\n ",
6420
 
+                        description,
6421
 
+                        origin,
6422
 
+                        device_port_name,
6423
 
+                        card_id, 
6424
 
+                        stream_port->port,
6425
 
+                        stream_card_id);
6426
 
+
6427
 
+               if ( stream_card_id == card_id &&
6428
 
+                    g_strcmp0 (device_port_name, stream_port->port) == 0) {                                         
6429
 
+                       g_debug ("\n Match device with stream \n We have a match with description : %s  \n origin : %s \n cached already with device id %u, \n => set stream id to %i \n\n ",
6430
 
+                                description,
6431
 
+                                origin,
6432
 
+                                gvc_mixer_ui_device_get_id (device),
6433
 
+                                 stream_id);
6434
 
+                       
6435
 
+                       g_object_set (G_OBJECT (device),
6436
 
+                                     "stream-id", (gint)stream_id,
6437
 
+                                     NULL);                                                                                 
6438
 
+                       in_possession = TRUE;                                               
6439
 
+               }
6440
 
+                                                                             
6441
 
+               g_free (device_port_name);                              
6442
 
+               g_free (origin);                                                
6443
 
+               g_free (description);
6444
 
+               
6445
 
+               if (in_possession == TRUE)
6446
 
+                       break;
6447
 
+       }
6448
 
+       return in_possession;   
6449
 
+}
6450
 
+
6451
 
+/*
6452
 
+This method attempts to match a sink or source with it's relevant UI device.
6453
 
+GvcMixerStream can represent both a sink or source.
6454
 
+Using static card port introspection implies that we know beforehand what outputs and inputs are available to the user.
6455
 
+But that does not mean that all of these inputs and outputs are available to be used. 
6456
 
+For instance we might be able to see that there is a HDMI port available but if we are on the default analog stereo output profile there is no valid sink for that HDMI device. We first need to change profile and when update_sink is called only then can we match the new hdmi sink with it's corresponding device.
6457
 
+It works like this: 
6458
 
+Firstly it checks to see if the incoming stream has no ports.
6459
 
+- If a stream has no ports but has a valid card ID (bluetooth),  it will attempt to match the device with the stream using the card id.
6460
 
+- If a stream has no ports and no valid card id, it goes ahead and makes a new device (software/network devices are only detectable at the sink/source level)
6461
 
+If the stream has ports it will match each port against the stream using @match_stream_with_devices.
6462
 
+This method should always find a match !
6463
 
+*/
6464
 
+static void
6465
 
+sync_devices (GvcMixerControl *control,
6466
 
+             GvcMixerStream* stream)
6467
 
+{
6468
 
+       // Go through ports to see what outputs can be created.
6469
 
+       const GList *stream_ports = NULL;
6470
 
+       const GList *n = NULL;
6471
 
+        const GList *d;
6472
 
+        gboolean is_output = !GVC_IS_MIXER_SOURCE (stream);
6473
 
+        stream_ports = gvc_mixer_stream_get_ports (stream);
6474
 
+       gint stream_port_count = 0;
6475
 
+               
6476
 
+        if (g_list_length (stream_ports) == 0){
6477
 
+                GvcMixerUIDevice* device;
6478
 
+                // Bluetooth
6479
 
+                // => no ports && a valid card
6480
 
+                if (gvc_mixer_stream_get_card_index (stream) != PA_INVALID_INDEX) {
6481
 
+                        GList *devices;
6482
 
+
6483
 
+                        devices = g_hash_table_get_values ( is_output ? control->priv->ui_outputs : control->priv->ui_inputs);
6484
 
+
6485
 
+                        gboolean in_possession  = FALSE;
6486
 
+
6487
 
+                        for (d = devices; d != NULL; d = d->next) {                             
6488
 
+                                gint  card_id;
6489
 
+                                device = d->data;
6490
 
+                                
6491
 
+                                g_object_get (G_OBJECT (device),
6492
 
+                                             "card-id", &card_id,
6493
 
+                                              NULL);
6494
 
+                                g_debug ("\n sync devices \n device description - %s \n device card id - %i \n stream description - %s \n stream card id - %i", gvc_mixer_ui_device_get_description (device), card_id, gvc_mixer_stream_get_description (stream), gvc_mixer_stream_get_card_index (stream));
6495
 
+                                if (card_id == gvc_mixer_stream_get_card_index (stream)){
6496
 
+                                        in_possession = TRUE;
6497
 
+                                        break;
6498
 
+                                }
6499
 
+                        }
6500
 
+                        if (!in_possession){
6501
 
+                                g_warning ("\n \n Couldn't match the portless stream (with card) - %s \n is it an input ? -> %i \n \n streams card id -> %i \n", gvc_mixer_stream_get_description (stream), GVC_IS_MIXER_SOURCE (stream), gvc_mixer_stream_get_card_index (stream));
6502
 
+                                return;
6503
 
+                        }
6504
 
+
6505
 
+                        GvcMixerCard* card = NULL;
6506
 
+                        card = gvc_mixer_control_lookup_card_id (control,
6507
 
+                                                                 gvc_mixer_stream_get_card_index (stream));
6508
 
+                        g_object_set (G_OBJECT (device),
6509
 
+                                      "stream-id", (gint)gvc_mixer_stream_get_id (stream),
6510
 
+                                      "description", gvc_mixer_stream_get_description (stream),
6511
 
+                                      "origin", "", /*Leave it empty for these special cases*/
6512
 
+                                      "port-name", NULL,
6513
 
+                                      "port-available", TRUE,
6514
 
+                                      NULL);
6515
 
+                }
6516
 
+                // Network sink/source => no ports && no card.
6517
 
+                else{
6518
 
+                        GObject *object;
6519
 
+
6520
 
+                        object = g_object_new (GVC_TYPE_MIXER_UI_DEVICE,
6521
 
+                                               "stream-id", (gint)gvc_mixer_stream_get_id (stream),
6522
 
+                                               "description", gvc_mixer_stream_get_description (stream),
6523
 
+                                               "origin", "", /*Leave it empty for these special cases*/
6524
 
+                                               "port-name", NULL,
6525
 
+                                               "port-available", TRUE,
6526
 
+                                                NULL);
6527
 
+                        device = GVC_MIXER_UI_DEVICE (object);
6528
 
+
6529
 
+                        g_hash_table_insert (is_output ? control->priv->ui_outputs : control->priv->ui_inputs,
6530
 
+                                             GUINT_TO_POINTER (gvc_mixer_ui_device_get_id (device)),
6531
 
+                                             g_object_ref (device));
6532
 
+                                        
6533
 
+                }
6534
 
+                g_signal_emit (G_OBJECT (control),
6535
 
+                               signals[is_output ? OUTPUT_ADDED : INPUT_ADDED],
6536
 
+                               0,
6537
 
+                               gvc_mixer_ui_device_get_id (device));
6538
 
+
6539
 
+                return;
6540
 
+        }
6541
 
+
6542
 
+        // Go ahead and make sure to match each port against a previously created device
6543
 
+       for (n = stream_ports; n != NULL; n = n->next) {
6544
 
+
6545
 
+               GvcMixerStreamPort *stream_port;
6546
 
+               stream_port = n->data;          
6547
 
+               stream_port_count ++;
6548
 
+                                                       
6549
 
+               if ( TRUE == match_stream_with_devices (control,
6550
 
+                                                       stream_port,
6551
 
+                                                       stream))
6552
 
+                       continue;               
6553
 
+               
6554
 
+               g_warning ("\n Sync_devices : Failed to match \n stream id: %u \n description : %s \n origin : %s \n \n ",
6555
 
+                          gvc_mixer_stream_get_id (stream),
6556
 
+                          stream_port->human_port,                                      
6557
 
+                          gvc_mixer_stream_get_description (stream));          
6558
 
+       }               
6559
 
+}
6560
 
+
6561
 
+static void
6562
 
+set_icon_name_from_proplist (GvcMixerStream *stream,
6563
 
+                             pa_proplist    *l,
6564
 
+                             const char     *default_icon_name)
6565
 
+{
6566
 
+        const char *t;
6567
 
+
6568
 
+        if ((t = pa_proplist_gets (l, PA_PROP_DEVICE_ICON_NAME))) {
6569
 
+                goto finish;
6570
 
+        }
6571
 
+
6572
 
+        if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ICON_NAME))) {
6573
 
+                goto finish;
6574
 
+        }
6575
 
+
6576
 
+        if ((t = pa_proplist_gets (l, PA_PROP_WINDOW_ICON_NAME))) {
6577
 
+                goto finish;
6578
 
+        }
6579
 
+
6580
 
+        if ((t = pa_proplist_gets (l, PA_PROP_APPLICATION_ICON_NAME))) {
6581
 
+                goto finish;
6582
 
+        }
6583
 
+
6584
 
+        if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ROLE))) {
6585
 
+
6586
 
+                if (strcmp (t, "video") == 0 ||
6587
 
+                    strcmp (t, "phone") == 0) {
6588
 
+                        goto finish;
6589
 
+                }
6590
 
+
6591
 
+                if (strcmp (t, "music") == 0) {
6592
 
+                        t = "audio";
6593
 
+                        goto finish;
6594
 
+                }
6595
 
+
6596
 
+                if (strcmp (t, "game") == 0) {
6597
 
+                        t = "applications-games";
6598
 
+                        goto finish;
6599
 
+                }
6600
 
+
6601
 
+                if (strcmp (t, "event") == 0) {
6602
 
+                        t = "dialog-information";
6603
 
+                        goto finish;
6604
 
+                }
6605
 
+        }
6606
 
+
6607
 
+        t = default_icon_name;
6608
 
+
6609
 
+ finish:
6610
 
+        gvc_mixer_stream_set_icon_name (stream, t);
6611
 
+}
6612
 
+
6613
 
+/*
6614
 
+* Called when anything changes with a sink.
6615
 
+*/
6616
 
+static void
6617
 
+update_sink (GvcMixerControl    *control,
6618
 
+             const pa_sink_info *info)
6619
 
+{
6620
 
+        GvcMixerStream  *stream;
6621
 
+        gboolean        is_new;
6622
 
+        pa_volume_t     max_volume;
6623
 
+        GvcChannelMap   *map;
6624
 
+        char            map_buff[PA_CHANNEL_MAP_SNPRINT_MAX];
6625
 
+
6626
 
+        pa_channel_map_snprint (map_buff, PA_CHANNEL_MAP_SNPRINT_MAX, &info->channel_map);
6627
 
+#if 1
6628
 
+        g_debug ("Updating sink: index=%u name='%s' description='%s' map='%s'",
6629
 
+                 info->index,
6630
 
+                 info->name,
6631
 
+                 info->description,
6632
 
+                 map_buff);
6633
 
+#endif
6634
 
+
6635
 
+        map = NULL;
6636
 
+        is_new = FALSE;
6637
 
+        stream = g_hash_table_lookup (control->priv->sinks,
6638
 
+                                      GUINT_TO_POINTER (info->index));
6639
 
+
6640
 
+        if (stream == NULL) {
6641
 
+                GList *list = NULL;
6642
 
+                guint i;
6643
 
+
6644
 
+                map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map);
6645
 
+                stream = gvc_mixer_sink_new (control->priv->pa_context,
6646
 
+                                             info->index,
6647
 
+                                             map);
6648
 
+
6649
 
+                for (i = 0; i < info->n_ports; i++) {
6650
 
+                        GvcMixerStreamPort *port;
6651
 
+
6652
 
+                        port = g_new0 (GvcMixerStreamPort, 1);
6653
 
+                        port->port = g_strdup (info->ports[i]->name);
6654
 
+                        port->human_port = g_strdup (info->ports[i]->description);
6655
 
+                        port->priority = info->ports[i]->priority;
6656
 
+                        port->available = info->ports[i]->available == 0 ||
6657
 
+                                            info->ports[i]->available == 2;
6658
 
+                        
6659
 
+                        list = g_list_prepend (list, port);
6660
 
+                }
6661
 
+                gvc_mixer_stream_set_ports (stream, list);
6662
 
+
6663
 
+                g_object_unref (map);
6664
 
+                is_new = TRUE;
6665
 
+
6666
 
+        } else if (gvc_mixer_stream_is_running (stream)) {
6667
 
+                /* Ignore events if volume changes are outstanding */
6668
 
+                g_debug ("Ignoring event, volume changes are outstanding");
6669
 
+                return;
6670
 
+        }   
6671
 
+
6672
 
+        max_volume = pa_cvolume_max (&info->volume);
6673
 
+        gvc_mixer_stream_set_name (stream, info->name);
6674
 
+        gvc_mixer_stream_set_card_index (stream, info->card);
6675
 
+        gvc_mixer_stream_set_description (stream, info->description);
6676
 
+        set_icon_name_from_proplist (stream, info->proplist, "audio-card");
6677
 
+        gvc_mixer_stream_set_volume (stream, (guint)max_volume);
6678
 
+        gvc_mixer_stream_set_is_muted (stream, info->mute);
6679
 
+        gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SINK_DECIBEL_VOLUME));
6680
 
+        gvc_mixer_stream_set_base_volume (stream, (guint32) info->base_volume);
6681
 
+
6682
 
+        // Messy I know but to set the port everytime regardless of whether it has changed will cost us a 
6683
 
+        // port change notify signal which causes the frontend to resync. 
6684
 
+        // Only update the UI when something has changed.
6685
 
+        if (info->active_port != NULL){
6686
 
+                if (is_new){
6687
 
+                        gvc_mixer_stream_set_port (stream, info->active_port->name);                        
6688
 
+                }
6689
 
+                else{
6690
 
+                        GvcMixerStreamPort* active_port;
6691
 
+                        active_port = gvc_mixer_stream_get_port (stream);
6692
 
+                        if (active_port == NULL || 
6693
 
+                            g_strcmp0 (active_port->port, info->active_port->name) != 0){                
6694
 
+                                g_debug ("\n update sink - apparently a port update");
6695
 
+                                gvc_mixer_stream_set_port (stream, info->active_port->name);
6696
 
+                        }
6697
 
+                }
6698
 
+       }
6699
 
+        
6700
 
+        if (is_new) {
6701
 
+                g_debug ("\n update sink - is new \n");
6702
 
+
6703
 
+                g_hash_table_insert (control->priv->sinks,
6704
 
+                                     GUINT_TO_POINTER (info->index),
6705
 
+                                     g_object_ref (stream));
6706
 
+                add_stream (control, stream);
6707
 
+                // Always sink on a new stream to able to assign the right stream id 
6708
 
+                // to the appropriate outputs (=> multiple potential outputs per stream).
6709
 
+                sync_devices (control, stream);        
6710
 
+        }
6711
 
+        
6712
 
+        /*
6713
 
+        When we change profile on a device that is not the server default sink,
6714
 
+        it will jump back to the default sink set by the server to prevent the audio setup from being 'outputless'.
6715
 
+        All well and good but then when we get the new stream created for the new profile how do we know 
6716
 
+        that this is the intended default or selected device the user wishes to use.
6717
 
+        This is messy but it's the only reliable way that it can be done without ripping the whole thing apart.
6718
 
+        */
6719
 
+        if (control->priv->profile_swapping_device_id != GVC_MIXER_UI_DEVICE_INVALID){
6720
 
+                GvcMixerUIDevice *dev = NULL;
6721
 
+                dev = gvc_mixer_control_lookup_output_id (control, control->priv->profile_swapping_device_id);
6722
 
+                if (dev != NULL){
6723
 
+                        // now check to make sure this new stream is the same stream just matched and set on the device object
6724
 
+                        if (gvc_mixer_ui_device_get_stream_id (dev) == gvc_mixer_stream_get_id (stream)){
6725
 
+                                g_debug ("Looks like we profile swapped on a non server default sink");
6726
 
+                                gvc_mixer_control_set_default_sink (control, stream);
6727
 
+                        }  
6728
 
+                }
6729
 
+                control->priv->profile_swapping_device_id = GVC_MIXER_UI_DEVICE_INVALID;                
6730
 
+        }
6731
 
+
6732
 
+        if (control->priv->default_sink_name != NULL
6733
 
+            && info->name != NULL
6734
 
+            && strcmp (control->priv->default_sink_name, info->name) == 0) {
6735
 
+                _set_default_sink (control, stream);
6736
 
+        }
6737
 
+
6738
 
+        if (map == NULL)
6739
 
+                map = (GvcChannelMap *) gvc_mixer_stream_get_channel_map (stream);
6740
 
+        
6741
 
+        gvc_channel_map_volume_changed (map, &info->volume, FALSE);     
6742
 
+}
6743
 
+
6744
 
+static void
6745
 
+update_source (GvcMixerControl      *control,
6746
 
+               const pa_source_info *info)
6747
 
+{
6748
 
+        GvcMixerStream *stream;
6749
 
+        gboolean        is_new;
6750
 
+        gboolean        port_change;
6751
 
+        pa_volume_t     max_volume;
6752
 
+
6753
 
+#if 1
6754
 
+        g_debug ("Updating source: index=%u name='%s' description='%s'",
6755
 
+                 info->index,
6756
 
+                 info->name,
6757
 
+                 info->description);
6758
 
+#endif
6759
 
+
6760
 
+        /* completely ignore monitors, they're not real sources */
6761
 
+        if (info->monitor_of_sink != PA_INVALID_INDEX) {
6762
 
+                return;
6763
 
+        }
6764
 
+
6765
 
+        is_new = FALSE;
6766
 
+        stream = g_hash_table_lookup (control->priv->sources,
6767
 
+                                      GUINT_TO_POINTER (info->index));
6768
 
+        if (stream == NULL) {
6769
 
+                GList *list = NULL;
6770
 
+                guint i;
6771
 
+                GvcChannelMap *map;
6772
 
+
6773
 
+                map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map);
6774
 
+                stream = gvc_mixer_source_new (control->priv->pa_context,
6775
 
+                                               info->index,
6776
 
+                                               map);
6777
 
+
6778
 
+                for (i = 0; i < info->n_ports; i++) {
6779
 
+                        GvcMixerStreamPort *port;
6780
 
+
6781
 
+                        port = g_new0 (GvcMixerStreamPort, 1);
6782
 
+                        port->port = g_strdup (info->ports[i]->name);
6783
 
+                        port->human_port = g_strdup (info->ports[i]->description);
6784
 
+                        port->priority = info->ports[i]->priority;
6785
 
+                        list = g_list_prepend (list, port);
6786
 
+                }
6787
 
+                gvc_mixer_stream_set_ports (stream, list);
6788
 
+
6789
 
+                g_object_unref (map);
6790
 
+                is_new = TRUE;
6791
 
+        } else if (gvc_mixer_stream_is_running (stream)) {
6792
 
+                /* Ignore events if volume changes are outstanding */
6793
 
+                g_debug ("Ignoring event, volume changes are outstanding");
6794
 
+                return;
6795
 
+        }
6796
 
+
6797
 
+        max_volume = pa_cvolume_max (&info->volume);
6798
 
+
6799
 
+        gvc_mixer_stream_set_name (stream, info->name);
6800
 
+        gvc_mixer_stream_set_card_index (stream, info->card);
6801
 
+        gvc_mixer_stream_set_description (stream, info->description);
6802
 
+        set_icon_name_from_proplist (stream, info->proplist, "audio-input-microphone");
6803
 
+        gvc_mixer_stream_set_volume (stream, (guint)max_volume);
6804
 
+        gvc_mixer_stream_set_is_muted (stream, info->mute);
6805
 
+        gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SOURCE_DECIBEL_VOLUME));
6806
 
+        gvc_mixer_stream_set_base_volume (stream, (guint32) info->base_volume);
6807
 
+        g_debug ("\n update source \n");
6808
 
+
6809
 
+        if (info->active_port != NULL){
6810
 
+                if (is_new){
6811
 
+                        gvc_mixer_stream_set_port (stream, info->active_port->name);                        
6812
 
+                }
6813
 
+                else{
6814
 
+                        GvcMixerStreamPort* active_port;
6815
 
+                        active_port = gvc_mixer_stream_get_port (stream);
6816
 
+                        if (active_port == NULL || 
6817
 
+                            g_strcmp0 (active_port->port, info->active_port->name) != 0){                
6818
 
+                                g_debug ("\n update source - apparently a port update \n");
6819
 
+                                gvc_mixer_stream_set_port (stream, info->active_port->name);
6820
 
+                        }
6821
 
+                }
6822
 
+        }
6823
 
+        
6824
 
+        if (is_new) {
6825
 
+                g_hash_table_insert (control->priv->sources,
6826
 
+                                     GUINT_TO_POINTER (info->index),
6827
 
+                                     g_object_ref (stream));
6828
 
+                add_stream (control, stream);
6829
 
+                sync_devices (control, stream);
6830
 
+        }
6831
 
+
6832
 
+        if (control->priv->profile_swapping_device_id != GVC_MIXER_UI_DEVICE_INVALID){
6833
 
+                GvcMixerUIDevice *dev = NULL;
6834
 
6835
 
+                dev = gvc_mixer_control_lookup_input_id (control, control->priv->profile_swapping_device_id);
6836
 
+
6837
 
+                if (dev != NULL){
6838
 
+                        // now check to make sure this new stream is the same stream just matched and set on the device object
6839
 
+                        if (gvc_mixer_ui_device_get_stream_id (dev) == gvc_mixer_stream_get_id (stream)){
6840
 
+                                g_debug ("Looks like we profile swapped on a non server default sink");
6841
 
+                                gvc_mixer_control_set_default_source (control, stream);
6842
 
+                        }  
6843
 
+                }
6844
 
+                control->priv->profile_swapping_device_id = GVC_MIXER_UI_DEVICE_INVALID;                
6845
 
+        }
6846
 
+        if (control->priv->default_source_name != NULL
6847
 
+            && info->name != NULL
6848
 
+            && strcmp (control->priv->default_source_name, info->name) == 0) {
6849
 
+                _set_default_source (control, stream);
6850
 
+        }
6851
 
+}
6852
 
+
6853
 
+static void
6854
 
+set_is_event_stream_from_proplist (GvcMixerStream *stream,
6855
 
+                                   pa_proplist    *l)
6856
 
+{
6857
 
+        const char *t;
6858
 
+        gboolean is_event_stream;
6859
 
+
6860
 
+        is_event_stream = FALSE;
6861
 
+
6862
 
+        if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ROLE))) {
6863
 
+                if (g_str_equal (t, "event"))
6864
 
+                        is_event_stream = TRUE;
6865
 
+        }
6866
 
+
6867
 
+        gvc_mixer_stream_set_is_event_stream (stream, is_event_stream);
6868
 
+}
6869
 
+
6870
 
+static void
6871
 
+set_application_id_from_proplist (GvcMixerStream *stream,
6872
 
+                                  pa_proplist    *l)
6873
 
+{
6874
 
+        const char *t;
6875
 
+
6876
 
+        if ((t = pa_proplist_gets (l, PA_PROP_APPLICATION_ID))) {
6877
 
+                gvc_mixer_stream_set_application_id (stream, t);
6878
 
+        }
6879
 
+}
6880
 
+
6881
 
+static void
6882
 
+update_sink_input (GvcMixerControl          *control,
6883
 
+                   const pa_sink_input_info *info)
6884
 
+{
6885
 
+        GvcMixerStream *stream;
6886
 
+        gboolean        is_new;
6887
 
+        pa_volume_t     max_volume;
6888
 
+        const char     *name;
6889
 
+
6890
 
+#if 0
6891
 
+        g_debug ("Updating sink input: index=%u name='%s' client=%u sink=%u",
6892
 
+                 info->index,
6893
 
+                 info->name,
6894
 
+                 info->client,
6895
 
+                 info->sink);
6896
 
+#endif
6897
 
+
6898
 
+        is_new = FALSE;
6899
 
+
6900
 
+        stream = g_hash_table_lookup (control->priv->sink_inputs,
6901
 
+                                      GUINT_TO_POINTER (info->index));
6902
 
+        if (stream == NULL) {
6903
 
+                GvcChannelMap *map;
6904
 
+                map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map);
6905
 
+                stream = gvc_mixer_sink_input_new (control->priv->pa_context,
6906
 
+                                                   info->index,
6907
 
+                                                   map);
6908
 
+                g_object_unref (map);
6909
 
+                is_new = TRUE;
6910
 
+        } else if (gvc_mixer_stream_is_running (stream)) {
6911
 
+                /* Ignore events if volume changes are outstanding */
6912
 
+                g_debug ("Ignoring event, volume changes are outstanding");
6913
 
+                return;
6914
 
+        }
6915
 
+
6916
 
+        max_volume = pa_cvolume_max (&info->volume);
6917
 
+
6918
 
+        name = (const char *)g_hash_table_lookup (control->priv->clients,
6919
 
+                                                  GUINT_TO_POINTER (info->client));
6920
 
+        gvc_mixer_stream_set_name (stream, name);
6921
 
+        gvc_mixer_stream_set_description (stream, info->name);
6922
 
+
6923
 
+        set_application_id_from_proplist (stream, info->proplist);
6924
 
+        set_is_event_stream_from_proplist (stream, info->proplist);
6925
 
+        set_icon_name_from_proplist (stream, info->proplist, "applications-multimedia");
6926
 
+        gvc_mixer_stream_set_volume (stream, (guint)max_volume);
6927
 
+        gvc_mixer_stream_set_is_muted (stream, info->mute);
6928
 
+        gvc_mixer_stream_set_is_virtual (stream, info->client == PA_INVALID_INDEX);
6929
 
+
6930
 
+        if (is_new) {
6931
 
+                g_hash_table_insert (control->priv->sink_inputs,
6932
 
+                                     GUINT_TO_POINTER (info->index),
6933
 
+                                     g_object_ref (stream));
6934
 
+                add_stream (control, stream);
6935
 
+        }
6936
 
+}
6937
 
+
6938
 
+static void
6939
 
+update_source_output (GvcMixerControl             *control,
6940
 
+                      const pa_source_output_info *info)
6941
 
+{
6942
 
+        GvcMixerStream *stream;
6943
 
+        gboolean        is_new;
6944
 
+        const char     *name;
6945
 
+
6946
 
+#if 1
6947
 
+        g_debug ("Updating source output: index=%u name='%s' client=%u source=%u",
6948
 
+                 info->index,
6949
 
+                 info->name,
6950
 
+                 info->client,
6951
 
+                 info->source);
6952
 
+#endif
6953
 
+
6954
 
+        is_new = FALSE;
6955
 
+        stream = g_hash_table_lookup (control->priv->source_outputs,
6956
 
+                                      GUINT_TO_POINTER (info->index));
6957
 
+        if (stream == NULL) {
6958
 
+                GvcChannelMap *map;
6959
 
+                map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map);
6960
 
+                stream = gvc_mixer_source_output_new (control->priv->pa_context,
6961
 
+                                                      info->index,
6962
 
+                                                      map);
6963
 
+                g_object_unref (map);
6964
 
+                is_new = TRUE;
6965
 
+        }
6966
 
+
6967
 
+        name = (const char *)g_hash_table_lookup (control->priv->clients,
6968
 
+                                                  GUINT_TO_POINTER (info->client));
6969
 
+
6970
 
+        gvc_mixer_stream_set_name (stream, name);
6971
 
+        gvc_mixer_stream_set_description (stream, info->name);
6972
 
+        set_application_id_from_proplist (stream, info->proplist);
6973
 
+        set_is_event_stream_from_proplist (stream, info->proplist);
6974
 
+        set_icon_name_from_proplist (stream, info->proplist, "audio-input-microphone");
6975
 
+
6976
 
+        if (is_new) {
6977
 
+                g_hash_table_insert (control->priv->source_outputs,
6978
 
+                                     GUINT_TO_POINTER (info->index),
6979
 
+                                     g_object_ref (stream));
6980
 
+                add_stream (control, stream);
6981
 
+        }
6982
 
+}
6983
 
+
6984
 
+static void
6985
 
+update_client (GvcMixerControl      *control,
6986
 
+               const pa_client_info *info)
6987
 
+{
6988
 
+#if 1
6989
 
+        g_debug ("Updating client: index=%u name='%s'",
6990
 
+                 info->index,
6991
 
+                 info->name);
6992
 
+#endif
6993
 
+        g_hash_table_insert (control->priv->clients,
6994
 
+                             GUINT_TO_POINTER (info->index),
6995
 
+                             g_strdup (info->name));
6996
 
+}
6997
 
+
6998
 
+static char *
6999
 
+card_num_streams_to_status (guint sinks,
7000
 
+                            guint sources)
7001
 
+{
7002
 
+        char *sinks_str;
7003
 
+        char *sources_str;
7004
 
+        char *ret;
7005
 
+
7006
 
+        if (sinks == 0 && sources == 0) {
7007
 
+                /* translators:
7008
 
+                 * The device has been disabled */
7009
 
+                return g_strdup (_("Disabled"));
7010
 
+        }
7011
 
+        if (sinks == 0) {
7012
 
+                sinks_str = NULL;
7013
 
+        } else {
7014
 
+                /* translators:
7015
 
+                 * The number of sound outputs on a particular device */
7016
 
+                sinks_str = g_strdup_printf (ngettext ("%u Output",
7017
 
+                                                       "%u Outputs",
7018
 
+                                                       sinks),
7019
 
+                                             sinks);
7020
 
+        }
7021
 
+        if (sources == 0) {
7022
 
+                sources_str = NULL;
7023
 
+        } else {
7024
 
+                /* translators:
7025
 
+                 * The number of sound inputs on a particular device */
7026
 
+                sources_str = g_strdup_printf (ngettext ("%u Input",
7027
 
+                                                         "%u Inputs",
7028
 
+                                                         sources),
7029
 
+                                               sources);
7030
 
+        }
7031
 
+        if (sources_str == NULL)
7032
 
+                return sinks_str;
7033
 
+        if (sinks_str == NULL)
7034
 
+                return sources_str;
7035
 
+        ret = g_strdup_printf ("%s / %s", sinks_str, sources_str);
7036
 
+        g_free (sinks_str);
7037
 
+        g_free (sources_str);
7038
 
+        return ret;
7039
 
+}
7040
 
+/**
7041
 
+* A utility method to gather which card profiles are relevant to the port .
7042
 
+*/
7043
 
+static GList* 
7044
 
+determine_profiles_for_port (pa_card_port_info *port,
7045
 
+                            GList* card_profiles)
7046
 
+{
7047
 
+       gint i;
7048
 
+       GList *supported_profiles = NULL;
7049
 
+       GList *p;
7050
 
+       for (i = 0; i < port->n_profiles; i++) {
7051
 
+               for ( p = card_profiles; p != NULL; p = p->next) {
7052
 
+                       GvcMixerCardProfile *prof;
7053
 
+                       prof = p->data;
7054
 
+                       if (g_strcmp0 (port->profiles[i]->name, prof->profile) == 0) {
7055
 
+                               supported_profiles = g_list_append (supported_profiles, prof);  
7056
 
+                       }
7057
 
+               }
7058
 
+       }
7059
 
+       g_debug ("\n %i profiles supported on port %s \n",
7060
 
+                g_list_length (supported_profiles),
7061
 
+                port->description);
7062
 
+       return g_list_sort (supported_profiles, (GCompareFunc) sort_profiles);
7063
 
+}
7064
 
+
7065
 
+static gboolean
7066
 
+is_card_port_an_output (GvcMixerCardPort* port)
7067
 
+{
7068
 
+       return port->direction == PA_DIRECTION_OUTPUT ? TRUE : FALSE;
7069
 
+} 
7070
 
+
7071
 
+/*
7072
 
+* This method will create a ui device for the given port. 
7073
 
+*/
7074
 
+static void
7075
 
+create_ui_device_from_port (GvcMixerControl* control,
7076
 
+                           GvcMixerCardPort* port,
7077
 
+                           GvcMixerCard* card)
7078
 
+{
7079
 
+       UiDeviceDirection direction;
7080
 
+       
7081
 
+       direction = (is_card_port_an_output(port) == TRUE) ? UiDeviceOutput : UiDeviceInput;
7082
 
+       GObject *object;
7083
 
+       gboolean available = port->available == 0 || port->available == 2;
7084
 
+
7085
 
+       object = g_object_new (GVC_TYPE_MIXER_UI_DEVICE,
7086
 
+                              "type", (uint)direction,
7087
 
+                              "card-id", (gint)gvc_mixer_card_get_index (card),
7088
 
+                              "port-name", port->port,
7089
 
+                              "description", port->human_port,
7090
 
+                              "origin", gvc_mixer_card_get_name (card),
7091
 
+                              "port-available", available,
7092
 
+                              NULL);
7093
 
+                              
7094
 
+       GvcMixerUIDevice* uidevice = GVC_MIXER_UI_DEVICE (object);
7095
 
+       gvc_mixer_ui_device_set_profiles (uidevice, port->profiles);
7096
 
+
7097
 
+        g_hash_table_insert (is_card_port_an_output (port) ? control->priv->ui_outputs : control->priv->ui_inputs,
7098
 
+                             GUINT_TO_POINTER (gvc_mixer_ui_device_get_id (uidevice)),
7099
 
+                             g_object_ref (uidevice));
7100
 
+
7101
 
+
7102
 
+        if (available) {
7103
 
+                g_signal_emit (G_OBJECT (control),
7104
 
+                               signals[is_card_port_an_output (port) ? OUTPUT_ADDED : INPUT_ADDED],
7105
 
+                               0,
7106
 
+                               gvc_mixer_ui_device_get_id (uidevice));
7107
 
+        }       
7108
 
+
7109
 
+       g_debug ("\n create_ui_device_from_port, direction %u \n description %s \n origin %s \n port available %i \n \n", 
7110
 
+                direction,
7111
 
+                port->human_port,
7112
 
+                gvc_mixer_card_get_name (card),
7113
 
+                available);
7114
 
+}
7115
 
+
7116
 
+/*
7117
 
+This method will match up GvcMixerCardPorts with existing devices. 
7118
 
+A match is achieved if the device's card-id and the port's card-id are the same
7119
 
+&& the device's port-name and the card-port's port member are the same. 
7120
 
+A signal is then sent adding or removing that device from the UI depending on the availability of the port.
7121
 
+*/
7122
 
+static void
7123
 
+match_card_port_with_existing_device (GvcMixerControl *control,
7124
 
+                                     GvcMixerCardPort* card_port,
7125
 
+                                     GvcMixerCard* card,
7126
 
+                                     gboolean available)
7127
 
+{
7128
 
+        GList                  *d;
7129
 
+        GList                   *devices;
7130
 
+        GvcMixerUIDevice       *device;                        
7131
 
+        gboolean in_possession         = FALSE;
7132
 
+        gboolean is_output      = is_card_port_an_output (card_port);
7133
 
+
7134
 
+        devices  = g_hash_table_get_values (is_output ? control->priv->ui_outputs : control->priv->ui_inputs);
7135
 
+
7136
 
+       for (d = devices; d != NULL; d = d->next) {                                     
7137
 
+                device = d->data;
7138
 
+                gint     card_id;
7139
 
+                gchar    *device_port_name;
7140
 
+               
7141
 
+                g_object_get (G_OBJECT (device),
7142
 
+                             "card-id", &card_id,
7143
 
+                             "port-name", &device_port_name,
7144
 
+                              NULL);
7145
 
+
7146
 
+                if (g_strcmp0 (card_port->port, device_port_name) == 0 && 
7147
 
+                        card_id == gvc_mixer_card_get_index (card)) { 
7148
 
+                        g_debug ("\n Found the relevant device %s \n update it's port availability flag to %i \n is_output %i",
7149
 
+                                device_port_name,
7150
 
+                                 available,
7151
 
+                                 is_output);
7152
 
+                        g_object_set ( G_OBJECT (device),
7153
 
+                                       "port-available", available, NULL);
7154
 
+                        g_signal_emit (G_OBJECT (control),
7155
 
+                                       is_output ? signals[available ? OUTPUT_ADDED : OUTPUT_REMOVED] : signals[available ? INPUT_ADDED : INPUT_REMOVED],
7156
 
+                                       0,
7157
 
+                                       gvc_mixer_ui_device_get_id (device));   
7158
 
+              }
7159
 
+              g_free (device_port_name);
7160
 
+       }
7161
 
+}
7162
 
+/*
7163
 
+At this point we can determine all devices available to us (besides network 'ports')
7164
 
+This is done by the following:
7165
 
+
7166
 
+ - gvc_mixer_card and gvc_mixer_card_ports are created and relevant setters are called.
7167
 
+ - First it checks to see if it's a portless card. Bluetooth devices are portless AFAIHS.
7168
 
+        If so it creates two devices, an input and an output.
7169
 
+ - If it's a 'normal' card with ports it will create a new ui-device or 
7170
 
+   synchronise port availability with the existing device cached for that port on this card.
7171
 
+*/                 
7172
 
+static void
7173
 
+update_card (GvcMixerControl      *control,
7174
 
+             const pa_card_info   *info)
7175
 
+{
7176
 
+        GvcMixerCard *card;
7177
 
+        gboolean      is_new = FALSE;
7178
 
+#if 1
7179
 
+        guint i,t;
7180
 
+        const char *key;
7181
 
+        void *state;
7182
 
+
7183
 
+        for (i = 0; i < info->n_profiles; i++) {
7184
 
+                struct pa_card_profile_info pi = info->profiles[i];
7185
 
+                gboolean is_default;
7186
 
+
7187
 
+                is_default = (g_strcmp0 (pi.name, info->active_profile->name) == 0);
7188
 
+                g_debug ("\tProfile '%s': %d sources %d sinks%s",
7189
 
+                         pi.name, pi.n_sources, pi.n_sinks,
7190
 
+                         is_default ? " (Current)" : "");
7191
 
+        }
7192
 
+        state = NULL;
7193
 
+        key = pa_proplist_iterate (info->proplist, &state);
7194
 
+        while (key != NULL) {
7195
 
+                g_debug ("\tProperty: '%s' = '%s'",
7196
 
+                        key, pa_proplist_gets (info->proplist, key));
7197
 
+                key = pa_proplist_iterate (info->proplist, &state);
7198
 
+        }
7199
 
+#endif
7200
 
+        card = g_hash_table_lookup (control->priv->cards,
7201
 
+                                    GUINT_TO_POINTER (info->index));
7202
 
+        if (card == NULL) {
7203
 
+                GList *profile_list = NULL;
7204
 
+
7205
 
+                for (i = 0; i < info->n_profiles; i++) {
7206
 
+                        struct pa_card_profile_info pi = info->profiles[i];
7207
 
+                        GvcMixerCardProfile *profile;
7208
 
+
7209
 
+                        profile = g_new0 (GvcMixerCardProfile, 1);
7210
 
+                        profile->profile = g_strdup (pi.name);
7211
 
+                        profile->human_profile = g_strdup (pi.description);
7212
 
+                        profile->status = card_num_streams_to_status (pi.n_sinks, pi.n_sources);
7213
 
+                        profile->n_sinks = pi.n_sinks;
7214
 
+                        profile->n_sources = pi.n_sources;
7215
 
+                        profile->priority = pi.priority;
7216
 
+                        profile_list = g_list_prepend (profile_list, profile);
7217
 
+                }
7218
 
+                card = gvc_mixer_card_new (control->priv->pa_context,
7219
 
+                                           info->index);
7220
 
+                gvc_mixer_card_set_profiles (card, profile_list);
7221
 
+
7222
 
+               GList *port_list = NULL;
7223
 
+                for (i = 0; i < info->n_ports; i++) {
7224
 
+                        GvcMixerCardPort *port;
7225
 
+                        port = g_new0 (GvcMixerCardPort, 1);
7226
 
+                        port->port = g_strdup (info->ports[i]->name);
7227
 
+                        port->human_port = g_strdup (info->ports[i]->description);
7228
 
+                        port->priority = info->ports[i]->priority;
7229
 
+                        port->available = info->ports[i]->available;
7230
 
+                        port->direction = info->ports[i]->direction;
7231
 
+                       port->profiles = determine_profiles_for_port (info->ports[i], profile_list);
7232
 
+                        port_list = g_list_prepend (port_list, port);                      
7233
 
+                }                
7234
 
+                gvc_mixer_card_set_ports (card, port_list);                
7235
 
+                is_new = TRUE;
7236
 
+        }
7237
 
+
7238
 
+        gvc_mixer_card_set_name (card, pa_proplist_gets (info->proplist, "device.description"));
7239
 
+        gvc_mixer_card_set_icon_name (card, pa_proplist_gets (info->proplist, "device.icon_name"));
7240
 
+        gvc_mixer_card_set_profile (card, info->active_profile->name);
7241
 
+
7242
 
+        if (is_new) {
7243
 
+                g_hash_table_insert (control->priv->cards,
7244
 
+                                     GUINT_TO_POINTER (info->index),
7245
 
+                                     g_object_ref (card));
7246
 
+        }
7247
 
+        
7248
 
+        const GList *card_ports = NULL;
7249
 
+        const GList *m = NULL;
7250
 
+        
7251
 
+        card_ports = gvc_mixer_card_get_ports (card);
7252
 
+        
7253
 
+        guint port_count;
7254
 
+        port_count = g_list_length (card_ports);
7255
 
+
7256
 
+        if (port_count == 0 && is_new){
7257
 
+                // TODO : move to its own method.
7258
 
+                g_debug ("\n Portless card just registered - %s \n", gvc_mixer_card_get_name (card));
7259
 
+                // For now just create two devices and presume this device is multi directional
7260
 
+                // Ensure to remove both on card removal (available to false by default)
7261
 
+                const GList *profiles = NULL;
7262
 
+                profiles = gvc_mixer_card_get_profiles (card);
7263
 
+
7264
 
+                g_debug ("\n Portless card just registered - %i \n", gvc_mixer_card_get_index (card));
7265
 
+
7266
 
+                GObject *object;
7267
 
+                object = g_object_new (GVC_TYPE_MIXER_UI_DEVICE,
7268
 
+                                       "type", 0,
7269
 
+                                       "description", gvc_mixer_card_get_name (card),
7270
 
+                                       "origin", "", /*Leave it empty for these special cases*/
7271
 
+                                       "port-name", NULL,
7272
 
+                                       "port-available", FALSE,
7273
 
+                                       "card-id", gvc_mixer_card_get_index (card),
7274
 
+                                       NULL);
7275
 
+                GvcMixerUIDevice* in = GVC_MIXER_UI_DEVICE (object);
7276
 
+                gvc_mixer_ui_device_set_profiles (in, profiles);                     
7277
 
+
7278
 
+                g_hash_table_insert (control->priv->ui_inputs,
7279
 
+                                     GUINT_TO_POINTER (gvc_mixer_ui_device_get_id (in)),
7280
 
+                                     g_object_ref (in));
7281
 
+                object = g_object_new (GVC_TYPE_MIXER_UI_DEVICE,
7282
 
+                                       "type", 1,
7283
 
+                                       "description", gvc_mixer_card_get_name (card),
7284
 
+                                       "origin", "", /*Leave it empty for these special cases*/
7285
 
+                                       "port-name", NULL,
7286
 
+                                       "port-available", FALSE,
7287
 
+                                       "card-id", gvc_mixer_card_get_index (card),
7288
 
+                                       NULL);
7289
 
+                GvcMixerUIDevice* out = GVC_MIXER_UI_DEVICE (object);
7290
 
+                gvc_mixer_ui_device_set_profiles (out, profiles);                     
7291
 
+
7292
 
+                g_hash_table_insert (control->priv->ui_outputs,
7293
 
+                                     GUINT_TO_POINTER (gvc_mixer_ui_device_get_id (out)),
7294
 
+                                     g_object_ref (out));
7295
 
+        }
7296
 
+
7297
 
+        for (m = card_ports; m != NULL; m = m->next) {
7298
 
+                GvcMixerCardPort *card_port;
7299
 
+                card_port = m->data;
7300
 
+                if (is_new) {
7301
 
+                        create_ui_device_from_port (control, card_port, card);
7302
 
+                }
7303
 
+                else{
7304
 
+                        for (i = 0; i < info->n_ports; i++) {
7305
 
+                                if (g_strcmp0 (card_port->port, info->ports[i]->name) == 0){
7306
 
+                                        if (card_port->available != info->ports[i]->available) {
7307
 
+                                                card_port->available = info->ports[i]->available;
7308
 
+                                                g_debug ("\n !!! sync port availability on card %i \n card port name %s \n new available value %i \n",
7309
 
+                                                          gvc_mixer_card_get_index (card),
7310
 
+                                                          card_port->port,
7311
 
+                                                          card_port->available);
7312
 
+                                                match_card_port_with_existing_device (control,
7313
 
+                                                                                      card_port,
7314
 
+                                                                                      card,
7315
 
+                                                                                      card_port->available == 0 ||
7316
 
+                                                                                      card_port->available == 2);      
7317
 
+                                        }
7318
 
+                                }                              
7319
 
+                        }
7320
 
+                }
7321
 
+        }
7322
 
+        g_signal_emit (G_OBJECT (control),
7323
 
+                       signals[CARD_ADDED],
7324
 
+                       0,
7325
 
+                       info->index);
7326
 
+}
7327
 
+
7328
 
+
7329
 
+
7330
 
+static void
7331
 
+_pa_context_get_sink_info_cb (pa_context         *context,
7332
 
+                              const pa_sink_info *i,
7333
 
+                              int                 eol,
7334
 
+                              void               *userdata)
7335
 
+{
7336
 
+        GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7337
 
+
7338
 
+        if (eol < 0) {
7339
 
+                if (pa_context_errno (context) == PA_ERR_NOENTITY) {
7340
 
+                        return;
7341
 
+                }
7342
 
+
7343
 
+                g_warning ("Sink callback failure");
7344
 
+                return;
7345
 
+        }
7346
 
+
7347
 
+        if (eol > 0) {
7348
 
+                dec_outstanding (control);
7349
 
+                return;
7350
 
+        }
7351
 
+
7352
 
+        update_sink (control, i);
7353
 
+}
7354
 
+
7355
 
+static void
7356
 
+_pa_context_get_source_info_cb (pa_context           *context,
7357
 
+                                const pa_source_info *i,
7358
 
+                                int                   eol,
7359
 
+                                void                 *userdata)
7360
 
+{
7361
 
+        GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7362
 
+
7363
 
+        if (eol < 0) {
7364
 
+                if (pa_context_errno (context) == PA_ERR_NOENTITY) {
7365
 
+                        return;
7366
 
+                }
7367
 
+
7368
 
+                g_warning ("Source callback failure");
7369
 
+                return;
7370
 
+        }
7371
 
+
7372
 
+        if (eol > 0) {
7373
 
+                dec_outstanding (control);
7374
 
+                return;
7375
 
+        }
7376
 
+
7377
 
+        update_source (control, i);
7378
 
+}
7379
 
+
7380
 
+static void
7381
 
+_pa_context_get_sink_input_info_cb (pa_context               *context,
7382
 
+                                    const pa_sink_input_info *i,
7383
 
+                                    int                       eol,
7384
 
+                                    void                     *userdata)
7385
 
+{
7386
 
+        GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7387
 
+
7388
 
+        if (eol < 0) {
7389
 
+                if (pa_context_errno (context) == PA_ERR_NOENTITY) {
7390
 
+                        return;
7391
 
+                }
7392
 
+
7393
 
+                g_warning ("Sink input callback failure");
7394
 
+                return;
7395
 
+        }
7396
 
+
7397
 
+        if (eol > 0) {
7398
 
+                dec_outstanding (control);
7399
 
+                return;
7400
 
+        }
7401
 
+
7402
 
+        update_sink_input (control, i);
7403
 
+}
7404
 
+
7405
 
+static void
7406
 
+_pa_context_get_source_output_info_cb (pa_context                  *context,
7407
 
+                                       const pa_source_output_info *i,
7408
 
+                                       int                          eol,
7409
 
+                                       void                        *userdata)
7410
 
+{
7411
 
+        GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7412
 
+
7413
 
+        if (eol < 0) {
7414
 
+                if (pa_context_errno (context) == PA_ERR_NOENTITY) {
7415
 
+                        return;
7416
 
+                }
7417
 
+
7418
 
+                g_warning ("Source output callback failure");
7419
 
+                return;
7420
 
+        }
7421
 
+
7422
 
+        if (eol > 0)  {
7423
 
+                dec_outstanding (control);
7424
 
+                return;
7425
 
+        }
7426
 
+
7427
 
+        update_source_output (control, i);
7428
 
+}
7429
 
+
7430
 
+static void
7431
 
+_pa_context_get_client_info_cb (pa_context           *context,
7432
 
+                                const pa_client_info *i,
7433
 
+                                int                   eol,
7434
 
+                                void                 *userdata)
7435
 
+{
7436
 
+        GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7437
 
+
7438
 
+        if (eol < 0) {
7439
 
+                if (pa_context_errno (context) == PA_ERR_NOENTITY) {
7440
 
+                        return;
7441
 
+                }
7442
 
+
7443
 
+                g_warning ("Client callback failure");
7444
 
+                return;
7445
 
+        }
7446
 
+
7447
 
+        if (eol > 0) {
7448
 
+                dec_outstanding (control);
7449
 
+                return;
7450
 
+        }
7451
 
+
7452
 
+        update_client (control, i);
7453
 
+}
7454
 
+
7455
 
+static void
7456
 
+_pa_context_get_card_info_by_index_cb (pa_context *context,
7457
 
+                                       const pa_card_info *i,
7458
 
+                                       int eol,
7459
 
+                                       void *userdata)
7460
 
+{
7461
 
+        GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7462
 
+
7463
 
+        if (eol < 0) {
7464
 
+                if (pa_context_errno (context) == PA_ERR_NOENTITY)
7465
 
+                        return;
7466
 
+
7467
 
+                g_warning ("Card callback failure");
7468
 
+                return;
7469
 
+        }
7470
 
+
7471
 
+        if (eol > 0) {
7472
 
+                dec_outstanding (control);
7473
 
+                return;
7474
 
+        }
7475
 
+
7476
 
+        update_card (control, i);
7477
 
+}
7478
 
+
7479
 
+static void
7480
 
+_pa_context_get_server_info_cb (pa_context           *context,
7481
 
+                                const pa_server_info *i,
7482
 
+                                void                 *userdata)
7483
 
+{
7484
 
+        GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7485
 
+
7486
 
+        if (i == NULL) {
7487
 
+                g_warning ("Server info callback failure");
7488
 
+                return;
7489
 
+        }
7490
 
+        g_debug ("\n get server info \n");
7491
 
+        update_server (control, i);
7492
 
+        dec_outstanding (control);
7493
 
+}
7494
 
+
7495
 
+static void
7496
 
+remove_event_role_stream (GvcMixerControl *control)
7497
 
+{
7498
 
+        g_debug ("Removing event role");
7499
 
+}
7500
 
+
7501
 
+static void
7502
 
+update_event_role_stream (GvcMixerControl                  *control,
7503
 
+                          const pa_ext_stream_restore_info *info)
7504
 
+{
7505
 
+        GvcMixerStream *stream;
7506
 
+        gboolean        is_new;
7507
 
+        pa_volume_t     max_volume;
7508
 
+
7509
 
+        if (strcmp (info->name, "sink-input-by-media-role:event") != 0) {
7510
 
+                return;
7511
 
+        }
7512
 
+
7513
 
+#if 0
7514
 
+        g_debug ("Updating event role: name='%s' device='%s'",
7515
 
+                 info->name,
7516
 
+                 info->device);
7517
 
+#endif
7518
 
+
7519
 
+        is_new = FALSE;
7520
 
+
7521
 
+        if (!control->priv->event_sink_input_is_set) {
7522
 
+                pa_channel_map pa_map;
7523
 
+                GvcChannelMap *map;
7524
 
+
7525
 
+                pa_map.channels = 1;
7526
 
+                pa_map.map[0] = PA_CHANNEL_POSITION_MONO;
7527
 
+                map = gvc_channel_map_new_from_pa_channel_map (&pa_map);
7528
 
+
7529
 
+                stream = gvc_mixer_event_role_new (control->priv->pa_context,
7530
 
+                                                   info->device,
7531
 
+                                                   map);
7532
 
+                control->priv->event_sink_input_id = gvc_mixer_stream_get_id (stream);
7533
 
+                control->priv->event_sink_input_is_set = TRUE;
7534
 
+
7535
 
+                is_new = TRUE;
7536
 
+        } else {
7537
 
+                stream = g_hash_table_lookup (control->priv->all_streams,
7538
 
+                                              GUINT_TO_POINTER (control->priv->event_sink_input_id));
7539
 
+        }
7540
 
+
7541
 
+        max_volume = pa_cvolume_max (&info->volume);
7542
 
+
7543
 
+        gvc_mixer_stream_set_name (stream, _("System Sounds"));
7544
 
+        gvc_mixer_stream_set_icon_name (stream, "multimedia-volume-control");
7545
 
+        gvc_mixer_stream_set_volume (stream, (guint)max_volume);
7546
 
+        gvc_mixer_stream_set_is_muted (stream, info->mute);
7547
 
+
7548
 
+        if (is_new) {
7549
 
+                add_stream (control, stream);
7550
 
+        }
7551
 
+}
7552
 
+
7553
 
+static void
7554
 
+_pa_ext_stream_restore_read_cb (pa_context                       *context,
7555
 
+                                const pa_ext_stream_restore_info *i,
7556
 
+                                int                               eol,
7557
 
+                                void                             *userdata)
7558
 
+{
7559
 
+        GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7560
 
+
7561
 
+        if (eol < 0) {
7562
 
+                g_debug ("Failed to initialized stream_restore extension: %s",
7563
 
+                         pa_strerror (pa_context_errno (context)));
7564
 
+                remove_event_role_stream (control);
7565
 
+                return;
7566
 
+        }
7567
 
+
7568
 
+        if (eol > 0) {
7569
 
+                dec_outstanding (control);
7570
 
+                /* If we don't have an event stream to restore, then
7571
 
+                 * set one up with a default 100% volume */
7572
 
+                if (!control->priv->event_sink_input_is_set) {
7573
 
+                        pa_ext_stream_restore_info info;
7574
 
+
7575
 
+                        memset (&info, 0, sizeof(info));
7576
 
+                        info.name = "sink-input-by-media-role:event";
7577
 
+                        info.volume.channels = 1;
7578
 
+                        info.volume.values[0] = PA_VOLUME_NORM;
7579
 
+                        update_event_role_stream (control, &info);
7580
 
+                }
7581
 
+                return;
7582
 
+        }
7583
 
+
7584
 
+        update_event_role_stream (control, i);
7585
 
+}
7586
 
+
7587
 
+static void
7588
 
+_pa_ext_stream_restore_subscribe_cb (pa_context *context,
7589
 
+                                     void       *userdata)
7590
 
+{
7591
 
+        GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7592
 
+        pa_operation    *o;
7593
 
+
7594
 
+        o = pa_ext_stream_restore_read (context,
7595
 
+                                        _pa_ext_stream_restore_read_cb,
7596
 
+                                        control);
7597
 
+        if (o == NULL) {
7598
 
+                g_warning ("pa_ext_stream_restore_read() failed");
7599
 
+                return;
7600
 
+        }
7601
 
+
7602
 
+        pa_operation_unref (o);
7603
 
+}
7604
 
+
7605
 
+static void
7606
 
+req_update_server_info (GvcMixerControl *control,
7607
 
+                        int              index)
7608
 
+{
7609
 
+        pa_operation *o;
7610
 
+
7611
 
+        o = pa_context_get_server_info (control->priv->pa_context,
7612
 
+                                        _pa_context_get_server_info_cb,
7613
 
+                                        control);
7614
 
+        if (o == NULL) {
7615
 
+                g_warning ("pa_context_get_server_info() failed");
7616
 
+                return;
7617
 
+        }
7618
 
+        pa_operation_unref (o);
7619
 
+}
7620
 
+
7621
 
+static void
7622
 
+req_update_client_info (GvcMixerControl *control,
7623
 
+                        int              index)
7624
 
+{
7625
 
+        pa_operation *o;
7626
 
+
7627
 
+        if (index < 0) {
7628
 
+                o = pa_context_get_client_info_list (control->priv->pa_context,
7629
 
+                                                     _pa_context_get_client_info_cb,
7630
 
+                                                     control);
7631
 
+        } else {
7632
 
+                o = pa_context_get_client_info (control->priv->pa_context,
7633
 
+                                                index,
7634
 
+                                                _pa_context_get_client_info_cb,
7635
 
+                                                control);
7636
 
+        }
7637
 
+
7638
 
+        if (o == NULL) {
7639
 
+                g_warning ("pa_context_client_info_list() failed");
7640
 
+                return;
7641
 
+        }
7642
 
+        pa_operation_unref (o);
7643
 
+}
7644
 
+
7645
 
+static void
7646
 
+req_update_card (GvcMixerControl *control,
7647
 
+                 int              index)
7648
 
+{
7649
 
+        pa_operation *o;
7650
 
+
7651
 
+        if (index < 0) {
7652
 
+                o = pa_context_get_card_info_list (control->priv->pa_context,
7653
 
+                                                   _pa_context_get_card_info_by_index_cb,
7654
 
+                                                   control);
7655
 
+        } else {
7656
 
+                o = pa_context_get_card_info_by_index (control->priv->pa_context,
7657
 
+                                                       index,
7658
 
+                                                       _pa_context_get_card_info_by_index_cb,
7659
 
+                                                       control);
7660
 
+        }
7661
 
+
7662
 
+        if (o == NULL) {
7663
 
+                g_warning ("pa_context_get_card_info_by_index() failed");
7664
 
+                return;
7665
 
+        }
7666
 
+        pa_operation_unref (o);
7667
 
+}
7668
 
+
7669
 
+static void
7670
 
+req_update_sink_info (GvcMixerControl *control,
7671
 
+                      int              index)
7672
 
+{
7673
 
+        pa_operation *o;
7674
 
+
7675
 
+        if (index < 0) {
7676
 
+                o = pa_context_get_sink_info_list (control->priv->pa_context,
7677
 
+                                                   _pa_context_get_sink_info_cb,
7678
 
+                                                   control);
7679
 
+        } else {
7680
 
+                o = pa_context_get_sink_info_by_index (control->priv->pa_context,
7681
 
+                                                       index,
7682
 
+                                                       _pa_context_get_sink_info_cb,
7683
 
+                                                       control);
7684
 
+        }
7685
 
+
7686
 
+        if (o == NULL) {
7687
 
+                g_warning ("pa_context_get_sink_info_list() failed");
7688
 
+                return;
7689
 
+        }
7690
 
+        pa_operation_unref (o);
7691
 
+}
7692
 
+
7693
 
+static void
7694
 
+req_update_source_info (GvcMixerControl *control,
7695
 
+                        int              index)
7696
 
+{
7697
 
+        pa_operation *o;
7698
 
+
7699
 
+        if (index < 0) {
7700
 
+                o = pa_context_get_source_info_list (control->priv->pa_context,
7701
 
+                                                     _pa_context_get_source_info_cb,
7702
 
+                                                     control);
7703
 
+        } else {
7704
 
+                o = pa_context_get_source_info_by_index(control->priv->pa_context,
7705
 
+                                                        index,
7706
 
+                                                        _pa_context_get_source_info_cb,
7707
 
+                                                        control);
7708
 
+        }
7709
 
+
7710
 
+        if (o == NULL) {
7711
 
+                g_warning ("pa_context_get_source_info_list() failed");
7712
 
+                return;
7713
 
+        }
7714
 
+        pa_operation_unref (o);
7715
 
+}
7716
 
+
7717
 
+static void
7718
 
+req_update_sink_input_info (GvcMixerControl *control,
7719
 
+                            int              index)
7720
 
+{
7721
 
+        pa_operation *o;
7722
 
+
7723
 
+        if (index < 0) {
7724
 
+                o = pa_context_get_sink_input_info_list (control->priv->pa_context,
7725
 
+                                                         _pa_context_get_sink_input_info_cb,
7726
 
+                                                         control);
7727
 
+        } else {
7728
 
+                o = pa_context_get_sink_input_info (control->priv->pa_context,
7729
 
+                                                    index,
7730
 
+                                                    _pa_context_get_sink_input_info_cb,
7731
 
+                                                    control);
7732
 
+        }
7733
 
+
7734
 
+        if (o == NULL) {
7735
 
+                g_warning ("pa_context_get_sink_input_info_list() failed");
7736
 
+                return;
7737
 
+        }
7738
 
+        pa_operation_unref (o);
7739
 
+}
7740
 
+
7741
 
+static void
7742
 
+req_update_source_output_info (GvcMixerControl *control,
7743
 
+                               int              index)
7744
 
+{
7745
 
+        pa_operation *o;
7746
 
+
7747
 
+        if (index < 0) {
7748
 
+                o = pa_context_get_source_output_info_list (control->priv->pa_context,
7749
 
+                                                            _pa_context_get_source_output_info_cb,
7750
 
+                                                            control);
7751
 
+        } else {
7752
 
+                o = pa_context_get_source_output_info (control->priv->pa_context,
7753
 
+                                                       index,
7754
 
+                                                       _pa_context_get_source_output_info_cb,
7755
 
+                                                       control);
7756
 
+        }
7757
 
+
7758
 
+        if (o == NULL) {
7759
 
+                g_warning ("pa_context_get_source_output_info_list() failed");
7760
 
+                return;
7761
 
+        }
7762
 
+        pa_operation_unref (o);
7763
 
+}
7764
 
+
7765
 
+static void
7766
 
+remove_client (GvcMixerControl *control,
7767
 
+               guint            index)
7768
 
+{
7769
 
+        g_hash_table_remove (control->priv->clients,
7770
 
+                             GUINT_TO_POINTER (index));
7771
 
+}
7772
 
+
7773
 
+static void
7774
 
+remove_card (GvcMixerControl *control,
7775
 
+             guint            index)
7776
 
+{
7777
 
+
7778
 
+        GList *devices;
7779
 
+        devices = g_list_concat (g_hash_table_get_values (control->priv->ui_inputs),
7780
 
+                                 g_hash_table_get_values (control->priv->ui_outputs));
7781
 
+
7782
 
+        GList            *d;
7783
 
+        GvcMixerUIDevice *device;
7784
 
+
7785
 
+        for (d = devices; d != NULL; d = d->next) {
7786
 
+                gint card_id = GVC_MIXER_UI_DEVICE_INVALID;
7787
 
+                device = d->data;
7788
 
+                g_object_get (G_OBJECT (device),
7789
 
+                             "card-id", &card_id,
7790
 
+                              NULL);
7791
 
+                if (card_id == index) {
7792
 
+                        g_signal_emit (G_OBJECT (control),
7793
 
+                                       signals[gvc_mixer_ui_device_is_output (device) ? OUTPUT_REMOVED : INPUT_REMOVED],
7794
 
+                                       0,
7795
 
+                                       gvc_mixer_ui_device_get_id (device));
7796
 
+                        g_debug ("\n Card removal remove device %s \n",
7797
 
+                                 gvc_mixer_ui_device_get_description (device)); 
7798
 
+                        g_hash_table_remove (gvc_mixer_ui_device_is_output (device) ? control->priv->ui_outputs : control->priv->ui_inputs, 
7799
 
+                                             GUINT_TO_POINTER (gvc_mixer_ui_device_get_id (device)));
7800
 
+                }
7801
 
+        }
7802
 
+        
7803
 
+        g_hash_table_remove (control->priv->cards,
7804
 
+                             GUINT_TO_POINTER (index));
7805
 
+
7806
 
+        g_signal_emit (G_OBJECT (control),
7807
 
+                       signals[CARD_REMOVED],
7808
 
+                       0,
7809
 
+                       index);
7810
 
+}
7811
 
+
7812
 
+static void
7813
 
+remove_sink (GvcMixerControl *control,
7814
 
+             guint            index)
7815
 
+{
7816
 
+        GvcMixerStream *stream;
7817
 
+
7818
 
+#if 0
7819
 
+        g_debug ("Removing sink: index=%u", index);
7820
 
+#endif
7821
 
+
7822
 
+        stream = g_hash_table_lookup (control->priv->sinks,
7823
 
+                                      GUINT_TO_POINTER (index));
7824
 
+        if (stream == NULL) {
7825
 
+                return;
7826
 
+        }   
7827
 
+
7828
 
+        GvcMixerUIDevice *device;
7829
 
+        device = gvc_mixer_control_lookup_device_from_stream (control, stream);
7830
 
+
7831
 
+        if (device != NULL){
7832
 
+                g_debug ("\n invalidate stream on device - remove-sinks - %s \n", gvc_mixer_ui_device_get_description (device));        
7833
 
+
7834
 
+                gvc_mixer_ui_device_invalidate_stream (device);
7835
 
+                // If its a software device - get rid of it
7836
 
+                if (gvc_mixer_ui_device_is_software (device) || gvc_mixer_ui_device_is_bluetooth (device)) {
7837
 
+                        g_signal_emit (G_OBJECT (control),
7838
 
+                                       signals[OUTPUT_REMOVED],
7839
 
+                                       0,
7840
 
+                                       gvc_mixer_ui_device_get_id (device));  
7841
 
+                }
7842
 
+                // otherwise check to make sure to invalidate other devices which may have that stream
7843
 
+                else{
7844
 
+                        GList   *d;
7845
 
+                        GList   *devices;
7846
 
+
7847
 
+                        devices = g_hash_table_get_values (control->priv->ui_outputs);          
7848
 
+
7849
 
+                        for (d = devices; d != NULL; d = d->next) {             
7850
 
+                                gint stream_id = GVC_MIXER_UI_DEVICE_INVALID;
7851
 
+                                device = d->data;
7852
 
+                                g_object_get (G_OBJECT (device),
7853
 
+                                             "stream-id", &stream_id,
7854
 
+                                              NULL);
7855
 
+                                if (stream_id == gvc_mixer_stream_get_id (stream)){
7856
 
+                                        g_debug ("\n invalidate stream on another relevant device - %s \n", gvc_mixer_ui_device_get_description (device)); 
7857
 
+                                        gvc_mixer_ui_device_invalidate_stream (device);
7858
 
+                                }
7859
 
+                        }
7860
 
+                }
7861
 
+        }
7862
 
+
7863
 
+        g_hash_table_remove (control->priv->sinks,
7864
 
+                             GUINT_TO_POINTER (index));
7865
 
+        remove_stream (control, stream);
7866
 
+}
7867
 
+
7868
 
+static void
7869
 
+remove_source (GvcMixerControl *control,
7870
 
+               guint            index)
7871
 
+{
7872
 
+        GvcMixerStream *stream;
7873
 
+
7874
 
+#if 0
7875
 
+        g_debug ("Removing source: index=%u", index);
7876
 
+#endif
7877
 
+
7878
 
+        stream = g_hash_table_lookup (control->priv->sources,
7879
 
+                                      GUINT_TO_POINTER (index));
7880
 
+        if (stream == NULL) {
7881
 
+                return;
7882
 
+        }
7883
 
+
7884
 
+        GvcMixerUIDevice *device;
7885
 
+        device = gvc_mixer_control_lookup_device_from_stream (control, stream);
7886
 
+
7887
 
+        if (device != NULL){
7888
 
+                g_debug ("\n invalidate stream on device - %s \n", gvc_mixer_ui_device_get_description (device));        
7889
 
+
7890
 
+                gvc_mixer_ui_device_invalidate_stream (device);
7891
 
+                // If its a software device - get rid of it
7892
 
+                if (gvc_mixer_ui_device_is_software (device) || gvc_mixer_ui_device_is_bluetooth (device)) {
7893
 
+                        g_signal_emit (G_OBJECT (control),
7894
 
+                                       signals[INPUT_REMOVED],
7895
 
+                                       0,
7896
 
+                                       gvc_mixer_ui_device_get_id (device));                            
7897
 
+                }
7898
 
+                // otherwise check to make sure to invalidate other devices which may have that stream
7899
 
+                else{
7900
 
+
7901
 
+                        GList           *d;
7902
 
+                        GList           *devices;
7903
 
+
7904
 
+                        devices = g_hash_table_get_values (control->priv->ui_inputs);          
7905
 
+
7906
 
+                        for (d = devices; d != NULL; d = d->next) {             
7907
 
+                                gint stream_id = GVC_MIXER_UI_DEVICE_INVALID;
7908
 
+                                device = d->data;
7909
 
+                                g_object_get (G_OBJECT (device),
7910
 
+                                             "stream-id", &stream_id,
7911
 
+                                              NULL);
7912
 
+                                if (stream_id == gvc_mixer_stream_get_id (stream)){
7913
 
+                                        g_debug ("\n invalidate stream on another relevant device - %s \n", gvc_mixer_ui_device_get_description (device)); 
7914
 
+                                        gvc_mixer_ui_device_invalidate_stream (device);
7915
 
+                                }
7916
 
+                        }
7917
 
+                }
7918
 
+        }
7919
 
+
7920
 
+
7921
 
+        g_hash_table_remove (control->priv->sources,
7922
 
+                             GUINT_TO_POINTER (index));
7923
 
+
7924
 
+        remove_stream (control, stream);
7925
 
+}
7926
 
+
7927
 
+static void
7928
 
+remove_sink_input (GvcMixerControl *control,
7929
 
+                   guint            index)
7930
 
+{
7931
 
+        GvcMixerStream *stream;
7932
 
+
7933
 
+#if 0
7934
 
+        g_debug ("Removing sink input: index=%u", index);
7935
 
+#endif
7936
 
+        stream = g_hash_table_lookup (control->priv->sink_inputs,
7937
 
+                                      GUINT_TO_POINTER (index));
7938
 
+        if (stream == NULL) {
7939
 
+                return;
7940
 
+        }
7941
 
+        g_hash_table_remove (control->priv->sink_inputs,
7942
 
+                             GUINT_TO_POINTER (index));
7943
 
+
7944
 
+        remove_stream (control, stream);
7945
 
+}
7946
 
+
7947
 
+static void
7948
 
+remove_source_output (GvcMixerControl *control,
7949
 
+                      guint            index)
7950
 
+{
7951
 
+        GvcMixerStream *stream;
7952
 
+
7953
 
+#if 0
7954
 
+        g_debug ("Removing source output: index=%u", index);
7955
 
+#endif
7956
 
+
7957
 
+        stream = g_hash_table_lookup (control->priv->source_outputs,
7958
 
+                                      GUINT_TO_POINTER (index));
7959
 
+        if (stream == NULL) {
7960
 
+                return;
7961
 
+        }
7962
 
+        g_hash_table_remove (control->priv->source_outputs,
7963
 
+                             GUINT_TO_POINTER (index));
7964
 
+
7965
 
+        remove_stream (control, stream);
7966
 
+}
7967
 
+
7968
 
+static void
7969
 
+_pa_context_subscribe_cb (pa_context                  *context,
7970
 
+                          pa_subscription_event_type_t t,
7971
 
+                          uint32_t                     index,
7972
 
+                          void                        *userdata)
7973
 
+{
7974
 
+        GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7975
 
+
7976
 
+        switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
7977
 
+        case PA_SUBSCRIPTION_EVENT_SINK:
7978
 
+                if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
7979
 
+                        remove_sink (control, index);
7980
 
+                } else {
7981
 
+                        req_update_sink_info (control, index);
7982
 
+                }
7983
 
+                break;
7984
 
+
7985
 
+        case PA_SUBSCRIPTION_EVENT_SOURCE:
7986
 
+                if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
7987
 
+                        remove_source (control, index);
7988
 
+                } else {
7989
 
+                        req_update_source_info (control, index);
7990
 
+                }
7991
 
+                break;
7992
 
+
7993
 
+        case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
7994
 
+                if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
7995
 
+                        remove_sink_input (control, index);
7996
 
+                } else {
7997
 
+                        req_update_sink_input_info (control, index);
7998
 
+                }
7999
 
+                break;
8000
 
+
8001
 
+        case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
8002
 
+                if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
8003
 
+                        remove_source_output (control, index);
8004
 
+                } else {
8005
 
+                        req_update_source_output_info (control, index);
8006
 
+                }
8007
 
+                break;
8008
 
+
8009
 
+        case PA_SUBSCRIPTION_EVENT_CLIENT:
8010
 
+                if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
8011
 
+                        remove_client (control, index);
8012
 
+                } else {
8013
 
+                        req_update_client_info (control, index);
8014
 
+                }
8015
 
+                break;
8016
 
+
8017
 
+        case PA_SUBSCRIPTION_EVENT_SERVER:
8018
 
+                req_update_server_info (control, index);
8019
 
+                break;
8020
 
+
8021
 
+        case PA_SUBSCRIPTION_EVENT_CARD:
8022
 
+                if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
8023
 
+                        remove_card (control, index);
8024
 
+                } else {
8025
 
+                        req_update_card (control, index);
8026
 
+                }
8027
 
+                break;
8028
 
+        }
8029
 
+}
8030
 
+
8031
 
+static void
8032
 
+gvc_mixer_control_ready (GvcMixerControl *control)
8033
 
+{
8034
 
+        pa_operation *o;
8035
 
+
8036
 
+        pa_context_set_subscribe_callback (control->priv->pa_context,
8037
 
+                                           _pa_context_subscribe_cb,
8038
 
+                                           control);
8039
 
+        o = pa_context_subscribe (control->priv->pa_context,
8040
 
+                                  (pa_subscription_mask_t)
8041
 
+                                  (PA_SUBSCRIPTION_MASK_SINK|
8042
 
+                                   PA_SUBSCRIPTION_MASK_SOURCE|
8043
 
+                                   PA_SUBSCRIPTION_MASK_SINK_INPUT|
8044
 
+                                   PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT|
8045
 
+                                   PA_SUBSCRIPTION_MASK_CLIENT|
8046
 
+                                   PA_SUBSCRIPTION_MASK_SERVER|
8047
 
+                                   PA_SUBSCRIPTION_MASK_CARD),
8048
 
+                                  NULL,
8049
 
+                                  NULL);
8050
 
+
8051
 
+        if (o == NULL) {
8052
 
+                g_warning ("pa_context_subscribe() failed");
8053
 
+                return;
8054
 
+        }
8055
 
+        pa_operation_unref (o);
8056
 
+
8057
 
+        req_update_server_info (control, -1);
8058
 
+        req_update_card (control, -1);
8059
 
+        req_update_client_info (control, -1);
8060
 
+        req_update_sink_info (control, -1);
8061
 
+        req_update_source_info (control, -1);
8062
 
+        req_update_sink_input_info (control, -1);
8063
 
+        req_update_source_output_info (control, -1);
8064
 
+
8065
 
+        control->priv->n_outstanding = 6;
8066
 
+
8067
 
+        /* This call is not always supported */
8068
 
+        o = pa_ext_stream_restore_read (control->priv->pa_context,
8069
 
+                                        _pa_ext_stream_restore_read_cb,
8070
 
+                                        control);
8071
 
+        if (o != NULL) {
8072
 
+                pa_operation_unref (o);
8073
 
+                control->priv->n_outstanding++;
8074
 
+
8075
 
+                pa_ext_stream_restore_set_subscribe_cb (control->priv->pa_context,
8076
 
+                                                        _pa_ext_stream_restore_subscribe_cb,
8077
 
+                                                        control);
8078
 
+
8079
 
+                o = pa_ext_stream_restore_subscribe (control->priv->pa_context,
8080
 
+                                                     1,
8081
 
+                                                     NULL,
8082
 
+                                                     NULL);
8083
 
+                if (o != NULL) {
8084
 
+                        pa_operation_unref (o);
8085
 
+                }
8086
 
+
8087
 
+        } else {
8088
 
+                g_debug ("Failed to initialized stream_restore extension: %s",
8089
 
+                         pa_strerror (pa_context_errno (control->priv->pa_context)));
8090
 
+        }
8091
 
+}
8092
 
+
8093
 
+static void
8094
 
+gvc_mixer_new_pa_context (GvcMixerControl *self)
8095
 
+{
8096
 
+        pa_proplist     *proplist;
8097
 
+
8098
 
+        g_return_if_fail (self);
8099
 
+        g_return_if_fail (!self->priv->pa_context);
8100
 
+
8101
 
+        proplist = pa_proplist_new ();
8102
 
+        pa_proplist_sets (proplist,
8103
 
+                          PA_PROP_APPLICATION_NAME,
8104
 
+                          self->priv->name);
8105
 
+        pa_proplist_sets (proplist,
8106
 
+                          PA_PROP_APPLICATION_ID,
8107
 
+                          "org.gnome.VolumeControl");
8108
 
+        pa_proplist_sets (proplist,
8109
 
+                          PA_PROP_APPLICATION_ICON_NAME,
8110
 
+                          "multimedia-volume-control");
8111
 
+        pa_proplist_sets (proplist,
8112
 
+                          PA_PROP_APPLICATION_VERSION,
8113
 
+                          PACKAGE_VERSION);
8114
 
+
8115
 
+        self->priv->pa_context = pa_context_new_with_proplist (self->priv->pa_api, NULL, proplist);
8116
 
+
8117
 
+        pa_proplist_free (proplist);
8118
 
+        g_assert (self->priv->pa_context);
8119
 
+}
8120
 
+
8121
 
+static void
8122
 
+remove_all_streams (GvcMixerControl *control, GHashTable *hash_table)
8123
 
+{
8124
 
+        GHashTableIter iter;
8125
 
+        gpointer key, value;
8126
 
+
8127
 
+        g_hash_table_iter_init (&iter, hash_table);
8128
 
+        while (g_hash_table_iter_next (&iter, &key, &value)) {
8129
 
+                remove_stream (control, value);
8130
 
+                g_hash_table_iter_remove (&iter);
8131
 
+        }
8132
 
+}
8133
 
+
8134
 
+static gboolean
8135
 
+idle_reconnect (gpointer data)
8136
 
+{
8137
 
+        GvcMixerControl *control = GVC_MIXER_CONTROL (data);
8138
 
+        GHashTableIter iter;
8139
 
+        gpointer key, value;
8140
 
+
8141
 
+        g_return_val_if_fail (control, FALSE);
8142
 
+
8143
 
+        if (control->priv->pa_context) {
8144
 
+                pa_context_unref (control->priv->pa_context);
8145
 
+                control->priv->pa_context = NULL;
8146
 
+                gvc_mixer_new_pa_context (control);
8147
 
+        }
8148
 
+
8149
 
+        remove_all_streams (control, control->priv->sinks);
8150
 
+        remove_all_streams (control, control->priv->sources);
8151
 
+        remove_all_streams (control, control->priv->sink_inputs);
8152
 
+        remove_all_streams (control, control->priv->source_outputs);
8153
 
+
8154
 
+        g_hash_table_iter_init (&iter, control->priv->clients);
8155
 
+        while (g_hash_table_iter_next (&iter, &key, &value))
8156
 
+                g_hash_table_iter_remove (&iter);
8157
 
+
8158
 
+        gvc_mixer_control_open (control); /* cannot fail */
8159
 
+
8160
 
+        control->priv->reconnect_id = 0;
8161
 
+        return FALSE;
8162
 
+}
8163
 
+
8164
 
+static void
8165
 
+_pa_context_state_cb (pa_context *context,
8166
 
+                      void       *userdata)
8167
 
+{
8168
 
+        GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
8169
 
+
8170
 
+        switch (pa_context_get_state (context)) {
8171
 
+        case PA_CONTEXT_UNCONNECTED:
8172
 
+        case PA_CONTEXT_CONNECTING:
8173
 
+        case PA_CONTEXT_AUTHORIZING:
8174
 
+        case PA_CONTEXT_SETTING_NAME:
8175
 
+                break;
8176
 
+
8177
 
+        case PA_CONTEXT_READY:
8178
 
+                gvc_mixer_control_ready (control);
8179
 
+                break;
8180
 
+
8181
 
+        case PA_CONTEXT_FAILED:
8182
 
+                control->priv->state = GVC_STATE_FAILED;
8183
 
+                g_signal_emit (control, signals[STATE_CHANGED], 0, GVC_STATE_FAILED);
8184
 
+                if (control->priv->reconnect_id == 0)
8185
 
+                        control->priv->reconnect_id = g_timeout_add_seconds (RECONNECT_DELAY, idle_reconnect, control);
8186
 
+                break;
8187
 
+
8188
 
+        case PA_CONTEXT_TERMINATED:
8189
 
+        default:
8190
 
+                /* FIXME: */
8191
 
+                break;
8192
 
+        }
8193
 
+}
8194
 
+
8195
 
+gboolean
8196
 
+gvc_mixer_control_open (GvcMixerControl *control)
8197
 
+{
8198
 
+        int res;
8199
 
+
8200
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE);
8201
 
+        g_return_val_if_fail (control->priv->pa_context != NULL, FALSE);
8202
 
+        g_return_val_if_fail (pa_context_get_state (control->priv->pa_context) == PA_CONTEXT_UNCONNECTED, FALSE);
8203
 
+
8204
 
+        pa_context_set_state_callback (control->priv->pa_context,
8205
 
+                                       _pa_context_state_cb,
8206
 
+                                       control);
8207
 
+
8208
 
+        control->priv->state = GVC_STATE_CONNECTING;
8209
 
+        g_signal_emit (G_OBJECT (control), signals[STATE_CHANGED], 0, GVC_STATE_CONNECTING);
8210
 
+        res = pa_context_connect (control->priv->pa_context, NULL, (pa_context_flags_t) PA_CONTEXT_NOFAIL, NULL);
8211
 
+        if (res < 0) {
8212
 
+                g_warning ("Failed to connect context: %s",
8213
 
+                           pa_strerror (pa_context_errno (control->priv->pa_context)));
8214
 
+        }
8215
 
+
8216
 
+        return res;
8217
 
+}
8218
 
+
8219
 
+gboolean
8220
 
+gvc_mixer_control_close (GvcMixerControl *control)
8221
 
+{
8222
 
+        g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE);
8223
 
+        g_return_val_if_fail (control->priv->pa_context != NULL, FALSE);
8224
 
+
8225
 
+        pa_context_disconnect (control->priv->pa_context);
8226
 
+
8227
 
+        control->priv->state = GVC_STATE_CLOSED;
8228
 
+        g_signal_emit (G_OBJECT (control), signals[STATE_CHANGED], 0, GVC_STATE_CLOSED);
8229
 
+        return TRUE;
8230
 
+}
8231
 
+
8232
 
+static void
8233
 
+gvc_mixer_control_dispose (GObject *object)
8234
 
+{
8235
 
+        GvcMixerControl *control = GVC_MIXER_CONTROL (object);
8236
 
+
8237
 
+        if (control->priv->reconnect_id != 0) {
8238
 
+                g_source_remove (control->priv->reconnect_id);
8239
 
+                control->priv->reconnect_id = 0;
8240
 
+        }
8241
 
+
8242
 
+        if (control->priv->pa_context != NULL) {
8243
 
+                pa_context_unref (control->priv->pa_context);
8244
 
+                control->priv->pa_context = NULL;
8245
 
+        }
8246
 
+
8247
 
+        if (control->priv->default_source_name != NULL) {
8248
 
+                g_free (control->priv->default_source_name);
8249
 
+                control->priv->default_source_name = NULL;
8250
 
+        }
8251
 
+        if (control->priv->default_sink_name != NULL) {
8252
 
+                g_free (control->priv->default_sink_name);
8253
 
+                control->priv->default_sink_name = NULL;
8254
 
+        }
8255
 
+
8256
 
+        if (control->priv->pa_mainloop != NULL) {
8257
 
+                pa_glib_mainloop_free (control->priv->pa_mainloop);
8258
 
+                control->priv->pa_mainloop = NULL;
8259
 
+        }
8260
 
+
8261
 
+        if (control->priv->all_streams != NULL) {
8262
 
+                g_hash_table_destroy (control->priv->all_streams);
8263
 
+                control->priv->all_streams = NULL;
8264
 
+        }
8265
 
+
8266
 
+        if (control->priv->sinks != NULL) {
8267
 
+                g_hash_table_destroy (control->priv->sinks);
8268
 
+                control->priv->sinks = NULL;
8269
 
+        }
8270
 
+        if (control->priv->sources != NULL) {
8271
 
+                g_hash_table_destroy (control->priv->sources);
8272
 
+                control->priv->sources = NULL;
8273
 
+        }
8274
 
+        if (control->priv->sink_inputs != NULL) {
8275
 
+                g_hash_table_destroy (control->priv->sink_inputs);
8276
 
+                control->priv->sink_inputs = NULL;
8277
 
+        }
8278
 
+        if (control->priv->source_outputs != NULL) {
8279
 
+                g_hash_table_destroy (control->priv->source_outputs);
8280
 
+                control->priv->source_outputs = NULL;
8281
 
+        }
8282
 
+        if (control->priv->clients != NULL) {
8283
 
+                g_hash_table_destroy (control->priv->clients);
8284
 
+                control->priv->clients = NULL;
8285
 
+        }
8286
 
+        if (control->priv->cards != NULL) {
8287
 
+                g_hash_table_destroy (control->priv->cards);
8288
 
+                control->priv->cards = NULL;
8289
 
+        }
8290
 
+        if (control->priv->ui_outputs != NULL) {
8291
 
+                g_hash_table_destroy (control->priv->ui_outputs);
8292
 
+                control->priv->ui_outputs = NULL;
8293
 
+        }
8294
 
+        if (control->priv->ui_inputs != NULL) {
8295
 
+                g_hash_table_destroy (control->priv->ui_inputs);
8296
 
+                control->priv->ui_inputs = NULL;
8297
 
+        }
8298
 
+        
8299
 
+
8300
 
+        G_OBJECT_CLASS (gvc_mixer_control_parent_class)->dispose (object);
8301
 
+}
8302
 
+
8303
 
+static void
8304
 
+gvc_mixer_control_set_property (GObject       *object,
8305
 
+                                guint          prop_id,
8306
 
+                                const GValue  *value,
8307
 
+                                GParamSpec    *pspec)
8308
 
+{
8309
 
+        GvcMixerControl *self = GVC_MIXER_CONTROL (object);
8310
 
+
8311
 
+        switch (prop_id) {
8312
 
+        case PROP_NAME:
8313
 
+                g_free (self->priv->name);
8314
 
+                self->priv->name = g_value_dup_string (value);
8315
 
+                g_object_notify (G_OBJECT (self), "name");
8316
 
+                break;
8317
 
+        default:
8318
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
8319
 
+                break;
8320
 
+        }
8321
 
+}
8322
 
+
8323
 
+static void
8324
 
+gvc_mixer_control_get_property (GObject     *object,
8325
 
+                                guint        prop_id,
8326
 
+                                GValue      *value,
8327
 
+                                GParamSpec  *pspec)
8328
 
+{
8329
 
+        GvcMixerControl *self = GVC_MIXER_CONTROL (object);
8330
 
+
8331
 
+        switch (prop_id) {
8332
 
+        case PROP_NAME:
8333
 
+                g_value_set_string (value, self->priv->name);
8334
 
+                break;
8335
 
+        default:
8336
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
8337
 
+                break;
8338
 
+        }
8339
 
+}
8340
 
+
8341
 
+
8342
 
+static GObject *
8343
 
+gvc_mixer_control_constructor (GType                  type,
8344
 
+                               guint                  n_construct_properties,
8345
 
+                               GObjectConstructParam *construct_params)
8346
 
+{
8347
 
+        GObject         *object;
8348
 
+        GvcMixerControl *self;
8349
 
+
8350
 
+        object = G_OBJECT_CLASS (gvc_mixer_control_parent_class)->constructor (type, n_construct_properties, construct_params);
8351
 
+
8352
 
+        self = GVC_MIXER_CONTROL (object);
8353
 
+
8354
 
+        gvc_mixer_new_pa_context (self);
8355
 
+        self->priv->profile_swapping_device_id = GVC_MIXER_UI_DEVICE_INVALID;
8356
 
+
8357
 
+        return object;
8358
 
+}
8359
 
+
8360
 
+static void
8361
 
+gvc_mixer_control_class_init (GvcMixerControlClass *klass)
8362
 
+{
8363
 
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
8364
 
+
8365
 
+        object_class->constructor = gvc_mixer_control_constructor;
8366
 
+        object_class->dispose = gvc_mixer_control_dispose;
8367
 
+        object_class->finalize = gvc_mixer_control_finalize;
8368
 
+        object_class->set_property = gvc_mixer_control_set_property;
8369
 
+        object_class->get_property = gvc_mixer_control_get_property;
8370
 
+
8371
 
+        g_object_class_install_property (object_class,
8372
 
+                                         PROP_NAME,
8373
 
+                                         g_param_spec_string ("name",
8374
 
+                                                              "Name",
8375
 
+                                                              "Name to display for this mixer control",
8376
 
+                                                              NULL,
8377
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
8378
 
+
8379
 
+        signals [STATE_CHANGED] =
8380
 
+                g_signal_new ("state-changed",
8381
 
+                              G_TYPE_FROM_CLASS (klass),
8382
 
+                              G_SIGNAL_RUN_LAST,
8383
 
+                              G_STRUCT_OFFSET (GvcMixerControlClass, state_changed),
8384
 
+                              NULL, NULL,
8385
 
+                              g_cclosure_marshal_VOID__UINT,
8386
 
+                              G_TYPE_NONE, 1, G_TYPE_UINT);
8387
 
+        signals [STREAM_ADDED] =
8388
 
+                g_signal_new ("stream-added",
8389
 
+                              G_TYPE_FROM_CLASS (klass),
8390
 
+                              G_SIGNAL_RUN_LAST,
8391
 
+                              G_STRUCT_OFFSET (GvcMixerControlClass, stream_added),
8392
 
+                              NULL, NULL,
8393
 
+                              g_cclosure_marshal_VOID__UINT,
8394
 
+                              G_TYPE_NONE, 1, G_TYPE_UINT);
8395
 
+        signals [STREAM_REMOVED] =
8396
 
+                g_signal_new ("stream-removed",
8397
 
+                              G_TYPE_FROM_CLASS (klass),
8398
 
+                              G_SIGNAL_RUN_LAST,
8399
 
+                              G_STRUCT_OFFSET (GvcMixerControlClass, stream_removed),
8400
 
+                              NULL, NULL,
8401
 
+                              g_cclosure_marshal_VOID__UINT,
8402
 
+                              G_TYPE_NONE, 1, G_TYPE_UINT);
8403
 
+        signals [CARD_ADDED] =
8404
 
+                g_signal_new ("card-added",
8405
 
+                              G_TYPE_FROM_CLASS (klass),
8406
 
+                              G_SIGNAL_RUN_LAST,
8407
 
+                              G_STRUCT_OFFSET (GvcMixerControlClass, card_added),
8408
 
+                              NULL, NULL,
8409
 
+                              g_cclosure_marshal_VOID__UINT,
8410
 
+                              G_TYPE_NONE, 1, G_TYPE_UINT);
8411
 
+        signals [CARD_REMOVED] =
8412
 
+                g_signal_new ("card-removed",
8413
 
+                              G_TYPE_FROM_CLASS (klass),
8414
 
+                              G_SIGNAL_RUN_LAST,
8415
 
+                              G_STRUCT_OFFSET (GvcMixerControlClass, card_removed),
8416
 
+                              NULL, NULL,
8417
 
+                              g_cclosure_marshal_VOID__UINT,
8418
 
+                              G_TYPE_NONE, 1, G_TYPE_UINT);
8419
 
+        signals [DEFAULT_SINK_CHANGED] =
8420
 
+                g_signal_new ("default-sink-changed",
8421
 
+                              G_TYPE_FROM_CLASS (klass),
8422
 
+                              G_SIGNAL_RUN_LAST,
8423
 
+                              G_STRUCT_OFFSET (GvcMixerControlClass, default_sink_changed),
8424
 
+                              NULL, NULL,
8425
 
+                              g_cclosure_marshal_VOID__UINT,
8426
 
+                              G_TYPE_NONE, 1, G_TYPE_UINT);
8427
 
+        signals [DEFAULT_SOURCE_CHANGED] =
8428
 
+                g_signal_new ("default-source-changed",
8429
 
+                              G_TYPE_FROM_CLASS (klass),
8430
 
+                              G_SIGNAL_RUN_LAST,
8431
 
+                              G_STRUCT_OFFSET (GvcMixerControlClass, default_source_changed),
8432
 
+                              NULL, NULL,
8433
 
+                              g_cclosure_marshal_VOID__UINT,
8434
 
+                              G_TYPE_NONE, 1, G_TYPE_UINT);
8435
 
+        signals [OUTPUT_ADDED] =
8436
 
+                g_signal_new ("output-added",
8437
 
+                              G_TYPE_FROM_CLASS (klass),
8438
 
+                              G_SIGNAL_RUN_LAST,
8439
 
+                              G_STRUCT_OFFSET (GvcMixerControlClass, output_added),
8440
 
+                              NULL, NULL,
8441
 
+                              g_cclosure_marshal_VOID__UINT,
8442
 
+                              G_TYPE_NONE, 1, G_TYPE_UINT);
8443
 
+
8444
 
+        signals [ACTIVE_OUTPUT_UPDATE] =
8445
 
+                g_signal_new ("active-output-update",
8446
 
+                              G_TYPE_FROM_CLASS (klass),
8447
 
+                              G_SIGNAL_RUN_LAST,
8448
 
+                              G_STRUCT_OFFSET (GvcMixerControlClass, active_output_update),
8449
 
+                              NULL, NULL,
8450
 
+                              g_cclosure_marshal_VOID__UINT,
8451
 
+                              G_TYPE_NONE, 1, G_TYPE_UINT);
8452
 
+
8453
 
+        signals [OUTPUT_REMOVED] =
8454
 
+                g_signal_new ("output-removed",
8455
 
+                              G_TYPE_FROM_CLASS (klass),
8456
 
+                              G_SIGNAL_RUN_LAST,
8457
 
+                              G_STRUCT_OFFSET (GvcMixerControlClass, output_removed),
8458
 
+                              NULL, NULL,
8459
 
+                              g_cclosure_marshal_VOID__UINT,
8460
 
+                              G_TYPE_NONE, 1, G_TYPE_UINT);
8461
 
+        signals [INPUT_ADDED] =
8462
 
+                g_signal_new ("input-added",
8463
 
+                              G_TYPE_FROM_CLASS (klass),
8464
 
+                              G_SIGNAL_RUN_LAST,
8465
 
+                              G_STRUCT_OFFSET (GvcMixerControlClass, input_added),
8466
 
+                              NULL, NULL,
8467
 
+                              g_cclosure_marshal_VOID__UINT,
8468
 
+                              G_TYPE_NONE, 1, G_TYPE_UINT);
8469
 
+        signals [INPUT_REMOVED] =
8470
 
+                g_signal_new ("input-removed",
8471
 
+                              G_TYPE_FROM_CLASS (klass),
8472
 
+                              G_SIGNAL_RUN_LAST,
8473
 
+                              G_STRUCT_OFFSET (GvcMixerControlClass, input_removed),
8474
 
+                              NULL, NULL,
8475
 
+                              g_cclosure_marshal_VOID__UINT,
8476
 
+                              G_TYPE_NONE, 1, G_TYPE_UINT);
8477
 
+        signals [ACTIVE_INPUT_UPDATE] =
8478
 
+                g_signal_new ("active-input-update",
8479
 
+                              G_TYPE_FROM_CLASS (klass),
8480
 
+                              G_SIGNAL_RUN_LAST,
8481
 
+                              G_STRUCT_OFFSET (GvcMixerControlClass, active_input_update),
8482
 
+                              NULL, NULL,
8483
 
+                              g_cclosure_marshal_VOID__UINT,
8484
 
+                              G_TYPE_NONE, 1, G_TYPE_UINT);                              
8485
 
+        g_type_class_add_private (klass, sizeof (GvcMixerControlPrivate));
8486
 
+}
8487
 
+
8488
 
+
8489
 
+static void
8490
 
+gvc_mixer_control_init (GvcMixerControl *control)
8491
 
+{
8492
 
+        control->priv = GVC_MIXER_CONTROL_GET_PRIVATE (control);
8493
 
+
8494
 
+        control->priv->pa_mainloop = pa_glib_mainloop_new (g_main_context_default ());
8495
 
+        g_assert (control->priv->pa_mainloop);
8496
 
+
8497
 
+        control->priv->pa_api = pa_glib_mainloop_get_api (control->priv->pa_mainloop);
8498
 
+        g_assert (control->priv->pa_api);
8499
 
+
8500
 
+        control->priv->all_streams = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref);
8501
 
+        control->priv->sinks = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref);
8502
 
+        control->priv->sources = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref);
8503
 
+        control->priv->sink_inputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref);
8504
 
+        control->priv->source_outputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref);
8505
 
+        control->priv->cards = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref);
8506
 
+        control->priv->ui_outputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref);
8507
 
+        control->priv->ui_inputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref);
8508
 
+
8509
 
+        control->priv->clients = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_free);
8510
 
+
8511
 
+        control->priv->state = GVC_STATE_CLOSED;
8512
 
+}
8513
 
+
8514
 
+static void
8515
 
+gvc_mixer_control_finalize (GObject *object)
8516
 
+{
8517
 
+        GvcMixerControl *mixer_control;
8518
 
+
8519
 
+        g_return_if_fail (object != NULL);
8520
 
+        g_return_if_fail (GVC_IS_MIXER_CONTROL (object));
8521
 
+
8522
 
+        mixer_control = GVC_MIXER_CONTROL (object);
8523
 
+        g_free (mixer_control->priv->name);
8524
 
+        mixer_control->priv->name = NULL;
8525
 
+
8526
 
+        g_return_if_fail (mixer_control->priv != NULL);
8527
 
+        G_OBJECT_CLASS (gvc_mixer_control_parent_class)->finalize (object);
8528
 
+}
8529
 
+
8530
 
+GvcMixerControl *
8531
 
+gvc_mixer_control_new (const char *name)
8532
 
+{
8533
 
+        GObject *control;
8534
 
+        control = g_object_new (GVC_TYPE_MIXER_CONTROL,
8535
 
+                                "name", name,
8536
 
+                                NULL);
8537
 
+        return GVC_MIXER_CONTROL (control);
8538
 
+}
8539
 
+
8540
 
+/* FIXME: Remove when PA 0.9.23 is used */
8541
 
+#ifndef PA_VOLUME_UI_MAX
8542
 
+#define PA_VOLUME_UI_MAX pa_sw_volume_from_dB(+11.0)
8543
 
+#endif
8544
 
+
8545
 
+gdouble
8546
 
+gvc_mixer_control_get_vol_max_norm (GvcMixerControl *control)
8547
 
+{
8548
 
+       return (gdouble) PA_VOLUME_NORM;
8549
 
+}
8550
 
+
8551
 
+gdouble
8552
 
+gvc_mixer_control_get_vol_max_amplified (GvcMixerControl *control)
8553
 
+{
8554
 
+       return (gdouble) PA_VOLUME_UI_MAX;
8555
 
+}
8556
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-control.h
8557
 
===================================================================
8558
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
8559
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-control.h     2012-08-28 17:08:49.452516900 +0200
8560
 
@@ -0,0 +1,139 @@
8561
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
8562
 
+ *
8563
 
+ * Copyright (C) 2008 Red Hat, Inc.
8564
 
+ *
8565
 
+ * This program is free software; you can redistribute it and/or modify
8566
 
+ * it under the terms of the GNU General Public License as published by
8567
 
+ * the Free Software Foundation; either version 2 of the License, or
8568
 
+ * (at your option) any later version.
8569
 
+ *
8570
 
+ * This program is distributed in the hope that it will be useful,
8571
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
8572
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8573
 
+ * GNU General Public License for more details.
8574
 
+ *
8575
 
+ * You should have received a copy of the GNU General Public License
8576
 
+ * along with this program; if not, write to the Free Software
8577
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
8578
 
+ *
8579
 
+ */
8580
 
+
8581
 
+#ifndef __GVC_MIXER_CONTROL_H
8582
 
+#define __GVC_MIXER_CONTROL_H
8583
 
+
8584
 
+#include <glib-object.h>
8585
 
+#include "gvc-mixer-stream.h"
8586
 
+#include "gvc-mixer-card.h"
8587
 
+#include "gvc-mixer-ui-device.h"
8588
 
+
8589
 
+G_BEGIN_DECLS
8590
 
+
8591
 
+typedef enum
8592
 
+{
8593
 
+        GVC_STATE_CLOSED,
8594
 
+        GVC_STATE_READY,
8595
 
+        GVC_STATE_CONNECTING,
8596
 
+        GVC_STATE_FAILED
8597
 
+} GvcMixerControlState;
8598
 
+
8599
 
+#define GVC_TYPE_MIXER_CONTROL         (gvc_mixer_control_get_type ())
8600
 
+#define GVC_MIXER_CONTROL(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControl))
8601
 
+#define GVC_MIXER_CONTROL_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_CONTROL, GvcMixerControlClass))
8602
 
+#define GVC_IS_MIXER_CONTROL(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_CONTROL))
8603
 
+#define GVC_IS_MIXER_CONTROL_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_CONTROL))
8604
 
+#define GVC_MIXER_CONTROL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControlClass))
8605
 
+
8606
 
+typedef struct GvcMixerControlPrivate GvcMixerControlPrivate;
8607
 
+
8608
 
+typedef struct
8609
 
+{
8610
 
+        GObject                 parent;
8611
 
+        GvcMixerControlPrivate *priv;
8612
 
+} GvcMixerControl;
8613
 
+
8614
 
+typedef struct
8615
 
+{
8616
 
+        GObjectClass            parent_class;
8617
 
+
8618
 
+        void (*state_changed)          (GvcMixerControl      *control,
8619
 
+                                        GvcMixerControlState  new_state);
8620
 
+        void (*stream_added)           (GvcMixerControl *control,
8621
 
+                                        guint            id);
8622
 
+        void (*stream_removed)         (GvcMixerControl *control,
8623
 
+                                        guint            id);
8624
 
+        void (*card_added)             (GvcMixerControl *control,
8625
 
+                                        guint            id);
8626
 
+        void (*card_removed)           (GvcMixerControl *control,
8627
 
+                                        guint            id);
8628
 
+        void (*default_sink_changed)   (GvcMixerControl *control,
8629
 
+                                        guint            id);
8630
 
+        void (*default_source_changed) (GvcMixerControl *control,
8631
 
+                                        guint            id);
8632
 
+        void (*output_added)           (GvcMixerControl *control,
8633
 
+                                        guint            id);
8634
 
+        void (*output_removed)         (GvcMixerControl *control,
8635
 
+                                        guint            id);
8636
 
+        void (*active_output_update)   (GvcMixerControl *control,
8637
 
+                                        guint            id);
8638
 
+        void (*active_input_update)    (GvcMixerControl *control,
8639
 
+                                        guint            id);
8640
 
+        void (*input_added)            (GvcMixerControl *control,
8641
 
+                                        guint            id);
8642
 
+        void (*input_removed)          (GvcMixerControl *control,
8643
 
+                                        guint            id);
8644
 
+                                        
8645
 
+} GvcMixerControlClass;
8646
 
+
8647
 
+GType               gvc_mixer_control_get_type            (void);
8648
 
+
8649
 
+GvcMixerControl *   gvc_mixer_control_new                 (const char *name);
8650
 
+
8651
 
+gboolean            gvc_mixer_control_open                (GvcMixerControl *control);
8652
 
+gboolean            gvc_mixer_control_close               (GvcMixerControl *control);
8653
 
+
8654
 
+GSList *            gvc_mixer_control_get_cards           (GvcMixerControl *control);
8655
 
+GSList *            gvc_mixer_control_get_streams         (GvcMixerControl *control);
8656
 
+GSList *            gvc_mixer_control_get_sinks           (GvcMixerControl *control);
8657
 
+GSList *            gvc_mixer_control_get_sources         (GvcMixerControl *control);
8658
 
+GSList *            gvc_mixer_control_get_sink_inputs     (GvcMixerControl *control);
8659
 
+GSList *            gvc_mixer_control_get_source_outputs  (GvcMixerControl *control);
8660
 
+
8661
 
+GvcMixerStream *        gvc_mixer_control_lookup_stream_id    (GvcMixerControl *control,
8662
 
+                                                           guint            id);
8663
 
+GvcMixerCard   *        gvc_mixer_control_lookup_card_id      (GvcMixerControl *control,
8664
 
+                                                           guint            id);
8665
 
+GvcMixerUIDevice *      gvc_mixer_control_lookup_output_id    (GvcMixerControl *control,
8666
 
+                                                           guint            id);                                                                      
8667
 
+GvcMixerUIDevice *      gvc_mixer_control_lookup_input_id    (GvcMixerControl *control,
8668
 
+                                                          guint            id);                                                                       
8669
 
+
8670
 
+GvcMixerStream *        gvc_mixer_control_get_default_sink     (GvcMixerControl *control);
8671
 
+GvcMixerStream *        gvc_mixer_control_get_default_source   (GvcMixerControl *control);
8672
 
+GvcMixerStream *        gvc_mixer_control_get_event_sink_input (GvcMixerControl *control);
8673
 
+
8674
 
+gboolean                gvc_mixer_control_set_default_sink     (GvcMixerControl *control,
8675
 
+                                                            GvcMixerStream  *stream);
8676
 
+gboolean                gvc_mixer_control_set_default_source   (GvcMixerControl *control,
8677
 
+                                                            GvcMixerStream  *stream);
8678
 
+
8679
 
+gdouble                 gvc_mixer_control_get_vol_max_norm      (GvcMixerControl *control);
8680
 
+gdouble                 gvc_mixer_control_get_vol_max_amplified (GvcMixerControl *control);
8681
 
+void                    gvc_mixer_control_change_output         (GvcMixerControl *control,
8682
 
+                                                                 GvcMixerUIDevice* output);
8683
 
+void                    gvc_mixer_control_change_input          (GvcMixerControl *control,
8684
 
+                                                                 GvcMixerUIDevice* input);
8685
 
+const gchar*            gvc_mixer_control_get_active_profile_from_ui_device (GvcMixerControl* control,
8686
 
+                                                                             GvcMixerUIDevice* device);
8687
 
+GvcMixerStream*         gvc_mixer_control_get_stream_from_device (GvcMixerControl *control,
8688
 
+                                                                  GvcMixerUIDevice *dev);
8689
 
+gboolean                gvc_mixer_control_change_profile_on_selected_device (GvcMixerControl *control,
8690
 
+                                                                             GvcMixerUIDevice *device,
8691
 
+                                                                             const gchar* profile);
8692
 
+
8693
 
+
8694
 
+GvcMixerControlState gvc_mixer_control_get_state            (GvcMixerControl *control);
8695
 
+
8696
 
+
8697
 
+G_END_DECLS
8698
 
+
8699
 
+#endif /* __GVC_MIXER_CONTROL_H */
8700
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-dialog.c
8701
 
===================================================================
8702
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
8703
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-dialog.c      2012-08-28 17:08:49.452516900 +0200
8704
 
@@ -0,0 +1,2203 @@
8705
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
8706
 
+ *
8707
 
+ * Copyright (C) 2008 William Jon McCann
8708
 
+ * Copyright (C) 2012 Conor Curran
8709
 
+ *
8710
 
+ * This program is free software; you can redistribute it and/or modify
8711
 
+ * it under the terms of the GNU General Public License as published by
8712
 
+ * the Free Software Foundation; either version 2 of the License, or
8713
 
+ * (at your option) any later version.
8714
 
+ *
8715
 
+ * This program is distributed in the hope that it will be useful,
8716
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
8717
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8718
 
+ * GNU General Public License for more details.
8719
 
+ *
8720
 
+ * You should have received a copy of the GNU General Public License
8721
 
+ * along with this program; if not, write to the Free Software
8722
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
8723
 
+ *
8724
 
+ */
8725
 
+
8726
 
+#include "config.h"
8727
 
+
8728
 
+#include <stdlib.h>
8729
 
+#include <stdio.h>
8730
 
+#include <unistd.h>
8731
 
+#include <math.h>
8732
 
+
8733
 
+#include <glib.h>
8734
 
+#include <glib/gi18n-lib.h>
8735
 
+#include <gdk/gdkkeysyms.h>
8736
 
+#include <gtk/gtk.h>
8737
 
+#include <pulse/pulseaudio.h>
8738
 
+
8739
 
+
8740
 
+#include "gvc-channel-bar.h"
8741
 
+#include "gvc-balance-bar.h"
8742
 
+#include "gvc-combo-box.h"
8743
 
+#include "gvc-mixer-control.h"
8744
 
+#include "gvc-mixer-card.h"
8745
 
+#include "gvc-mixer-ui-device.h"
8746
 
+#include "gvc-mixer-sink.h"
8747
 
+#include "gvc-mixer-source.h"
8748
 
+#include "gvc-mixer-source-output.h"
8749
 
+#include "gvc-mixer-dialog.h"
8750
 
+#include "gvc-sound-theme-chooser.h"
8751
 
+#include "gvc-level-bar.h"
8752
 
+#include "gvc-speaker-test.h"
8753
 
+#include "gvc-mixer-control-private.h"
8754
 
+
8755
 
+#define SCALE_SIZE 128
8756
 
+
8757
 
+#define GVC_MIXER_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_DIALOG, GvcMixerDialogPrivate))
8758
 
+
8759
 
+struct GvcMixerDialogPrivate
8760
 
+{
8761
 
+        GvcMixerControl *mixer_control;
8762
 
+        GHashTable      *bars;        
8763
 
+        GtkWidget       *notebook;
8764
 
+        GtkWidget       *output_bar;
8765
 
+        GtkWidget       *input_bar;
8766
 
+        GtkWidget       *input_level_bar;
8767
 
+        GtkWidget       *effects_bar;
8768
 
+        GtkWidget       *output_stream_box;
8769
 
+        GtkWidget       *sound_effects_box;
8770
 
+        GtkWidget       *hw_box;
8771
 
+        GtkWidget       *hw_treeview;
8772
 
+        GtkWidget       *hw_settings_box;
8773
 
+        GtkWidget       *hw_profile_combo;
8774
 
+        GtkWidget       *input_box;
8775
 
+        GtkWidget       *output_box;
8776
 
+        GtkWidget       *applications_box;
8777
 
+        GtkWidget       *no_apps_label;
8778
 
+        GtkWidget       *output_treeview;
8779
 
+        GtkWidget       *output_settings_box;
8780
 
+        GtkWidget       *output_balance_bar;
8781
 
+        GtkWidget       *output_fade_bar;
8782
 
+        GtkWidget       *output_lfe_bar;
8783
 
+        GtkWidget       *output_profile_combo;
8784
 
+        GtkWidget       *input_profile_combo;
8785
 
+        GtkWidget       *input_treeview;
8786
 
+        GtkWidget       *input_settings_box;
8787
 
+        GtkWidget       *sound_theme_chooser;
8788
 
+        GtkWidget       *click_feedback_button;
8789
 
+        GtkWidget       *audible_bell_button;
8790
 
+        GtkSizeGroup    *size_group;
8791
 
+        GtkWidget       *selected_output_label;
8792
 
+        GtkWidget       *selected_input_label;
8793
 
+        GtkWidget       *test_output_button;
8794
 
+        GSettings       *indicator_settings;
8795
 
+
8796
 
+        gdouble          last_input_peak;
8797
 
+        guint            num_apps;
8798
 
+};
8799
 
+
8800
 
+enum {
8801
 
+        NAME_COLUMN,
8802
 
+        DEVICE_COLUMN,
8803
 
+        ACTIVE_COLUMN,
8804
 
+        ID_COLUMN,
8805
 
+        SPEAKERS_COLUMN,
8806
 
+        ICON_COLUMN,
8807
 
+        NUM_COLUMNS
8808
 
+};
8809
 
+
8810
 
+enum {
8811
 
+        HW_ID_COLUMN,
8812
 
+        HW_ICON_COLUMN,
8813
 
+        HW_NAME_COLUMN,
8814
 
+        HW_STATUS_COLUMN,
8815
 
+        HW_PROFILE_COLUMN,
8816
 
+        HW_PROFILE_HUMAN_COLUMN,
8817
 
+        HW_SENSITIVE_COLUMN,
8818
 
+        HW_NUM_COLUMNS
8819
 
+};
8820
 
+
8821
 
+enum
8822
 
+{
8823
 
+        PROP_0,
8824
 
+        PROP_MIXER_CONTROL
8825
 
+};
8826
 
+
8827
 
+static void     gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass);
8828
 
+static void     gvc_mixer_dialog_init       (GvcMixerDialog      *mixer_dialog);
8829
 
+static void     gvc_mixer_dialog_finalize   (GObject             *object);
8830
 
+
8831
 
+static void     bar_set_stream              (GvcMixerDialog      *dialog,
8832
 
+                                             GtkWidget           *bar,
8833
 
+                                             GvcMixerStream      *stream);
8834
 
+
8835
 
+static void     on_adjustment_value_changed (GtkAdjustment  *adjustment,
8836
 
+                                             GvcMixerDialog *dialog);
8837
 
+static void    on_control_output_added (GvcMixerControl *control,
8838
 
+                                       guint            id,
8839
 
+                                       GvcMixerDialog  *dialog);
8840
 
+static void   on_control_active_output_update (GvcMixerControl *control,
8841
 
+                                               guint            id,
8842
 
+                                               GvcMixerDialog  *dialog);
8843
 
+                                       
8844
 
+static void   on_control_active_input_update (GvcMixerControl *control,
8845
 
+                                              guint            id,
8846
 
+                                              GvcMixerDialog  *dialog);
8847
 
+
8848
 
+G_DEFINE_TYPE (GvcMixerDialog, gvc_mixer_dialog, GTK_TYPE_VBOX)
8849
 
+
8850
 
+
8851
 
+static void
8852
 
+update_description (GvcMixerDialog *dialog,
8853
 
+                    guint column,
8854
 
+                    const char *value,
8855
 
+                    GvcMixerStream *stream)
8856
 
+{
8857
 
+        GtkTreeModel *model;
8858
 
+        GtkTreeIter   iter;
8859
 
+        guint         id;
8860
 
+
8861
 
+        if (GVC_IS_MIXER_SOURCE (stream))
8862
 
+                model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
8863
 
+        else if (GVC_IS_MIXER_SINK (stream))
8864
 
+                model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
8865
 
+        else
8866
 
+                g_assert_not_reached ();
8867
 
+
8868
 
+        if (gtk_tree_model_get_iter_first (model, &iter) == FALSE){
8869
 
+                g_warning ("The tree is empty => Cannot update the description");
8870
 
+                return;        
8871
 
+        }
8872
 
+
8873
 
+        id = gvc_mixer_stream_get_id (stream);
8874
 
+        do {
8875
 
+                guint       current_id;
8876
 
+
8877
 
+                gtk_tree_model_get (model, &iter,
8878
 
+                                    ID_COLUMN, &current_id,
8879
 
+                                    -1);
8880
 
+                if (id != current_id)
8881
 
+                        continue;
8882
 
+
8883
 
+                gtk_list_store_set (GTK_LIST_STORE (model),
8884
 
+                                    &iter,
8885
 
+                                    column, value,
8886
 
+                                    -1);
8887
 
+                break;
8888
 
+        } while (gtk_tree_model_iter_next (model, &iter));
8889
 
+}
8890
 
+
8891
 
+static void
8892
 
+profile_selection_changed (GvcComboBox *combo_box,
8893
 
+                           const char  *profile,
8894
 
+                           GvcMixerDialog *dialog)
8895
 
+{      
8896
 
+        g_debug ("profile_selection_changed - %s", profile);
8897
 
+        GvcMixerUIDevice *out;
8898
 
+        out = g_object_get_data (G_OBJECT (combo_box), "uidevice");
8899
 
+        
8900
 
+        if (out == NULL) {
8901
 
+                g_warning ("Could not find Output for profile combo box");
8902
 
+                return;
8903
 
+        }
8904
 
+
8905
 
+        g_debug (" \n on profile selection changed on output with \n description %s \n origin %s \n id %i \n \n",
8906
 
+                gvc_mixer_ui_device_get_description (out),
8907
 
+                gvc_mixer_ui_device_get_origin (out),
8908
 
+                gvc_mixer_ui_device_get_id (out));
8909
 
+
8910
 
+        if (gvc_mixer_control_change_profile_on_selected_device (dialog->priv->mixer_control, out, profile) == FALSE) {
8911
 
+                g_warning ("Could not change profile on device %s",
8912
 
+                           gvc_mixer_ui_device_get_description (out));
8913
 
+        }
8914
 
+}
8915
 
+
8916
 
+#define DECAY_STEP .15
8917
 
+
8918
 
+static void
8919
 
+update_input_peak (GvcMixerDialog *dialog,
8920
 
+                   gdouble         v)
8921
 
+{
8922
 
+        GtkAdjustment *adj;
8923
 
+
8924
 
+        if (dialog->priv->last_input_peak >= DECAY_STEP) {
8925
 
+                if (v < dialog->priv->last_input_peak - DECAY_STEP) {
8926
 
+                        v = dialog->priv->last_input_peak - DECAY_STEP;
8927
 
+                }
8928
 
+        }
8929
 
+
8930
 
+        dialog->priv->last_input_peak = v;
8931
 
+
8932
 
+        adj = gvc_level_bar_get_peak_adjustment (GVC_LEVEL_BAR (dialog->priv->input_level_bar));
8933
 
+        if (v >= 0) {
8934
 
+                gtk_adjustment_set_value (adj, v);
8935
 
+        } else {
8936
 
+                gtk_adjustment_set_value (adj, 0.0);
8937
 
+        }
8938
 
+}
8939
 
+
8940
 
+static void
8941
 
+update_input_meter (GvcMixerDialog *dialog,
8942
 
+                    uint32_t        source_index,
8943
 
+                    uint32_t        sink_input_idx,
8944
 
+                    double          v)
8945
 
+{
8946
 
+        update_input_peak (dialog, v);
8947
 
+}
8948
 
+
8949
 
+static void
8950
 
+on_monitor_suspended_callback (pa_stream *s,
8951
 
+                               void      *userdata)
8952
 
+{
8953
 
+        GvcMixerDialog *dialog;
8954
 
+
8955
 
+        dialog = userdata;
8956
 
+
8957
 
+        if (pa_stream_is_suspended (s)) {
8958
 
+                g_debug ("Stream suspended");
8959
 
+                update_input_meter (dialog,
8960
 
+                                    pa_stream_get_device_index (s),
8961
 
+                                    PA_INVALID_INDEX,
8962
 
+                                    -1);
8963
 
+        }
8964
 
+}
8965
 
+
8966
 
+static void
8967
 
+on_monitor_read_callback (pa_stream *s,
8968
 
+                          size_t     length,
8969
 
+                          void      *userdata)
8970
 
+{
8971
 
+        GvcMixerDialog *dialog;
8972
 
+        const void     *data;
8973
 
+        double          v;
8974
 
+
8975
 
+        dialog = userdata;
8976
 
+
8977
 
+        if (pa_stream_peek (s, &data, &length) < 0) {
8978
 
+                g_warning ("Failed to read data from stream");
8979
 
+                return;
8980
 
+        }
8981
 
+
8982
 
+        assert (length > 0);
8983
 
+        assert (length % sizeof (float) == 0);
8984
 
+
8985
 
+        v = ((const float *) data)[length / sizeof (float) -1];
8986
 
+
8987
 
+        pa_stream_drop (s);
8988
 
+
8989
 
+        if (v < 0) {
8990
 
+                v = 0;
8991
 
+        }
8992
 
+        if (v > 1) {
8993
 
+                v = 1;
8994
 
+        }
8995
 
+
8996
 
+        update_input_meter (dialog,
8997
 
+                            pa_stream_get_device_index (s),
8998
 
+                            pa_stream_get_monitor_stream (s),
8999
 
+                            v);
9000
 
+}
9001
 
+
9002
 
+static void
9003
 
+create_monitor_stream_for_source (GvcMixerDialog *dialog,
9004
 
+                                  GvcMixerStream *stream)
9005
 
+{
9006
 
+        pa_stream     *s;
9007
 
+        char           t[16];
9008
 
+        pa_buffer_attr attr;
9009
 
+        pa_sample_spec ss;
9010
 
+        pa_context    *context;
9011
 
+        int            res;
9012
 
+        pa_proplist   *proplist;
9013
 
+        gboolean       has_monitor;
9014
 
+
9015
 
+        if (stream == NULL) {
9016
 
+                g_debug ("\n create_monitor_stream_for_source - stream is null - returning\n");
9017
 
+                return;
9018
 
+        }
9019
 
+        has_monitor = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (stream), "has-monitor"));
9020
 
+        if (has_monitor != FALSE) {
9021
 
+                g_debug ("\n create_monitor_stream_for_source, has monitor is not false - returning \n");
9022
 
+                return;
9023
 
+        }
9024
 
+
9025
 
+        g_debug ("Create monitor for %u",
9026
 
+                 gvc_mixer_stream_get_index (stream));
9027
 
+
9028
 
+        context = gvc_mixer_control_get_pa_context (dialog->priv->mixer_control);
9029
 
+
9030
 
+        if (pa_context_get_server_protocol_version (context) < 13) {
9031
 
+                g_debug ("\n create_monitor_stream_for_source - protocol version is less 13 \n");
9032
 
+                return;
9033
 
+        }
9034
 
+
9035
 
+        ss.channels = 1;
9036
 
+        ss.format = PA_SAMPLE_FLOAT32;
9037
 
+        ss.rate = 25;
9038
 
+
9039
 
+        memset (&attr, 0, sizeof (attr));
9040
 
+        attr.fragsize = sizeof (float);
9041
 
+        attr.maxlength = (uint32_t) -1;
9042
 
+
9043
 
+        snprintf (t, sizeof (t), "%u", gvc_mixer_stream_get_index (stream));
9044
 
+
9045
 
+        proplist = pa_proplist_new ();
9046
 
+        pa_proplist_sets (proplist, PA_PROP_APPLICATION_ID, "org.gnome.VolumeControl");
9047
 
+        s = pa_stream_new_with_proplist (context, _("Peak detect"), &ss, NULL, proplist);
9048
 
+        pa_proplist_free (proplist);
9049
 
+        if (s == NULL) {
9050
 
+                g_warning ("Failed to create monitoring stream");
9051
 
+                return;
9052
 
+        }
9053
 
+
9054
 
+        pa_stream_set_read_callback (s, on_monitor_read_callback, dialog);
9055
 
+        pa_stream_set_suspended_callback (s, on_monitor_suspended_callback, dialog);
9056
 
+
9057
 
+        res = pa_stream_connect_record (s,
9058
 
+                                        t,
9059
 
+                                        &attr,
9060
 
+                                        (pa_stream_flags_t) (PA_STREAM_DONT_MOVE
9061
 
+                                                             |PA_STREAM_PEAK_DETECT
9062
 
+                                                             |PA_STREAM_ADJUST_LATENCY));
9063
 
+        if (res < 0) {
9064
 
+                g_warning ("Failed to connect monitoring stream");
9065
 
+                pa_stream_unref (s);
9066
 
+        } else {
9067
 
+                g_object_set_data (G_OBJECT (stream), "has-monitor", GINT_TO_POINTER (TRUE));
9068
 
+                g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream", s);
9069
 
+                g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "stream", stream);
9070
 
+        }
9071
 
+}
9072
 
+
9073
 
+
9074
 
+static void
9075
 
+stop_monitor_stream_for_source (GvcMixerDialog *dialog)
9076
 
+{
9077
 
+        pa_stream      *s;
9078
 
+        pa_context     *context;
9079
 
+        int             res;
9080
 
+        GvcMixerStream *stream;
9081
 
+
9082
 
+        stream = g_object_get_data (G_OBJECT (dialog->priv->input_level_bar), "stream");
9083
 
+
9084
 
+        if (stream == NULL){
9085
 
+                g_debug ("\n stop_monitor_stream_for_source - gvcstream is null - returning \n");                
9086
 
+                return;
9087
 
+        }
9088
 
+        else{
9089
 
+                g_debug ("\n stop_monitor_stream_for_source - gvcstream is not null - continue \n");                                
9090
 
+        }
9091
 
+
9092
 
+        s = g_object_get_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream");
9093
 
+
9094
 
+        if (s != NULL){
9095
 
+                res = pa_stream_disconnect (s);
9096
 
+                if (res == 0) {
9097
 
+                        g_debug("stream has been disconnected");
9098
 
+                        pa_stream_unref (s);
9099
 
+                }
9100
 
+                g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream", NULL);        
9101
 
+        }
9102
 
+                
9103
 
+        context = gvc_mixer_control_get_pa_context (dialog->priv->mixer_control);
9104
 
+
9105
 
+        if (pa_context_get_server_protocol_version (context) < 13) {
9106
 
+                return;
9107
 
+        }
9108
 
+        if (res == 0) {
9109
 
+                g_object_set_data (G_OBJECT (stream), "has-monitor", GINT_TO_POINTER (FALSE));
9110
 
+        }
9111
 
+        g_debug ("Stopping monitor for %u", pa_stream_get_index (s));
9112
 
+        g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "stream", NULL);
9113
 
+}
9114
 
+
9115
 
+static void
9116
 
+gvc_mixer_dialog_set_mixer_control (GvcMixerDialog  *dialog,
9117
 
+                                    GvcMixerControl *control)
9118
 
+{
9119
 
+        g_return_if_fail (GVC_MIXER_DIALOG (dialog));
9120
 
+        g_return_if_fail (GVC_IS_MIXER_CONTROL (control));
9121
 
+
9122
 
+        g_object_ref (control);
9123
 
+
9124
 
+        if (dialog->priv->mixer_control != NULL) {
9125
 
+                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
9126
 
+                                                      G_CALLBACK (on_control_active_output_update),
9127
 
+                                                      dialog);
9128
 
+                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
9129
 
+                                                      G_CALLBACK (on_control_active_input_update),
9130
 
+                                                      dialog);
9131
 
+                g_object_unref (dialog->priv->mixer_control);
9132
 
+        }
9133
 
+
9134
 
+        dialog->priv->mixer_control = control;
9135
 
+
9136
 
+        g_signal_connect (dialog->priv->mixer_control,
9137
 
+                          "active-output-update",
9138
 
+                          G_CALLBACK (on_control_active_output_update),
9139
 
+                          dialog);
9140
 
+        g_signal_connect (dialog->priv->mixer_control,
9141
 
+                          "active-input-update",
9142
 
+                          G_CALLBACK (on_control_active_input_update),
9143
 
+                          dialog);
9144
 
+
9145
 
+        g_object_notify (G_OBJECT (dialog), "mixer-control");
9146
 
+}
9147
 
+
9148
 
+static GvcMixerControl *
9149
 
+gvc_mixer_dialog_get_mixer_control (GvcMixerDialog *dialog)
9150
 
+{
9151
 
+        g_return_val_if_fail (GVC_IS_MIXER_DIALOG (dialog), NULL);
9152
 
+
9153
 
+        return dialog->priv->mixer_control;
9154
 
+}
9155
 
+
9156
 
+static void
9157
 
+gvc_mixer_dialog_set_property (GObject       *object,
9158
 
+                               guint          prop_id,
9159
 
+                               const GValue  *value,
9160
 
+                               GParamSpec    *pspec)
9161
 
+{
9162
 
+        GvcMixerDialog *self = GVC_MIXER_DIALOG (object);
9163
 
+
9164
 
+        switch (prop_id) {
9165
 
+        case PROP_MIXER_CONTROL:
9166
 
+                gvc_mixer_dialog_set_mixer_control (self, g_value_get_object (value));
9167
 
+                break;
9168
 
+        default:
9169
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
9170
 
+                break;
9171
 
+        }
9172
 
+}
9173
 
+
9174
 
+static void
9175
 
+gvc_mixer_dialog_get_property (GObject     *object,
9176
 
+                               guint        prop_id,
9177
 
+                               GValue      *value,
9178
 
+                               GParamSpec  *pspec)
9179
 
+{
9180
 
+        GvcMixerDialog *self = GVC_MIXER_DIALOG (object);
9181
 
+
9182
 
+        switch (prop_id) {
9183
 
+        case PROP_MIXER_CONTROL:
9184
 
+                g_value_set_object (value, gvc_mixer_dialog_get_mixer_control (self));
9185
 
+                break;
9186
 
+        default:
9187
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
9188
 
+                break;
9189
 
+        }
9190
 
+}
9191
 
+
9192
 
+static void
9193
 
+on_adjustment_value_changed (GtkAdjustment  *adjustment,
9194
 
+                             GvcMixerDialog *dialog)
9195
 
+{
9196
 
+        GvcMixerStream *stream;
9197
 
+
9198
 
+        stream = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-stream");
9199
 
+        if (stream != NULL) {
9200
 
+                GObject *bar;
9201
 
+                gdouble volume, rounded;
9202
 
+                char *name;
9203
 
+
9204
 
+                volume = gtk_adjustment_get_value (adjustment);
9205
 
+                rounded = round (volume);
9206
 
+
9207
 
+                bar = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-bar");
9208
 
+                g_object_get (bar, "name", &name, NULL);
9209
 
+                g_debug ("Setting stream volume %lf (rounded: %lf) for bar '%s'", volume, rounded, name);
9210
 
+                g_free (name);
9211
 
+
9212
 
+                /* FIXME would need to do that in the balance bar really... */
9213
 
+                /* Make sure we do not unmute muted streams, there's a button for that */
9214
 
+                if (volume == 0.0)
9215
 
+                        gvc_mixer_stream_set_is_muted (stream, TRUE);
9216
 
+                /* Only push the volume if it's actually changed */
9217
 
+                if (gvc_mixer_stream_set_volume(stream, (pa_volume_t) rounded) != FALSE)
9218
 
+                        gvc_mixer_stream_push_volume (stream);
9219
 
+        }
9220
 
+}
9221
 
+
9222
 
+static void
9223
 
+on_bar_is_muted_notify (GObject        *object,
9224
 
+                        GParamSpec     *pspec,
9225
 
+                        GvcMixerDialog *dialog)
9226
 
+{
9227
 
+        gboolean        is_muted;
9228
 
+        GvcMixerStream *stream;
9229
 
+
9230
 
+        is_muted = gvc_channel_bar_get_is_muted (GVC_CHANNEL_BAR (object));
9231
 
+
9232
 
+        stream = g_object_get_data (object, "gvc-mixer-dialog-stream");
9233
 
+        if (stream != NULL) {
9234
 
+                gvc_mixer_stream_change_is_muted (stream, is_muted);
9235
 
+        } else {
9236
 
+                char *name;
9237
 
+                g_object_get (object, "name", &name, NULL);
9238
 
+                g_warning ("Unable to find stream for bar '%s'", name);
9239
 
+                g_free (name);
9240
 
+        }
9241
 
+}
9242
 
+
9243
 
+static GtkWidget *
9244
 
+lookup_bar_for_stream (GvcMixerDialog *dialog,
9245
 
+                       GvcMixerStream *stream)
9246
 
+{
9247
 
+        GtkWidget *bar;
9248
 
+
9249
 
+        bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)));
9250
 
+
9251
 
+        return bar;
9252
 
+}
9253
 
+
9254
 
+// TODO
9255
 
+// Do we need this ?
9256
 
+// UI devices now pull description material mainly for the card ports.
9257
 
+// Therefore the need for stream description dynamic changes more than ever seems unneccessary. 
9258
 
+static void
9259
 
+on_stream_description_notify (GvcMixerStream *stream,
9260
 
+                              GParamSpec     *pspec,
9261
 
+                              GvcMixerDialog *dialog)
9262
 
+{
9263
 
+        update_description (dialog, NAME_COLUMN,
9264
 
+                            gvc_mixer_stream_get_description (stream),
9265
 
+                            stream);
9266
 
+}
9267
 
+
9268
 
+static void
9269
 
+on_stream_volume_notify (GObject        *object,
9270
 
+                         GParamSpec     *pspec,
9271
 
+                         GvcMixerDialog *dialog)
9272
 
+{
9273
 
+        GvcMixerStream *stream;
9274
 
+        GtkWidget      *bar;
9275
 
+        GtkAdjustment  *adj;
9276
 
+        stream = GVC_MIXER_STREAM (object);
9277
 
+
9278
 
+        bar = lookup_bar_for_stream (dialog, stream);
9279
 
+
9280
 
+        if (bar == NULL) {
9281
 
+                if (stream == gvc_mixer_control_get_default_sink(dialog->priv->mixer_control)) {
9282
 
+                        bar = dialog->priv->output_bar;
9283
 
+                }
9284
 
+                else if(stream == gvc_mixer_control_get_default_source(dialog->priv->mixer_control)) {
9285
 
+                        bar = dialog->priv->input_bar;
9286
 
+                }
9287
 
+                else{
9288
 
+                        g_warning ("Unable to find bar for stream %s in on_stream_volume_notify()",
9289
 
+                                   gvc_mixer_stream_get_name (stream));
9290
 
+                        return;
9291
 
+                }
9292
 
+        }
9293
 
+
9294
 
+        adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
9295
 
+
9296
 
+        g_signal_handlers_block_by_func (adj,
9297
 
+                                         on_adjustment_value_changed,
9298
 
+                                         dialog);
9299
 
+
9300
 
+        gtk_adjustment_set_value (adj,
9301
 
+                                  gvc_mixer_stream_get_volume (stream));
9302
 
+
9303
 
+        g_signal_handlers_unblock_by_func (adj,
9304
 
+                                           on_adjustment_value_changed,
9305
 
+                                           dialog);
9306
 
+}
9307
 
+
9308
 
+static void
9309
 
+on_stream_is_muted_notify (GObject        *object,
9310
 
+                           GParamSpec     *pspec,
9311
 
+                           GvcMixerDialog *dialog)
9312
 
+{
9313
 
+        GvcMixerStream *stream;
9314
 
+        GtkWidget      *bar;
9315
 
+        gboolean        is_muted;
9316
 
+
9317
 
+        stream = GVC_MIXER_STREAM (object);
9318
 
+
9319
 
+        bar = lookup_bar_for_stream (dialog, stream);
9320
 
+
9321
 
+        if (bar == NULL) {
9322
 
+                if (stream == gvc_mixer_control_get_default_sink(dialog->priv->mixer_control)) {
9323
 
+                        bar = dialog->priv->output_bar;
9324
 
+                }
9325
 
+                else if(stream == gvc_mixer_control_get_default_source(dialog->priv->mixer_control)) {
9326
 
+                        bar = dialog->priv->input_bar;
9327
 
+                }                
9328
 
+                else{
9329
 
+                        g_warning ("Unable to find bar for stream %s in on_stream_muted_notify()",
9330
 
+                                   gvc_mixer_stream_get_name (stream));
9331
 
+                        return;
9332
 
+                }
9333
 
+        }
9334
 
+
9335
 
+
9336
 
+        is_muted = gvc_mixer_stream_get_is_muted (stream);
9337
 
+        gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar),
9338
 
+                                      is_muted);
9339
 
+
9340
 
+        if (stream == gvc_mixer_control_get_default_sink (dialog->priv->mixer_control)) {
9341
 
+                gtk_widget_set_sensitive (dialog->priv->applications_box,
9342
 
+                                          !is_muted);
9343
 
+        }
9344
 
+
9345
 
+}
9346
 
+
9347
 
+static void
9348
 
+save_bar_for_stream (GvcMixerDialog *dialog,
9349
 
+                     GvcMixerStream *stream,
9350
 
+                     GtkWidget      *bar)
9351
 
+{
9352
 
+        g_debug ("\n saving bar for stream %s",
9353
 
+                 gvc_mixer_stream_get_name (stream));
9354
 
+        g_hash_table_insert (dialog->priv->bars,
9355
 
+                             GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)),
9356
 
+                             bar);
9357
 
+}
9358
 
+
9359
 
+static GtkWidget *
9360
 
+create_bar (GvcMixerDialog *dialog,
9361
 
+            gboolean        add_to_size_group,
9362
 
+            gboolean        symmetric)
9363
 
+{
9364
 
+        GtkWidget *bar;
9365
 
+
9366
 
+        bar = gvc_channel_bar_new ();
9367
 
+        gtk_widget_set_sensitive (bar, FALSE);
9368
 
+        if (add_to_size_group && dialog->priv->size_group != NULL) {
9369
 
+                gvc_channel_bar_set_size_group (GVC_CHANNEL_BAR (bar),
9370
 
+                                                dialog->priv->size_group,
9371
 
+                                                symmetric);
9372
 
+        }
9373
 
+        gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (bar),
9374
 
+                                         GTK_ORIENTATION_HORIZONTAL);
9375
 
+        gvc_channel_bar_set_show_mute (GVC_CHANNEL_BAR (bar),
9376
 
+                                       TRUE);
9377
 
+        g_signal_connect (bar,
9378
 
+                          "notify::is-muted",
9379
 
+                          G_CALLBACK (on_bar_is_muted_notify),
9380
 
+                          dialog);
9381
 
+        return bar;
9382
 
+}
9383
 
+
9384
 
+static GtkWidget *
9385
 
+create_app_bar (GvcMixerDialog *dialog,
9386
 
+                const char     *name,
9387
 
+                const char     *icon_name)
9388
 
+{
9389
 
+        GtkWidget *bar;
9390
 
+
9391
 
+        bar = create_bar (dialog, FALSE, FALSE);
9392
 
+        gvc_channel_bar_set_ellipsize (GVC_CHANNEL_BAR (bar), TRUE);
9393
 
+        gvc_channel_bar_set_icon_name (GVC_CHANNEL_BAR (bar), icon_name);
9394
 
+        if (name == NULL || strchr (name, '_') == NULL) {
9395
 
+                gvc_channel_bar_set_name (GVC_CHANNEL_BAR (bar), name);
9396
 
+        } else {
9397
 
+                char **tokens, *escaped;
9398
 
+
9399
 
+                tokens = g_strsplit (name, "_", -1);
9400
 
+                escaped = g_strjoinv ("__", tokens);
9401
 
+                g_strfreev (tokens);
9402
 
+                gvc_channel_bar_set_name (GVC_CHANNEL_BAR (bar), escaped);
9403
 
+                g_free (escaped);
9404
 
+        }
9405
 
+
9406
 
+        return bar;
9407
 
+}
9408
 
+
9409
 
+static gint test_it = 0;
9410
 
+
9411
 
+/* active_input_update
9412
 
+ * Handle input update change from the backend (control). 
9413
 
+ * Trust the backend whole-heartedly to deliver the correct input
9414
 
+ * i.e. keep it MVC.
9415
 
+ */
9416
 
+static void
9417
 
+active_input_update (GvcMixerDialog *dialog,
9418
 
+                     GvcMixerUIDevice *active_input)
9419
 
+{         
9420
 
+        g_debug ("\n active_input_update %s \n", gvc_mixer_ui_device_get_description (active_input));
9421
 
+        // First make sure the correct UI device is selected.
9422
 
+        GtkTreeModel *model;
9423
 
+        GtkTreeIter   iter;
9424
 
+
9425
 
+        model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
9426
 
+
9427
 
+        if (gtk_tree_model_get_iter_first (model, &iter) == FALSE){
9428
 
+                g_warning ("The tree is empty => we have no devices so cannot set the active input");
9429
 
+                return;        
9430
 
+        }
9431
 
+        
9432
 
+        do {
9433
 
+                gboolean         is_selected = FALSE;
9434
 
+                gint             id;
9435
 
+                        
9436
 
+                gtk_tree_model_get (model, &iter,
9437
 
+                                    ID_COLUMN, &id,
9438
 
+                                    -1);
9439
 
+
9440
 
+                is_selected = id == gvc_mixer_ui_device_get_id (active_input);
9441
 
+                
9442
 
+                gtk_list_store_set (GTK_LIST_STORE (model),
9443
 
+                                    &iter,
9444
 
+                                    ACTIVE_COLUMN, is_selected,
9445
 
+                                    -1);
9446
 
+
9447
 
+                if (is_selected) {
9448
 
+                        GtkTreeSelection *selection;
9449
 
+                        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->input_treeview));
9450
 
+                        gtk_tree_selection_select_iter (selection, &iter);
9451
 
+                }
9452
 
+                
9453
 
+        }while (gtk_tree_model_iter_next (model, &iter));
9454
 
+
9455
 
+
9456
 
+          // Not ideal but for now destroy the combo and recreate below.
9457
 
+        if (dialog->priv->input_profile_combo != NULL) {
9458
 
+                gtk_container_remove (GTK_CONTAINER (dialog->priv->input_settings_box),
9459
 
+                                      dialog->priv->input_profile_combo);
9460
 
+                dialog->priv->input_profile_combo = NULL;
9461
 
+        }
9462
 
+
9463
 
+        GvcMixerStream       *stream;  
9464
 
+        const GvcChannelMap  *map;
9465
 
+        GtkAdjustment        *adj;
9466
 
+  
9467
 
+        stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control, 
9468
 
+                                                           active_input); 
9469
 
+        if (stream == NULL) {
9470
 
+                g_warning ("active_input_update - couldn't find a stream from the supposed active input");
9471
 
+                gtk_widget_set_sensitive (dialog->priv->input_bar, 
9472
 
+                                          FALSE);                
9473
 
+                return;
9474
 
+        }
9475
 
+
9476
 
+        // Set the label accordingly
9477
 
+        adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->input_bar)));
9478
 
+        g_signal_handlers_disconnect_by_func(adj, on_adjustment_value_changed, dialog);
9479
 
+
9480
 
+        gtk_label_set_label (GTK_LABEL(dialog->priv->selected_input_label),
9481
 
+                             g_strdup_printf(_("Settings for %s"),
9482
 
+                                             gvc_mixer_ui_device_get_description (active_input)));  
9483
 
+
9484
 
+        gvc_channel_bar_set_base_volume (GVC_CHANNEL_BAR (dialog->priv->input_bar),
9485
 
+                                         gvc_mixer_stream_get_base_volume (stream));
9486
 
+        gvc_channel_bar_set_is_amplified (GVC_CHANNEL_BAR (dialog->priv->input_bar),
9487
 
+                                          gvc_mixer_stream_get_can_decibel (stream));
9488
 
+        /* Update the adjustment in case the previous bar wasn't decibel
9489
 
+         * capable, and we clipped it */
9490
 
+        adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->input_bar)));
9491
 
+        gtk_adjustment_set_value (adj,
9492
 
+                                  gvc_mixer_stream_get_volume (stream));        
9493
 
+        
9494
 
+        stop_monitor_stream_for_source (dialog);
9495
 
+        //if (test_it < 6){
9496
 
+        create_monitor_stream_for_source (dialog, stream);
9497
 
+        test_it += 1;
9498
 
+        //}
9499
 
+        bar_set_stream (dialog, dialog->priv->input_bar, stream);   
9500
 
+        // remove any previous stream that might have been pointed at 
9501
 
+        // the static input bar and connect new signals from new stream.
9502
 
+
9503
 
+        const GHashTable *profs_entries;
9504
 
+        profs_entries = gvc_mixer_ui_device_get_profiles (active_input);
9505
 
+
9506
 
+        const GList* profiles = NULL;
9507
 
+        profiles = g_hash_table_get_values (profs_entries);
9508
 
+
9509
 
+        if (profiles != NULL && !gvc_mixer_ui_device_should_profiles_be_hidden (active_input)){
9510
 
+                const gchar *active_profile;
9511
 
+                dialog->priv->input_profile_combo = gvc_combo_box_new (_("Mode:"));                
9512
 
+                gvc_combo_box_set_profiles (GVC_COMBO_BOX (dialog->priv->input_profile_combo),
9513
 
+                                            profs_entries);
9514
 
+                                
9515
 
+                active_profile = gvc_mixer_control_get_active_profile_from_ui_device (dialog->priv->mixer_control,
9516
 
+                                                                                       active_input);
9517
 
+                if (active_profile)
9518
 
+                        gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->input_profile_combo), active_profile);
9519
 
+
9520
 
+                g_object_set_data (G_OBJECT (dialog->priv->input_profile_combo),
9521
 
+                                   "uidevice",
9522
 
+                                   active_input);
9523
 
+
9524
 
+                g_signal_connect (G_OBJECT (dialog->priv->input_profile_combo), "changed",
9525
 
+                                  G_CALLBACK (profile_selection_changed), dialog);
9526
 
+
9527
 
+                gtk_box_pack_start (GTK_BOX (dialog->priv->input_settings_box),
9528
 
+                                    dialog->priv->input_profile_combo,
9529
 
+                                    TRUE, FALSE, 0);
9530
 
+
9531
 
+                if (dialog->priv->size_group != NULL) {
9532
 
+                        gvc_combo_box_set_size_group (GVC_COMBO_BOX (dialog->priv->input_profile_combo),
9533
 
+                                                      dialog->priv->size_group, FALSE);
9534
 
+                }
9535
 
+                gtk_widget_show (dialog->priv->input_profile_combo);                
9536
 
+        }
9537
 
+}
9538
 
+
9539
 
+/* active_output_update
9540
 
+ * Handle output update change from the backend (control). 
9541
 
+ * Trust the backend whole heartedly to deliver the correct output
9542
 
+ * i.e. keep it MVC.
9543
 
+ */
9544
 
+static void
9545
 
+active_output_update (GvcMixerDialog *dialog,
9546
 
+                      GvcMixerUIDevice *active_output)
9547
 
+{                 
9548
 
+        // First make sure the correct UI device is selected.
9549
 
+        GtkTreeModel *model;
9550
 
+        GtkTreeIter   iter;
9551
 
+        g_debug ("\n\n active output update - device id = %i \n\n",
9552
 
+                 gvc_mixer_ui_device_get_id (active_output));
9553
 
+
9554
 
+        model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
9555
 
+
9556
 
+        if (gtk_tree_model_get_iter_first (model, &iter) == FALSE){
9557
 
+                g_warning ("The tree is empty => we have no devices in the tree => cannot set the active output");
9558
 
+                return;        
9559
 
+        }
9560
 
+        
9561
 
+        do {
9562
 
+                gboolean         is_selected;
9563
 
+                gint             id;
9564
 
+                        
9565
 
+                gtk_tree_model_get (model, &iter,
9566
 
+                                    ID_COLUMN, &id,
9567
 
+                                    ACTIVE_COLUMN, &is_selected,                  
9568
 
+                                    -1);
9569
 
+
9570
 
+                if (is_selected && id == gvc_mixer_ui_device_get_id (active_output)) {
9571
 
+                        g_debug ("\n\n unneccessary active output update unless it was a profile change on the same device ? \n\n");
9572
 
+                }
9573
 
+
9574
 
+                is_selected = id == gvc_mixer_ui_device_get_id (active_output);
9575
 
+                
9576
 
+                gtk_list_store_set (GTK_LIST_STORE (model),
9577
 
+                                    &iter,
9578
 
+                                    ACTIVE_COLUMN, is_selected,
9579
 
+                                    -1);
9580
 
+
9581
 
+                if (is_selected) {
9582
 
+                        GtkTreeSelection *selection;
9583
 
+                        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->output_treeview));
9584
 
+                        gtk_tree_selection_select_iter (selection, &iter);
9585
 
+                }
9586
 
+                
9587
 
+        }while (gtk_tree_model_iter_next (model, &iter));
9588
 
+        
9589
 
+          // Not ideal but for now destroy the combo and recreate below.
9590
 
+        if (dialog->priv->output_profile_combo != NULL) {
9591
 
+                gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box),
9592
 
+                                      dialog->priv->output_profile_combo);
9593
 
+                dialog->priv->output_profile_combo = NULL;
9594
 
+        }
9595
 
+
9596
 
+        GvcMixerStream       *stream;  
9597
 
+        const GvcChannelMap  *map;
9598
 
+        GtkAdjustment        *adj;
9599
 
+  
9600
 
+        stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control, 
9601
 
+                                                           active_output); 
9602
 
+
9603
 
+        if (stream == NULL) {
9604
 
+                g_warning ("active_output_update - couldn't find a stream from the supposed active output");
9605
 
+                return;
9606
 
+        }
9607
 
+
9608
 
+        gboolean is_muted = gvc_mixer_stream_get_is_muted (stream);
9609
 
+        gtk_widget_set_sensitive (dialog->priv->applications_box,
9610
 
+                                  !is_muted);
9611
 
+        adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->output_bar)));
9612
 
+        g_signal_handlers_disconnect_by_func(adj, on_adjustment_value_changed, dialog);
9613
 
+
9614
 
+        bar_set_stream (dialog, dialog->priv->output_bar, stream);
9615
 
+        gvc_channel_bar_set_base_volume (GVC_CHANNEL_BAR (dialog->priv->output_bar),
9616
 
+                                         gvc_mixer_stream_get_base_volume (stream));
9617
 
+        gvc_channel_bar_set_is_amplified (GVC_CHANNEL_BAR (dialog->priv->output_bar),
9618
 
+                                          gvc_mixer_stream_get_can_decibel (stream));
9619
 
+        /* Update the adjustment in case the previous bar wasn't decibel
9620
 
+         * capable, and we clipped it */
9621
 
+        adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->output_bar)));
9622
 
+        gtk_adjustment_set_value (adj,
9623
 
+                                  gvc_mixer_stream_get_volume (stream));
9624
 
+
9625
 
+        map = gvc_mixer_stream_get_channel_map (stream);
9626
 
+
9627
 
+        if (map == NULL) {
9628
 
+                g_warning ("Active output stream has no channel map");
9629
 
+                gtk_widget_set_sensitive (dialog->priv->output_bar, FALSE);
9630
 
+                gtk_widget_set_sensitive (dialog->priv->output_balance_bar, FALSE);
9631
 
+                gtk_widget_set_sensitive (dialog->priv->output_lfe_bar, FALSE);
9632
 
+                gtk_widget_set_sensitive (dialog->priv->output_fade_bar, FALSE);                
9633
 
+                return;
9634
 
+        }
9635
 
+
9636
 
+
9637
 
+        // Swap bars to the active map
9638
 
+        gvc_balance_bar_set_map (GVC_BALANCE_BAR (dialog->priv->output_balance_bar), 
9639
 
+                                 map);  
9640
 
+        gvc_balance_bar_set_map (GVC_BALANCE_BAR (dialog->priv->output_fade_bar), 
9641
 
+                                 map);
9642
 
+        gvc_balance_bar_set_map (GVC_BALANCE_BAR (dialog->priv->output_lfe_bar), 
9643
 
+                                 map);
9644
 
+                           
9645
 
+        // Set sensitivities accordingly.
9646
 
+        gtk_widget_set_sensitive (dialog->priv->output_balance_bar,
9647
 
+                                  gvc_channel_map_can_balance (map));                                    
9648
 
+        gtk_widget_set_sensitive (dialog->priv->output_fade_bar, 
9649
 
+                                  gvc_channel_map_can_fade (map));
9650
 
+        gtk_widget_set_sensitive (dialog->priv->output_lfe_bar, 
9651
 
+                                  gvc_channel_map_has_lfe (map));
9652
 
+        gtk_widget_set_sensitive (dialog->priv->output_bar, 
9653
 
+                                  TRUE);
9654
 
+        // Set the label accordingly
9655
 
+       gtk_label_set_label (GTK_LABEL(dialog->priv->selected_output_label),
9656
 
+                            g_strdup_printf(_("Settings for %s"),
9657
 
+                                             gvc_mixer_ui_device_get_description (active_output)));
9658
 
+        g_debug ("\n active_output_update %s \n", gvc_mixer_ui_device_get_description (active_output));
9659
 
+
9660
 
+        const GHashTable *profs_entries;
9661
 
+        profs_entries = gvc_mixer_ui_device_get_profiles (active_output);
9662
 
+
9663
 
+        GList* profiles = NULL;
9664
 
+        profiles = g_hash_table_get_values (profs_entries);
9665
 
+
9666
 
+        if (profiles != NULL && !gvc_mixer_ui_device_should_profiles_be_hidden (active_output)) {
9667
 
+                const gchar *active_profile;
9668
 
+
9669
 
+                dialog->priv->output_profile_combo = gvc_combo_box_new (_("Mode:"));                
9670
 
+                gvc_combo_box_set_profiles (GVC_COMBO_BOX (dialog->priv->output_profile_combo),
9671
 
+                                            profs_entries);
9672
 
+                                
9673
 
+                gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box),
9674
 
+                                    dialog->priv->output_profile_combo,
9675
 
+                                    FALSE, FALSE, 3);
9676
 
+
9677
 
+                if (dialog->priv->size_group != NULL) {
9678
 
+                        gvc_combo_box_set_size_group (GVC_COMBO_BOX (dialog->priv->output_profile_combo),
9679
 
+                                                      dialog->priv->size_group, FALSE);
9680
 
+                }
9681
 
+
9682
 
+                active_profile = gvc_mixer_control_get_active_profile_from_ui_device (dialog->priv->mixer_control,
9683
 
+                                                                                       active_output);
9684
 
+                if (active_profile)
9685
 
+                        gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->output_profile_combo), active_profile);
9686
 
+                                          
9687
 
+                
9688
 
+                g_object_set_data (G_OBJECT (dialog->priv->output_profile_combo),
9689
 
+                                   "uidevice",
9690
 
+                                   active_output);
9691
 
+                g_signal_connect (G_OBJECT (dialog->priv->output_profile_combo), "changed",
9692
 
+                                  G_CALLBACK (profile_selection_changed), dialog);
9693
 
+
9694
 
+                gtk_widget_show (dialog->priv->output_profile_combo);                
9695
 
+        }
9696
 
+
9697
 
+}
9698
 
+
9699
 
+static void
9700
 
+bar_set_stream (GvcMixerDialog *dialog,
9701
 
+                GtkWidget      *bar,
9702
 
+                GvcMixerStream *stream)
9703
 
+{
9704
 
+        GtkAdjustment  *adj;
9705
 
+
9706
 
+        g_assert (bar != NULL);
9707
 
+
9708
 
+        gtk_widget_set_sensitive (bar, (stream != NULL));
9709
 
+
9710
 
+        adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
9711
 
+        
9712
 
+        g_signal_handlers_disconnect_by_func (adj, on_adjustment_value_changed, dialog);
9713
 
+
9714
 
+        g_object_set_data (G_OBJECT (bar), "gvc-mixer-dialog-stream", stream);
9715
 
+        g_object_set_data (G_OBJECT (adj), "gvc-mixer-dialog-stream", stream);
9716
 
+        g_object_set_data (G_OBJECT (adj), "gvc-mixer-dialog-bar", bar);
9717
 
+
9718
 
+        if (stream != NULL) {
9719
 
+                gboolean is_muted;
9720
 
+
9721
 
+                is_muted = gvc_mixer_stream_get_is_muted (stream);
9722
 
+                gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar), is_muted);
9723
 
+
9724
 
+                gtk_adjustment_set_value (adj,
9725
 
+                                          gvc_mixer_stream_get_volume (stream));
9726
 
+                g_signal_connect (stream,
9727
 
+                                  "notify::is-muted",
9728
 
+                                  G_CALLBACK (on_stream_is_muted_notify),
9729
 
+                                  dialog);
9730
 
+                g_signal_connect (stream,
9731
 
+                                  "notify::volume",
9732
 
+                                  G_CALLBACK (on_stream_volume_notify),
9733
 
+                                  dialog);
9734
 
+                g_signal_connect (adj,
9735
 
+                                  "value-changed",
9736
 
+                                  G_CALLBACK (on_adjustment_value_changed),
9737
 
+                                  dialog);
9738
 
+        }
9739
 
+}
9740
 
+
9741
 
+/**
9742
 
+* This method handles all streams that are not an input or output
9743
 
+* i.e. effects streams and application streams
9744
 
+* TODO rename to truly reflect its usage. 
9745
 
+**/
9746
 
+static void
9747
 
+add_stream (GvcMixerDialog *dialog,
9748
 
+            GvcMixerStream *stream)
9749
 
+{
9750
 
+  
9751
 
+        GtkWidget     *bar;
9752
 
+        bar = NULL;
9753
 
+
9754
 
+        if (stream == gvc_mixer_control_get_event_sink_input (dialog->priv->mixer_control)) {
9755
 
+                bar = dialog->priv->effects_bar;
9756
 
+                g_debug ("Adding effects stream");
9757
 
+        } else {
9758
 
+                // Must be a sink/source input/output
9759
 
+                const char *name;
9760
 
+                name = gvc_mixer_stream_get_name (stream);
9761
 
+                g_debug ("\n Add bar for application stream : %s",
9762
 
+                             name);
9763
 
+
9764
 
+                bar = create_app_bar (dialog, name,
9765
 
+                                      gvc_mixer_stream_get_icon_name (stream));
9766
 
+
9767
 
+                gtk_box_pack_start (GTK_BOX (dialog->priv->applications_box), bar, FALSE, FALSE, 12);
9768
 
+                dialog->priv->num_apps++;
9769
 
+                gtk_widget_hide (dialog->priv->no_apps_label);
9770
 
+        }
9771
 
+        // We should have a bar by now.
9772
 
+        g_assert (bar != NULL);
9773
 
+        GvcMixerStream *old_stream;
9774
 
+
9775
 
+        if (bar != NULL) {
9776
 
+                old_stream = g_object_get_data (G_OBJECT (bar), "gvc-mixer-dialog-stream");
9777
 
+                if (old_stream != NULL) {
9778
 
+                        char *name;
9779
 
+                        g_object_get (bar, "name", &name, NULL);
9780
 
+                        g_debug ("Disconnecting old stream '%s' from bar '%s'",
9781
 
+                                 gvc_mixer_stream_get_name (old_stream), name);
9782
 
+                        g_free (name);
9783
 
+
9784
 
+                        g_signal_handlers_disconnect_by_func (old_stream, on_stream_is_muted_notify, dialog);
9785
 
+                        g_signal_handlers_disconnect_by_func (old_stream, on_stream_volume_notify, dialog);
9786
 
+                        g_print ("\n in add stream \n");
9787
 
+                        g_hash_table_remove (dialog->priv->bars, GUINT_TO_POINTER (gvc_mixer_stream_get_id (old_stream)));
9788
 
+                }
9789
 
+                save_bar_for_stream (dialog, stream, bar);
9790
 
+                bar_set_stream (dialog, bar, stream);
9791
 
+                gtk_widget_show (bar);
9792
 
+        }
9793
 
+}
9794
 
+
9795
 
+static void
9796
 
+remove_stream (GvcMixerDialog  *dialog,
9797
 
+               guint            id)
9798
 
+{        
9799
 
+        GtkWidget *bar;
9800
 
+        bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (id));
9801
 
+        if (bar != NULL) {
9802
 
+                g_hash_table_remove (dialog->priv->bars, GUINT_TO_POINTER (id));
9803
 
+                gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (bar)),
9804
 
+                                      bar);
9805
 
+                dialog->priv->num_apps--;
9806
 
+                if (dialog->priv->num_apps == 0) {
9807
 
+                        gtk_widget_show (dialog->priv->no_apps_label);
9808
 
+                }
9809
 
+        }
9810
 
+
9811
 
+}
9812
 
+
9813
 
+static void
9814
 
+on_control_stream_added (GvcMixerControl *control,
9815
 
+                         guint            id,
9816
 
+                         GvcMixerDialog  *dialog)
9817
 
+{
9818
 
+        GvcMixerStream *stream;
9819
 
+        stream = gvc_mixer_control_lookup_stream_id (control, id);
9820
 
+        
9821
 
+        if (stream == NULL) 
9822
 
+                return;
9823
 
+        
9824
 
+        const char    *app_id;
9825
 
+        app_id = gvc_mixer_stream_get_application_id (stream);
9826
 
+
9827
 
+        if (stream == gvc_mixer_control_get_event_sink_input (dialog->priv->mixer_control) || (!GVC_IS_MIXER_SOURCE (stream) &&
9828
 
+                !GVC_IS_MIXER_SINK (stream)
9829
 
+                && !gvc_mixer_stream_is_virtual (stream)
9830
 
+                && g_strcmp0 (app_id, "org.gnome.VolumeControl") != 0
9831
 
+                && g_strcmp0 (app_id, "org.PulseAudio.pavucontrol") != 0)) {
9832
 
+
9833
 
+                GtkWidget      *bar;
9834
 
+
9835
 
+                bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (id));
9836
 
+                if (bar != NULL) {
9837
 
+                        g_debug ("GvcMixerDialog: Stream %u already added", id);
9838
 
+                        return;
9839
 
+                }
9840
 
+                add_stream (dialog, stream);
9841
 
+        } 
9842
 
+}
9843
 
+
9844
 
+static void
9845
 
+on_control_stream_removed (GvcMixerControl *control,
9846
 
+                           guint            id,
9847
 
+                           GvcMixerDialog  *dialog)
9848
 
+{
9849
 
+        remove_stream (dialog, id);
9850
 
+}
9851
 
+
9852
 
+static gboolean
9853
 
+find_item_by_id (GtkTreeModel *model,
9854
 
+                 guint         id,
9855
 
+                 guint         column,
9856
 
+                 GtkTreeIter  *iter)
9857
 
+{
9858
 
+        gboolean found_item;
9859
 
+
9860
 
+        found_item = FALSE;
9861
 
+
9862
 
+        if (!gtk_tree_model_get_iter_first (model, iter)) {
9863
 
+                return FALSE;
9864
 
+        }
9865
 
+
9866
 
+        do {
9867
 
+                guint t_id;
9868
 
+
9869
 
+                gtk_tree_model_get (model, iter,
9870
 
+                                    column, &t_id, -1);
9871
 
+
9872
 
+                if (id == t_id) {
9873
 
+                        found_item = TRUE;
9874
 
+                }
9875
 
+        } while (!found_item && gtk_tree_model_iter_next (model, iter));
9876
 
+
9877
 
+        return found_item;
9878
 
+}
9879
 
+
9880
 
+static void
9881
 
+add_input_ui_entry (GvcMixerDialog *dialog,
9882
 
+                    GvcMixerUIDevice *input)
9883
 
+{
9884
 
+        g_debug ("\n Add input ui entry with id : %u \n",
9885
 
+                  gvc_mixer_ui_device_get_id (input));
9886
 
+
9887
 
+        gchar    *port_name;
9888
 
+        gchar    *origin;
9889
 
+        gchar    *description;
9890
 
+        gboolean active;
9891
 
+        gboolean available;
9892
 
+        gint     card_id;
9893
 
+        gint     stream_id;
9894
 
+
9895
 
+        g_object_get (G_OBJECT (input),
9896
 
+                     "stream-id", &stream_id,
9897
 
+                     "card-id", &card_id,
9898
 
+                     "origin", &origin,
9899
 
+                     "description", &description,
9900
 
+                     "port-name", &port_name,
9901
 
+                     "port-available", &available,
9902
 
+                      NULL);
9903
 
+        GtkTreeModel        *model;
9904
 
+        GtkTreeIter          iter;
9905
 
+        const GvcChannelMap *map;
9906
 
+        GIcon               *icon;
9907
 
+
9908
 
+        if (card_id == GVC_MIXER_UI_DEVICE_INVALID) {
9909
 
+                GvcMixerStream *stream;
9910
 
+                g_debug ("just detected a network source");
9911
 
+                stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control, input);
9912
 
+                if (stream == NULL) {
9913
 
+                        g_warning ("tried to add the network source but the stream was null - fail ?!");
9914
 
+                        g_free (port_name);                                    
9915
 
+                        g_free (origin);                                                       
9916
 
+                        g_free (description);                                          
9917
 
+                        return;
9918
 
+                }
9919
 
+                icon = gvc_mixer_stream_get_gicon (stream);                    
9920
 
+        }
9921
 
+        else{
9922
 
+                GvcMixerCard        *card;
9923
 
+                card = gvc_mixer_control_lookup_card_id (dialog->priv->mixer_control, card_id);
9924
 
+                icon = gvc_mixer_card_get_gicon (card);                 
9925
 
+        }
9926
 
+
9927
 
+        model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
9928
 
+        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
9929
 
+
9930
 
+        gtk_list_store_set (GTK_LIST_STORE (model),
9931
 
+                            &iter,
9932
 
+                            NAME_COLUMN, description,
9933
 
+                            DEVICE_COLUMN, origin,
9934
 
+                            ACTIVE_COLUMN, FALSE,
9935
 
+                            ICON_COLUMN, icon,
9936
 
+                            ID_COLUMN, gvc_mixer_ui_device_get_id (input),
9937
 
+                            SPEAKERS_COLUMN,origin,
9938
 
+                            -1);
9939
 
+
9940
 
+        if (icon != NULL)
9941
 
+                g_object_unref (icon);
9942
 
+
9943
 
+        // TODO check this.
9944
 
+        /*g_signal_connect (output,
9945
 
+                          "notify::description",
9946
 
+                          G_CALLBACK (on_output_description_notify),
9947
 
+                          dialog);*/
9948
 
+              
9949
 
+        g_free (port_name);                                        
9950
 
+        g_free (origin);                                                        
9951
 
+        g_free (description);                   
9952
 
+}                                   
9953
 
+
9954
 
+static void
9955
 
+add_output_ui_entry (GvcMixerDialog *dialog,
9956
 
+                     GvcMixerUIDevice *output)
9957
 
+{
9958
 
+        g_debug ("\n Add output ui entry with id : %u \n",
9959
 
+                  gvc_mixer_ui_device_get_id (output));
9960
 
+
9961
 
+        gchar    *sink_port_name;
9962
 
+        gchar    *origin;
9963
 
+        gchar    *description;
9964
 
+        gboolean active;
9965
 
+        gboolean available;
9966
 
+        gint     card_id;
9967
 
+        gint     sink_stream_id;
9968
 
+
9969
 
+        g_object_get (G_OBJECT (output),
9970
 
+                     "stream-id", &sink_stream_id,
9971
 
+                     "card-id", &card_id,
9972
 
+                     "origin", &origin,
9973
 
+                     "description", &description,
9974
 
+                     "port-name", &sink_port_name,
9975
 
+                     "port-available", &available,
9976
 
+                      NULL);
9977
 
+       
9978
 
+        GtkTreeModel        *model;
9979
 
+        GtkTreeIter          iter;
9980
 
+        const GvcChannelMap *map;
9981
 
+        GIcon               *icon;
9982
 
+
9983
 
+        if (card_id == GVC_MIXER_UI_DEVICE_INVALID) {
9984
 
+                g_debug ("just detected a network sink");
9985
 
+                
9986
 
+                GvcMixerStream *stream;
9987
 
+                stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control, output);
9988
 
+                if (stream == NULL) {
9989
 
+                        g_warning ("tried to add the network sink but the stream was null - fail ?!");
9990
 
+                        g_free (sink_port_name);                                       
9991
 
+                        g_free (origin);                                                       
9992
 
+                        g_free (description);                                          
9993
 
+                        return;
9994
 
+                }
9995
 
+                icon = gvc_mixer_stream_get_gicon (stream);                    
9996
 
+        }
9997
 
+        else{
9998
 
+                GvcMixerCard       *card;
9999
 
+                card = gvc_mixer_control_lookup_card_id (dialog->priv->mixer_control, card_id);
10000
 
+                icon = gvc_mixer_card_get_gicon (card);                        
10001
 
+        }
10002
 
+
10003
 
+        model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
10004
 
+        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
10005
 
+
10006
 
+        gtk_list_store_set (GTK_LIST_STORE (model),
10007
 
+                            &iter,
10008
 
+                            NAME_COLUMN, description,
10009
 
+                            DEVICE_COLUMN, origin,
10010
 
+                            ACTIVE_COLUMN, FALSE,
10011
 
+                            ICON_COLUMN, icon,
10012
 
+                            ID_COLUMN, gvc_mixer_ui_device_get_id (output),
10013
 
+                            SPEAKERS_COLUMN,origin,
10014
 
+                            -1);
10015
 
+
10016
 
+        if (icon != NULL)
10017
 
+                g_object_unref (icon);
10018
 
+
10019
 
+        // TODO check this.
10020
 
+        /*g_signal_connect (output,
10021
 
+                          "notify::description",
10022
 
+                          G_CALLBACK (on_output_description_notify),
10023
 
+                          dialog);*/
10024
 
+              
10025
 
+        g_free (sink_port_name);                                       
10026
 
+        g_free (origin);                                                       
10027
 
+        g_free (description);                  
10028
 
+}                                  
10029
 
+
10030
 
+static void
10031
 
+on_control_output_added (GvcMixerControl *control,
10032
 
+                         guint            id,
10033
 
+                         GvcMixerDialog  *dialog)
10034
 
+{
10035
 
+       GvcMixerUIDevice* out = NULL;
10036
 
+       out = gvc_mixer_control_lookup_output_id (control, id);
10037
 
+
10038
 
+       if (out == NULL) {
10039
 
+               g_warning ("on_control_output_added - tried to fetch an output of id %u but got nothing", id);
10040
 
+               return;
10041
 
+       }
10042
 
+
10043
 
+       add_output_ui_entry (dialog, out);
10044
 
+}
10045
 
+
10046
 
+static void
10047
 
+on_control_active_output_update (GvcMixerControl *control,
10048
 
+                                 guint            id,
10049
 
+                                 GvcMixerDialog  *dialog)
10050
 
+{
10051
 
+       GvcMixerUIDevice* out = NULL;
10052
 
+       out = gvc_mixer_control_lookup_output_id (control, id);
10053
 
+
10054
 
+       if (out == NULL) {
10055
 
+               g_warning ("\n on_control_active_output_update - tried to fetch an output of id %u but got nothing", id);
10056
 
+               return;
10057
 
+       }
10058
 
+        active_output_update (dialog, out);
10059
 
+}
10060
 
+
10061
 
+static void
10062
 
+on_control_active_input_update (GvcMixerControl *control,
10063
 
+                                 guint            id,
10064
 
+                                 GvcMixerDialog  *dialog)
10065
 
+{
10066
 
+       GvcMixerUIDevice* in = NULL;
10067
 
+       in = gvc_mixer_control_lookup_input_id (control, id);
10068
 
+
10069
 
+       if (in == NULL) {
10070
 
+               g_warning ("on_control_active_input_update - tried to fetch an input of id %u but got nothing", id);
10071
 
+               return;
10072
 
+       }
10073
 
+        active_input_update (dialog, in);
10074
 
+}
10075
 
+
10076
 
+static void
10077
 
+on_control_input_added (GvcMixerControl *control,
10078
 
+                        guint            id,
10079
 
+                        GvcMixerDialog  *dialog)
10080
 
+{
10081
 
+       GvcMixerUIDevice* in = NULL;
10082
 
+       in = gvc_mixer_control_lookup_input_id (control, id);
10083
 
+
10084
 
+       if (in == NULL) {
10085
 
+               g_warning ("on_control_input_added - tried to fetch an input of id %u but got nothing", id);
10086
 
+               return;
10087
 
+       }
10088
 
+       add_input_ui_entry (dialog, in);
10089
 
+}
10090
 
+
10091
 
+static void
10092
 
+on_control_output_removed (GvcMixerControl *control,
10093
 
+                           guint           id,
10094
 
+                           GvcMixerDialog  *dialog)
10095
 
+{
10096
 
+        GtkWidget    *bar;
10097
 
+        gboolean      found;
10098
 
+        GtkTreeIter   iter;
10099
 
+        GtkTreeModel *model;
10100
 
+
10101
 
+        GvcMixerUIDevice* out = NULL;
10102
 
+        out = gvc_mixer_control_lookup_output_id (control, id);
10103
 
+        
10104
 
+        gint sink_stream_id;
10105
 
+        
10106
 
+        g_object_get (G_OBJECT (out),
10107
 
+                     "stream-id", &sink_stream_id,
10108
 
+                      NULL);
10109
 
+                     
10110
 
+        g_debug ("Remove output from dialog \n id : %u \n sink stream id : %i \n",
10111
 
+                  id,
10112
 
+                  sink_stream_id);
10113
 
+
10114
 
+        /* remove from any models */
10115
 
+        model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
10116
 
+        found = find_item_by_id (GTK_TREE_MODEL (model), id, ID_COLUMN, &iter);
10117
 
+        if (found) {
10118
 
+                gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
10119
 
+        }
10120
 
+}     
10121
 
+
10122
 
+
10123
 
+                 
10124
 
+static void
10125
 
+on_control_input_removed (GvcMixerControl *control,
10126
 
+                          guint            id,
10127
 
+                          GvcMixerDialog  *dialog)
10128
 
+{
10129
 
+        GtkWidget    *bar;
10130
 
+        gboolean      found;
10131
 
+        GtkTreeIter   iter;
10132
 
+        GtkTreeModel *model;
10133
 
+
10134
 
+        GvcMixerUIDevice* in = NULL;
10135
 
+        in = gvc_mixer_control_lookup_input_id (control, id);
10136
 
+        
10137
 
+        gint stream_id;
10138
 
+        
10139
 
+        g_object_get (G_OBJECT (in),
10140
 
+                     "stream-id", &stream_id,
10141
 
+                      NULL);
10142
 
+                      
10143
 
+        g_debug ("Remove input from dialog \n id : %u \n stream id : %i \n",
10144
 
+                  id,
10145
 
+                  stream_id);
10146
 
+
10147
 
+        /* remove from any models */
10148
 
+        model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
10149
 
+        found = find_item_by_id (GTK_TREE_MODEL (model), id, ID_COLUMN, &iter);
10150
 
+        if (found) {
10151
 
+                gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
10152
 
+        }        
10153
 
+}
10154
 
+
10155
 
+static void
10156
 
+_gtk_label_make_bold (GtkLabel *label)
10157
 
+{
10158
 
+        PangoFontDescription *font_desc;
10159
 
+
10160
 
+        font_desc = pango_font_description_new ();
10161
 
+
10162
 
+        pango_font_description_set_weight (font_desc,
10163
 
+                                           PANGO_WEIGHT_BOLD);
10164
 
+
10165
 
+        /* This will only affect the weight of the font, the rest is
10166
 
+         * from the current state of the widget, which comes from the
10167
 
+         * theme or user prefs, since the font desc only has the
10168
 
+         * weight flag turned on.
10169
 
+         */
10170
 
+        gtk_widget_modify_font (GTK_WIDGET (label), font_desc);
10171
 
+
10172
 
+        pango_font_description_free (font_desc);
10173
 
+}
10174
 
+
10175
 
+
10176
 
+static void
10177
 
+on_input_selection_changed (GtkTreeSelection *selection,
10178
 
+                             GvcMixerDialog   *dialog)
10179
 
+{
10180
 
+        GtkTreeModel *model;
10181
 
+        GtkTreeIter   iter;
10182
 
+        gboolean      toggled;
10183
 
+        guint         id;
10184
 
+
10185
 
+        if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) {
10186
 
+                g_debug ("Could not get default input from selection");
10187
 
+                return;
10188
 
+        }
10189
 
+
10190
 
+        gtk_tree_model_get (model, &iter,
10191
 
+                            ID_COLUMN, &id,
10192
 
+                            ACTIVE_COLUMN, &toggled,
10193
 
+                            -1);
10194
 
+
10195
 
+        toggled ^= 1;
10196
 
+        GvcMixerUIDevice *input;
10197
 
+        //g_debug ("on_input_selection_changed - try swap to input with id %u", id); 
10198
 
+        input = gvc_mixer_control_lookup_input_id (dialog->priv->mixer_control, id);
10199
 
+        
10200
 
+        if (input == NULL) {
10201
 
+                g_warning ("on_input_selection_changed - Unable to find input with id: %u", id);
10202
 
+                return;
10203
 
+        }
10204
 
+
10205
 
+        gvc_mixer_control_change_input (dialog->priv->mixer_control, input);
10206
 
+}
10207
 
+
10208
 
+static void
10209
 
+on_output_selection_changed (GtkTreeSelection *selection,
10210
 
+                             GvcMixerDialog   *dialog)
10211
 
+{
10212
 
+        GtkTreeModel *model;
10213
 
+        GtkTreeIter   iter;
10214
 
+        gboolean      active;
10215
 
+        guint         id;
10216
 
+
10217
 
+        if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) {
10218
 
+                g_debug ("Could not get default output from selection");
10219
 
+                return;
10220
 
+        }
10221
 
+
10222
 
+        gtk_tree_model_get (model, &iter,
10223
 
+                            ID_COLUMN, &id,
10224
 
+                            ACTIVE_COLUMN, &active,
10225
 
+                            -1);
10226
 
+        
10227
 
+        g_debug ("\n\n on_output_selection_changed - active %i \n\n", active); 
10228
 
+        if (active){
10229
 
+                return;
10230
 
+        }
10231
 
+
10232
 
+        GvcMixerUIDevice *output;
10233
 
+        g_debug ("\n on_output_selection_changed - try swap to output with id %u", id); 
10234
 
+       output = gvc_mixer_control_lookup_output_id (dialog->priv->mixer_control, id);
10235
 
+        
10236
 
+       if (output == NULL) {
10237
 
+               g_warning ("on_output_selection_changed - Unable to find output with id: %u", id);
10238
 
+               return;
10239
 
+       }
10240
 
+
10241
 
+        gvc_mixer_control_change_output (dialog->priv->mixer_control, output);
10242
 
+}
10243
 
+
10244
 
+static void
10245
 
+name_to_text (GtkTreeViewColumn *column,
10246
 
+              GtkCellRenderer *cell,
10247
 
+              GtkTreeModel *model,
10248
 
+              GtkTreeIter *iter,
10249
 
+              gpointer user_data)
10250
 
+{
10251
 
+        char *name, *mapping;
10252
 
+
10253
 
+        gtk_tree_model_get(model, iter,
10254
 
+                           NAME_COLUMN, &name,
10255
 
+                           SPEAKERS_COLUMN, &mapping,
10256
 
+                           -1);
10257
 
+
10258
 
+        if (mapping == NULL) {
10259
 
+                g_object_set (cell, "text", name, NULL);
10260
 
+        } else {
10261
 
+                char *str;
10262
 
+
10263
 
+                str = g_strdup_printf ("%s\n<i>%s</i>",
10264
 
+                                       name, mapping);
10265
 
+                g_object_set (cell, "markup", str, NULL);
10266
 
+                g_free (str);
10267
 
+        }
10268
 
+
10269
 
+        g_free (name);
10270
 
+        g_free (mapping);
10271
 
+}
10272
 
+
10273
 
+static GtkWidget *
10274
 
+create_stream_treeview (GvcMixerDialog *dialog,
10275
 
+                        GCallback       on_selection_changed)
10276
 
+{
10277
 
+        GtkWidget         *treeview;
10278
 
+        GtkListStore      *store;
10279
 
+        GtkCellRenderer   *renderer;
10280
 
+        GtkTreeViewColumn *column;
10281
 
+        GtkTreeSelection  *selection;
10282
 
+
10283
 
+        treeview = gtk_tree_view_new ();
10284
 
+        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
10285
 
+
10286
 
+        store = gtk_list_store_new (NUM_COLUMNS,
10287
 
+                                    G_TYPE_STRING,
10288
 
+                                    G_TYPE_STRING,
10289
 
+                                    G_TYPE_BOOLEAN,
10290
 
+                                    G_TYPE_UINT,
10291
 
+                                    G_TYPE_STRING,
10292
 
+                                    G_TYPE_ICON);
10293
 
+        gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
10294
 
+                                 GTK_TREE_MODEL (store));
10295
 
+
10296
 
+        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
10297
 
+        gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
10298
 
+
10299
 
+        column = gtk_tree_view_column_new ();
10300
 
+        gtk_tree_view_column_set_title (column, _("Name"));
10301
 
+        renderer = gtk_cell_renderer_pixbuf_new ();
10302
 
+        gtk_tree_view_column_pack_start (column, renderer, FALSE);
10303
 
+        g_object_set (G_OBJECT (renderer), "stock-size", GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
10304
 
+        gtk_tree_view_column_set_attributes (column, renderer,
10305
 
+                                             "gicon", ICON_COLUMN,
10306
 
+                                             NULL);
10307
 
+
10308
 
+        renderer = gtk_cell_renderer_text_new ();
10309
 
+        gtk_tree_view_column_pack_start (column, renderer, TRUE);
10310
 
+        gtk_tree_view_column_set_cell_data_func (column, renderer,
10311
 
+                                                 name_to_text, NULL, NULL);
10312
 
+        gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
10313
 
+
10314
 
+        g_signal_connect ( selection, "changed",
10315
 
+                          on_selection_changed, dialog);
10316
 
+#if 0
10317
 
+        renderer = gtk_cell_renderer_text_new ();
10318
 
+        column = gtk_tree_view_column_new_with_attributes (_("Device"),
10319
 
+                                                           renderer,
10320
 
+                                                           "text", DEVICE_COLUMN,
10321
 
+                                                           NULL);
10322
 
+        gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
10323
 
+#endif
10324
 
+        return treeview;
10325
 
+}
10326
 
+
10327
 
+static void
10328
 
+on_profile_changed (GvcComboBox *widget,
10329
 
+                    const char  *profile,
10330
 
+                    gpointer     user_data)
10331
 
+{
10332
 
+        GvcMixerCard        *card;
10333
 
+
10334
 
+        card = g_object_get_data (G_OBJECT (widget), "card");
10335
 
+        if (card == NULL) {
10336
 
+                g_warning ("Could not find card for combobox");
10337
 
+                return;
10338
 
+        }
10339
 
+
10340
 
+        g_debug ("Profile changed to %s for card %s", profile,
10341
 
+                 gvc_mixer_card_get_name (card));
10342
 
+
10343
 
+        gvc_mixer_card_change_profile (card, profile);
10344
 
+}
10345
 
+
10346
 
+static void
10347
 
+on_test_speakers_clicked (GtkButton *widget,
10348
 
+                          gpointer  user_data)
10349
 
+{
10350
 
+        GvcMixerDialog      *dialog = GVC_MIXER_DIALOG (user_data);
10351
 
+        GtkTreeModel        *model;
10352
 
+        GtkTreeIter         iter;
10353
 
+        gint                active_output = GVC_MIXER_UI_DEVICE_INVALID;
10354
 
+
10355
 
+        model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
10356
 
+        
10357
 
+        if (gtk_tree_model_get_iter_first (model, &iter) == FALSE){
10358
 
+                g_warning ("The tree is empty => we have no device to test speakers with return");
10359
 
+                return;        
10360
 
+        }
10361
 
+                
10362
 
+        do {
10363
 
+                gboolean         is_selected = FALSE ;
10364
 
+                gint             id;
10365
 
+                        
10366
 
+                gtk_tree_model_get (model, &iter,
10367
 
+                                    ID_COLUMN, &id,
10368
 
+                                    ACTIVE_COLUMN, &is_selected,
10369
 
+                                    -1);
10370
 
+                
10371
 
+                if (is_selected) {
10372
 
+                        active_output = id;
10373
 
+                        break;
10374
 
+                }
10375
 
+                
10376
 
+        }while (gtk_tree_model_iter_next (model, &iter));
10377
 
+        
10378
 
+        if (active_output == GVC_MIXER_UI_DEVICE_INVALID) {
10379
 
+                g_warning ("Cant find the active output from the UI");
10380
 
+                return;
10381
 
+        }        
10382
 
+
10383
 
+        GvcMixerUIDevice *output;
10384
 
+        output = gvc_mixer_control_lookup_output_id (dialog->priv->mixer_control, (guint)active_output);
10385
 
+        gint stream_id = gvc_mixer_ui_device_get_stream_id(output);
10386
 
+
10387
 
+        if (stream_id == GVC_MIXER_UI_DEVICE_INVALID)
10388
 
+                return;
10389
 
+
10390
 
+        g_debug ("Test the speakers on the %s", gvc_mixer_ui_device_get_description (output));
10391
 
+        
10392
 
+        GvcMixerStream        *stream;
10393
 
+        GvcMixerCardProfile *profile;
10394
 
+        GtkWidget           *d, *speaker_test, *container;
10395
 
+        char                *title;
10396
 
+
10397
 
+        stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, stream_id);
10398
 
+        if (stream == NULL) {
10399
 
+                g_debug ("Stream/sink not found");
10400
 
+                return;
10401
 
+        }
10402
 
+        title = g_strdup_printf (_("Speaker Testing for %s"), gvc_mixer_ui_device_get_description (output));
10403
 
+        d = gtk_dialog_new_with_buttons (title,
10404
 
+                                         GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget))),
10405
 
+                                         GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
10406
 
+                                         GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
10407
 
+                                         NULL);
10408
 
+        gtk_window_set_has_resize_grip (GTK_WINDOW (d), FALSE);
10409
 
+
10410
 
+        g_free (title);
10411
 
+        speaker_test = gvc_speaker_test_new (dialog->priv->mixer_control,
10412
 
+                                             stream);
10413
 
+        gtk_widget_show (speaker_test);
10414
 
+        container = gtk_dialog_get_content_area (GTK_DIALOG (d));
10415
 
+        gtk_container_add (GTK_CONTAINER (container), speaker_test);
10416
 
+
10417
 
+        gtk_dialog_run (GTK_DIALOG (d));
10418
 
+        gtk_widget_destroy (d);
10419
 
+}
10420
 
+
10421
 
+static GObject *
10422
 
+gvc_mixer_dialog_constructor (GType                  type,
10423
 
+                              guint                  n_construct_properties,
10424
 
+                              GObjectConstructParam *construct_params)
10425
 
+{
10426
 
+        GObject          *object;
10427
 
+        GvcMixerDialog   *self;
10428
 
+        GtkWidget        *main_vbox;
10429
 
+        GtkWidget        *label;
10430
 
+        GtkWidget        *alignment;
10431
 
+        GtkWidget        *alignment_settings_box;
10432
 
+        GtkWidget        *settings_box;
10433
 
+        GtkWidget        *box;
10434
 
+        GtkWidget        *sbox;
10435
 
+        GtkWidget        *ebox;
10436
 
+        GtkWidget        *test_sound_box;
10437
 
+        GSList           *streams;
10438
 
+        GSList           *cards;
10439
 
+        GSList           *l;
10440
 
+        GvcMixerStream   *stream;
10441
 
+        GvcMixerCard     *card;
10442
 
+        GtkTreeSelection *selection;
10443
 
+
10444
 
+        object = G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->constructor (type, n_construct_properties, construct_params);
10445
 
+
10446
 
+        self = GVC_MIXER_DIALOG (object);
10447
 
+
10448
 
+        main_vbox = GTK_WIDGET (self);
10449
 
+        gtk_box_set_spacing (GTK_BOX (main_vbox), 2);
10450
 
+
10451
 
+        gtk_container_set_border_width (GTK_CONTAINER (self), 3);
10452
 
+
10453
 
+        self->priv->output_stream_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
10454
 
+        alignment = gtk_alignment_new (0, 0, 1, 1);
10455
 
+        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 0, 0);
10456
 
+        gtk_container_add (GTK_CONTAINER (alignment), self->priv->output_stream_box);
10457
 
+        gtk_box_pack_start (GTK_BOX (main_vbox),
10458
 
+                            alignment,
10459
 
+                            FALSE, FALSE, 0);
10460
 
+
10461
 
+        self->priv->notebook = gtk_notebook_new ();
10462
 
+        gtk_box_pack_start (GTK_BOX (main_vbox),
10463
 
+                            self->priv->notebook,
10464
 
+                            TRUE, TRUE, 0);
10465
 
+        gtk_container_set_border_width (GTK_CONTAINER (self->priv->notebook), 5);
10466
 
+
10467
 
+        /* Output page */
10468
 
+        self->priv->output_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);        
10469
 
+        gtk_container_set_border_width (GTK_CONTAINER (self->priv->output_box), 12);
10470
 
+        label = gtk_label_new (_("Output"));
10471
 
+        gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
10472
 
+                                  self->priv->output_box,
10473
 
+                                  label);
10474
 
+
10475
 
+        box = gtk_frame_new (_("Play sound through"));
10476
 
+        gtk_widget_set_size_request (GTK_WIDGET (box), 310, -1);        
10477
 
+        label = gtk_frame_get_label_widget (GTK_FRAME (box));
10478
 
+        _gtk_label_make_bold (GTK_LABEL (label));
10479
 
+        gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
10480
 
+        gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
10481
 
+        gtk_box_pack_start (GTK_BOX (self->priv->output_box), box, FALSE, TRUE, 0);
10482
 
+
10483
 
+        alignment = gtk_alignment_new (0, 0, 1, 1);
10484
 
+        gtk_container_add (GTK_CONTAINER (box), alignment);
10485
 
+        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 10, 5, 0, 15);
10486
 
+
10487
 
+        self->priv->output_treeview = create_stream_treeview (self,
10488
 
+                                                              G_CALLBACK (on_output_selection_changed));
10489
 
+        gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->output_treeview);
10490
 
+
10491
 
+        box = gtk_scrolled_window_new (NULL, NULL);
10492
 
+        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (box),
10493
 
+                                        GTK_POLICY_NEVER,
10494
 
+                                        GTK_POLICY_AUTOMATIC);
10495
 
+        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (box),
10496
 
+                                             GTK_SHADOW_IN);
10497
 
+        gtk_container_add (GTK_CONTAINER (box), self->priv->output_treeview);
10498
 
+        gtk_container_add (GTK_CONTAINER (alignment), box);
10499
 
+        
10500
 
+        self->priv->selected_output_label = gtk_label_new (_("Settings for the selected device"));
10501
 
+        gtk_widget_set_halign (self->priv->selected_output_label, GTK_ALIGN_START);
10502
 
+        gtk_widget_set_valign (self->priv->selected_output_label, GTK_ALIGN_START);       
10503
 
+        gtk_misc_set_padding (GTK_MISC (self->priv->selected_output_label), 0, 0);
10504
 
+        _gtk_label_make_bold (GTK_LABEL (self->priv->selected_output_label));
10505
 
+        settings_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
10506
 
+        alignment_settings_box = gtk_alignment_new (0, 0, 1, 1);
10507
 
+        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment_settings_box), 7, 0, 0, 0);
10508
 
+        self->priv->output_settings_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
10509
 
+        gtk_container_add (GTK_CONTAINER (alignment_settings_box), self->priv->output_settings_box);
10510
 
+
10511
 
+        gtk_box_pack_start (GTK_BOX (self->priv->output_box),
10512
 
+                            settings_box,
10513
 
+                            FALSE,
10514
 
+                            FALSE,
10515
 
+                            0);
10516
 
+        gtk_box_pack_start (GTK_BOX (settings_box),
10517
 
+                            self->priv->selected_output_label,
10518
 
+                            FALSE,
10519
 
+                            FALSE,
10520
 
+                            0);
10521
 
+        gtk_box_pack_start (GTK_BOX (settings_box),
10522
 
+                            alignment_settings_box,
10523
 
+                            FALSE,
10524
 
+                            FALSE,
10525
 
+                            0);
10526
 
+
10527
 
+        self->priv->output_balance_bar = gvc_balance_bar_new (BALANCE_TYPE_RL);
10528
 
+        if (self->priv->size_group != NULL) {
10529
 
+                gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (self->priv->output_balance_bar),
10530
 
+                                                self->priv->size_group,
10531
 
+                                                FALSE);
10532
 
+        }
10533
 
+        gtk_box_pack_start (GTK_BOX (self->priv->output_settings_box),
10534
 
+                            self->priv->output_balance_bar,
10535
 
+                            FALSE, FALSE, 3);
10536
 
+        gtk_widget_show (self->priv->output_balance_bar);
10537
 
+
10538
 
+        self->priv->output_fade_bar = gvc_balance_bar_new (BALANCE_TYPE_FR);
10539
 
+        if (self->priv->size_group != NULL) {
10540
 
+                gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (self->priv->output_fade_bar),
10541
 
+                                                self->priv->size_group,
10542
 
+                                                FALSE);
10543
 
+        }
10544
 
+        gtk_box_pack_start (GTK_BOX (self->priv->output_settings_box),
10545
 
+                            self->priv->output_fade_bar,
10546
 
+                            FALSE, FALSE, 3);
10547
 
+        gtk_widget_show (self->priv->output_fade_bar);
10548
 
+
10549
 
+        self->priv->output_lfe_bar = gvc_balance_bar_new (BALANCE_TYPE_LFE);
10550
 
+        if (self->priv->size_group != NULL) {
10551
 
+                gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (self->priv->output_lfe_bar),
10552
 
+                                                self->priv->size_group,
10553
 
+                                                FALSE);
10554
 
+        }
10555
 
+        gtk_box_pack_start (GTK_BOX (self->priv->output_settings_box),
10556
 
+                            self->priv->output_lfe_bar,
10557
 
+                            FALSE, FALSE, 3);
10558
 
+        gtk_widget_show (self->priv->output_lfe_bar);
10559
 
+                
10560
 
+        /* Creating a box and try to deal using the same size group. */
10561
 
+        test_sound_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
10562
 
+        gtk_box_pack_end (GTK_BOX (self->priv->output_settings_box),
10563
 
+                          test_sound_box,
10564
 
+                          FALSE, 
10565
 
+                          FALSE,
10566
 
+                          5);
10567
 
+
10568
 
+        sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
10569
 
+        gtk_box_pack_start (GTK_BOX (test_sound_box),
10570
 
+                            sbox,
10571
 
+                            FALSE, FALSE, 0);
10572
 
+
10573
 
+        label = gtk_label_new (_("Test:"));
10574
 
+        gtk_box_pack_start (GTK_BOX (sbox),
10575
 
+                            label,
10576
 
+                            FALSE, FALSE, 0);
10577
 
+        if (self->priv->size_group != NULL)
10578
 
+                gtk_size_group_add_widget (self->priv->size_group, sbox);
10579
 
+
10580
 
+        self->priv->test_output_button = gtk_button_new_with_label (_("Test Sound"));
10581
 
+        
10582
 
+        /* FIXME: I am getting mental with all these hardcoded padding values,
10583
 
+         * Here 8 works fine, not sure why. */
10584
 
+        gtk_box_pack_start (GTK_BOX (test_sound_box),
10585
 
+                            self->priv->test_output_button,
10586
 
+                            TRUE, TRUE, 8);
10587
 
+
10588
 
+        /* Is this needed */
10589
 
+        if (self->priv->size_group != NULL)
10590
 
+                gtk_size_group_add_widget (self->priv->size_group, self->priv->test_output_button);
10591
 
+
10592
 
+        gtk_widget_show (test_sound_box);
10593
 
+
10594
 
+        //gtk_container_add (GTK_CONTAINER (box), self->priv->output_settings_box);
10595
 
+       g_signal_connect (self->priv->test_output_button,
10596
 
+                          "released",
10597
 
+                           G_CALLBACK (on_test_speakers_clicked),
10598
 
+                           self);
10599
 
+
10600
 
+        /* Input page */
10601
 
+        self->priv->input_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
10602
 
+        gtk_container_set_border_width (GTK_CONTAINER (self->priv->input_box), 12);
10603
 
+        label = gtk_label_new (_("Input"));
10604
 
+        gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
10605
 
+                                  self->priv->input_box,
10606
 
+                                  label);
10607
 
+        box = gtk_frame_new (_("Record sound from"));
10608
 
+        gtk_widget_set_size_request (GTK_WIDGET (box), 310, -1);        
10609
 
+        label = gtk_frame_get_label_widget (GTK_FRAME (box));
10610
 
+        _gtk_label_make_bold (GTK_LABEL (label));
10611
 
+        gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
10612
 
+        gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
10613
 
+        gtk_box_pack_start (GTK_BOX (self->priv->input_box), box, FALSE, TRUE, 0);
10614
 
+
10615
 
+        alignment = gtk_alignment_new (0, 0, 1, 1);
10616
 
+        gtk_container_add (GTK_CONTAINER (box), alignment);
10617
 
+        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 10, 5, 0, 15);
10618
 
+
10619
 
+        self->priv->input_treeview = create_stream_treeview (self,
10620
 
+                                                             G_CALLBACK (on_input_selection_changed));
10621
 
+        gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->input_treeview);
10622
 
+
10623
 
+        box = gtk_scrolled_window_new (NULL, NULL);
10624
 
+        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (box),
10625
 
+                                        GTK_POLICY_NEVER,
10626
 
+                                        GTK_POLICY_AUTOMATIC);
10627
 
+        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (box),
10628
 
+                                             GTK_SHADOW_IN);
10629
 
+        gtk_container_add (GTK_CONTAINER (box), self->priv->input_treeview);
10630
 
+        gtk_container_add (GTK_CONTAINER (alignment), box);
10631
 
+
10632
 
+        self->priv->selected_input_label = gtk_label_new (_("Settings for the selected device"));
10633
 
+        gtk_widget_set_halign (self->priv->selected_input_label, GTK_ALIGN_START);
10634
 
+        _gtk_label_make_bold (GTK_LABEL (self->priv->selected_input_label));
10635
 
+        
10636
 
+        self->priv->input_settings_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
10637
 
+        gtk_box_pack_start (GTK_BOX (self->priv->input_box),
10638
 
+                            self->priv->input_settings_box,
10639
 
+                            FALSE,
10640
 
+                            FALSE,
10641
 
+                            0);
10642
 
+        gtk_box_pack_start (GTK_BOX (self->priv->input_settings_box),
10643
 
+                            self->priv->selected_input_label,
10644
 
+                            FALSE,
10645
 
+                            FALSE,
10646
 
+                            0);     
10647
 
+
10648
 
+        self->priv->input_bar = create_bar (self, FALSE, TRUE);
10649
 
+        gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->input_bar),
10650
 
+                                  _("_Input volume:"));
10651
 
+        gvc_channel_bar_set_low_icon_name (GVC_CHANNEL_BAR (self->priv->input_bar),
10652
 
+                                           "audio-input-microphone-low-symbolic");
10653
 
+        gvc_channel_bar_set_high_icon_name (GVC_CHANNEL_BAR (self->priv->input_bar),
10654
 
+                                            "audio-input-microphone-high-symbolic");
10655
 
+        gtk_widget_set_sensitive (self->priv->input_bar, FALSE);
10656
 
+
10657
 
+        if (self->priv->size_group != NULL) {
10658
 
+                gvc_channel_bar_set_size_group (GVC_CHANNEL_BAR (self->priv->input_bar),
10659
 
+                                                self->priv->size_group,
10660
 
+                                                FALSE);                
10661
 
+        }
10662
 
+
10663
 
+        gtk_box_pack_start (GTK_BOX (self->priv->input_settings_box),
10664
 
+                            self->priv->input_bar,
10665
 
+                            FALSE, FALSE, 15);
10666
 
+        gtk_widget_show (self->priv->input_bar);
10667
 
+        
10668
 
+
10669
 
+        /* Creating a box and try to deal using the same size group. */
10670
 
+        GtkWidget *input_level_box;
10671
 
+        input_level_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
10672
 
+        gtk_box_pack_start (GTK_BOX (self->priv->input_settings_box),
10673
 
+                            input_level_box,
10674
 
+                            FALSE,
10675
 
+                            FALSE,
10676
 
+                            5);
10677
 
+
10678
 
+        sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
10679
 
+        gtk_box_pack_start (GTK_BOX (input_level_box),
10680
 
+                            sbox,
10681
 
+                            FALSE, FALSE, 0);
10682
 
+        
10683
 
+        label = gtk_label_new (_("Input level:"));
10684
 
+        gtk_box_pack_start (GTK_BOX (sbox),
10685
 
+                            label,
10686
 
+                            FALSE, FALSE, 0);
10687
 
+        if (self->priv->size_group != NULL)
10688
 
+                gtk_size_group_add_widget (self->priv->size_group, sbox);
10689
 
+
10690
 
+
10691
 
+        self->priv->input_level_bar = gvc_level_bar_new ();
10692
 
+        gvc_level_bar_set_orientation (GVC_LEVEL_BAR (self->priv->input_level_bar),
10693
 
+                                       GTK_ORIENTATION_HORIZONTAL);
10694
 
+        gvc_level_bar_set_scale (GVC_LEVEL_BAR (self->priv->input_level_bar),
10695
 
+                                 GVC_LEVEL_SCALE_LINEAR);
10696
 
+
10697
 
+        gtk_box_pack_start (GTK_BOX (input_level_box),
10698
 
+                            self->priv->input_level_bar,
10699
 
+                            TRUE, TRUE, 0);        
10700
 
+               
10701
 
+        /* Effects page */
10702
 
+        self->priv->sound_effects_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
10703
 
+        gtk_container_set_border_width (GTK_CONTAINER (self->priv->sound_effects_box), 12);
10704
 
+        label = gtk_label_new (_("Sound Effects"));
10705
 
+        gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
10706
 
+                                  self->priv->sound_effects_box,
10707
 
+                                  label);
10708
 
+
10709
 
+        self->priv->effects_bar = create_bar (self, FALSE, TRUE);
10710
 
+        gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->effects_bar),
10711
 
+                                  _("_Alert volume:"));
10712
 
+        gtk_widget_set_sensitive (self->priv->effects_bar, FALSE);
10713
 
+        gtk_box_pack_start (GTK_BOX (self->priv->sound_effects_box),
10714
 
+                            self->priv->effects_bar, FALSE, FALSE, 0);
10715
 
+
10716
 
+        self->priv->sound_theme_chooser = gvc_sound_theme_chooser_new ();
10717
 
+        gtk_box_pack_start (GTK_BOX (self->priv->sound_effects_box),
10718
 
+                            self->priv->sound_theme_chooser,
10719
 
+                            TRUE, TRUE, 6);
10720
 
+
10721
 
+        /* Applications */
10722
 
+        self->priv->applications_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
10723
 
+        gtk_container_set_border_width (GTK_CONTAINER (self->priv->applications_box), 12);
10724
 
+        label = gtk_label_new (_("Applications"));
10725
 
+        gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
10726
 
+                                  self->priv->applications_box,
10727
 
+                                  label);
10728
 
+        self->priv->no_apps_label = gtk_label_new (_("No application is currently playing or recording audio."));
10729
 
+        gtk_box_pack_start (GTK_BOX (self->priv->applications_box),
10730
 
+                            self->priv->no_apps_label,
10731
 
+                            TRUE, TRUE, 0);
10732
 
+
10733
 
+        self->priv->output_stream_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
10734
 
+        alignment = gtk_alignment_new (0, 0, 1, 1);
10735
 
+        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 12, 0, 0, 0);
10736
 
+        gtk_container_add (GTK_CONTAINER (alignment), self->priv->output_stream_box);
10737
 
+        gtk_box_pack_start (GTK_BOX (main_vbox),
10738
 
+                            alignment,
10739
 
+                            FALSE, FALSE, 0);
10740
 
+        // Output volume
10741
 
+        self->priv->output_bar = create_bar (self, FALSE, TRUE);
10742
 
+        gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->output_bar),
10743
 
+                                  _("_Output volume:"));
10744
 
+        gtk_widget_set_sensitive (self->priv->output_bar, FALSE);
10745
 
+        gtk_widget_set_size_request (self->priv->output_bar, 460, -1);        
10746
 
+
10747
 
+        gtk_box_pack_start (GTK_BOX (self->priv->output_stream_box),
10748
 
+                            self->priv->output_bar, TRUE, FALSE, 12);
10749
 
+
10750
 
+        gtk_widget_show_all (main_vbox);
10751
 
+
10752
 
+        g_signal_connect (self->priv->mixer_control,
10753
 
+                          "stream-added",
10754
 
+                          G_CALLBACK (on_control_stream_added),
10755
 
+                          self);
10756
 
+        g_signal_connect (self->priv->mixer_control,
10757
 
+                          "stream-removed",
10758
 
+                          G_CALLBACK (on_control_stream_removed),
10759
 
+                          self);
10760
 
+        g_signal_connect (self->priv->mixer_control,
10761
 
+                          "output-added",
10762
 
+                          G_CALLBACK (on_control_output_added),
10763
 
+                          self);
10764
 
+        g_signal_connect (self->priv->mixer_control,
10765
 
+                          "output-removed",
10766
 
+                          G_CALLBACK (on_control_output_removed),
10767
 
+                          self);
10768
 
+        g_signal_connect (self->priv->mixer_control,
10769
 
+                          "input-added",
10770
 
+                          G_CALLBACK (on_control_input_added),
10771
 
+                          self);
10772
 
+        g_signal_connect (self->priv->mixer_control,
10773
 
+                          "input-removed",
10774
 
+                          G_CALLBACK (on_control_input_removed),
10775
 
+                          self);        
10776
 
+        return object;
10777
 
+}
10778
 
+
10779
 
+static void
10780
 
+gvc_mixer_dialog_dispose (GObject *object)
10781
 
+{
10782
 
+        GvcMixerDialog *dialog = GVC_MIXER_DIALOG (object);
10783
 
+
10784
 
+        g_clear_object (&dialog->priv->indicator_settings);
10785
 
+
10786
 
+        if (dialog->priv->mixer_control != NULL) {
10787
 
+                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10788
 
+                                                      on_control_output_added,
10789
 
+                                                      dialog);
10790
 
+                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10791
 
+                                                      on_control_output_removed,
10792
 
+                                                      dialog);
10793
 
+                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10794
 
+                                                      on_control_active_input_update,
10795
 
+                                                      dialog);
10796
 
+                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10797
 
+                                                      on_control_active_output_update,
10798
 
+                                                      dialog);                                            
10799
 
+                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10800
 
+                                                      on_control_input_added,
10801
 
+                                                      dialog);
10802
 
+                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10803
 
+                                                      on_control_input_removed,
10804
 
+                                                      dialog);
10805
 
+                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10806
 
+                                                      on_control_stream_added,
10807
 
+                                                      dialog);
10808
 
+                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10809
 
+                                                      on_control_stream_removed,
10810
 
+                                                      dialog);
10811
 
+                g_object_unref (dialog->priv->mixer_control);
10812
 
+                dialog->priv->mixer_control = NULL;
10813
 
+        }
10814
 
+
10815
 
+        if (dialog->priv->bars != NULL) {
10816
 
+                g_hash_table_destroy (dialog->priv->bars);
10817
 
+                dialog->priv->bars = NULL;
10818
 
+        }
10819
 
+
10820
 
+        G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->dispose (object);
10821
 
+}
10822
 
+
10823
 
+static void
10824
 
+gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass)
10825
 
+{
10826
 
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
10827
 
+
10828
 
+        object_class->constructor = gvc_mixer_dialog_constructor;
10829
 
+        object_class->dispose = gvc_mixer_dialog_dispose;
10830
 
+        object_class->finalize = gvc_mixer_dialog_finalize;
10831
 
+        object_class->set_property = gvc_mixer_dialog_set_property;
10832
 
+        object_class->get_property = gvc_mixer_dialog_get_property;
10833
 
+
10834
 
+        g_object_class_install_property (object_class,
10835
 
+                                         PROP_MIXER_CONTROL,
10836
 
+                                         g_param_spec_object ("mixer-control",
10837
 
+                                                              "mixer control",
10838
 
+                                                              "mixer control",
10839
 
+                                                              GVC_TYPE_MIXER_CONTROL,
10840
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
10841
 
+
10842
 
+        g_type_class_add_private (klass, sizeof (GvcMixerDialogPrivate));
10843
 
+}
10844
 
+
10845
 
+
10846
 
+static void
10847
 
+gvc_mixer_dialog_init (GvcMixerDialog *dialog)
10848
 
+{
10849
 
+        dialog->priv = GVC_MIXER_DIALOG_GET_PRIVATE (dialog);
10850
 
+        dialog->priv->bars = g_hash_table_new (NULL, NULL);
10851
 
+        dialog->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
10852
 
+}
10853
 
+
10854
 
+static void
10855
 
+gvc_mixer_dialog_finalize (GObject *object)
10856
 
+{
10857
 
+        GvcMixerDialog *mixer_dialog;
10858
 
+
10859
 
+        g_return_if_fail (object != NULL);
10860
 
+        g_return_if_fail (GVC_IS_MIXER_DIALOG (object));
10861
 
+
10862
 
+        mixer_dialog = GVC_MIXER_DIALOG (object);
10863
 
+
10864
 
+        g_return_if_fail (mixer_dialog->priv != NULL);
10865
 
+        G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->finalize (object);
10866
 
+}
10867
 
+
10868
 
+GvcMixerDialog *
10869
 
+gvc_mixer_dialog_new (GvcMixerControl *control)
10870
 
+{
10871
 
+        GObject *dialog;
10872
 
+        dialog = g_object_new (GVC_TYPE_MIXER_DIALOG,
10873
 
+                               "mixer-control", control,
10874
 
+                               NULL);
10875
 
+        return GVC_MIXER_DIALOG (dialog);
10876
 
+}
10877
 
+
10878
 
+enum {
10879
 
+        PAGE_OUTPUT,
10880
 
+        PAGE_INPUT,
10881
 
+        PAGE_EVENTS,
10882
 
+        PAGE_APPLICATIONS
10883
 
+};
10884
 
+
10885
 
+gboolean
10886
 
+gvc_mixer_dialog_set_page (GvcMixerDialog *self,
10887
 
+                           const char     *page)
10888
 
+{
10889
 
+        guint num;
10890
 
+
10891
 
+        g_return_val_if_fail (self != NULL, FALSE);
10892
 
+
10893
 
+        num = PAGE_OUTPUT;
10894
 
+
10895
 
+        if (g_str_equal (page, "effects"))
10896
 
+                num = PAGE_EVENTS;
10897
 
+        else if (g_str_equal (page, "input"))
10898
 
+                num = PAGE_INPUT;
10899
 
+        else if (g_str_equal (page, "output"))
10900
 
+                num = PAGE_OUTPUT;
10901
 
+        else if (g_str_equal (page, "applications"))
10902
 
+                num = PAGE_APPLICATIONS;
10903
 
+
10904
 
+        gtk_notebook_set_current_page (GTK_NOTEBOOK (self->priv->notebook), num);
10905
 
+
10906
 
+        return TRUE;
10907
 
+}
10908
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-dialog.h
10909
 
===================================================================
10910
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
10911
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-dialog.h      2012-08-28 17:08:49.456516899 +0200
10912
 
@@ -0,0 +1,56 @@
10913
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
10914
 
+ *
10915
 
+ * Copyright (C) 2008 Red Hat, Inc.
10916
 
+ *
10917
 
+ * This program is free software; you can redistribute it and/or modify
10918
 
+ * it under the terms of the GNU General Public License as published by
10919
 
+ * the Free Software Foundation; either version 2 of the License, or
10920
 
+ * (at your option) any later version.
10921
 
+ *
10922
 
+ * This program is distributed in the hope that it will be useful,
10923
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10924
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10925
 
+ * GNU General Public License for more details.
10926
 
+ *
10927
 
+ * You should have received a copy of the GNU General Public License
10928
 
+ * along with this program; if not, write to the Free Software
10929
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
10930
 
+ *
10931
 
+ */
10932
 
+
10933
 
+#ifndef __GVC_MIXER_DIALOG_H
10934
 
+#define __GVC_MIXER_DIALOG_H
10935
 
+
10936
 
+#include <glib-object.h>
10937
 
+#include "gvc-mixer-control.h"
10938
 
+
10939
 
+G_BEGIN_DECLS
10940
 
+
10941
 
+#define GVC_TYPE_MIXER_DIALOG         (gvc_mixer_dialog_get_type ())
10942
 
+#define GVC_MIXER_DIALOG(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_DIALOG, GvcMixerDialog))
10943
 
+#define GVC_MIXER_DIALOG_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_DIALOG, GvcMixerDialogClass))
10944
 
+#define GVC_IS_MIXER_DIALOG(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_DIALOG))
10945
 
+#define GVC_IS_MIXER_DIALOG_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_DIALOG))
10946
 
+#define GVC_MIXER_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_DIALOG, GvcMixerDialogClass))
10947
 
+
10948
 
+typedef struct GvcMixerDialogPrivate GvcMixerDialogPrivate;
10949
 
+
10950
 
+typedef struct
10951
 
+{
10952
 
+        GtkVBox                parent;
10953
 
+        GvcMixerDialogPrivate *priv;
10954
 
+} GvcMixerDialog;
10955
 
+
10956
 
+typedef struct
10957
 
+{
10958
 
+        GtkVBoxClass           parent_class;
10959
 
+} GvcMixerDialogClass;
10960
 
+
10961
 
+GType               gvc_mixer_dialog_get_type            (void);
10962
 
+
10963
 
+GvcMixerDialog *    gvc_mixer_dialog_new                 (GvcMixerControl *control);
10964
 
+gboolean            gvc_mixer_dialog_set_page            (GvcMixerDialog *dialog, const gchar* page);
10965
 
+
10966
 
+G_END_DECLS
10967
 
+
10968
 
+#endif /* __GVC_MIXER_DIALOG_H */
10969
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-event-role.c
10970
 
===================================================================
10971
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
10972
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-event-role.c  2012-08-28 17:08:49.456516899 +0200
10973
 
@@ -0,0 +1,231 @@
10974
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
10975
 
+ *
10976
 
+ * Copyright (C) 2008 William Jon McCann
10977
 
+ *
10978
 
+ * This program is free software; you can redistribute it and/or modify
10979
 
+ * it under the terms of the GNU General Public License as published by
10980
 
+ * the Free Software Foundation; either version 2 of the License, or
10981
 
+ * (at your option) any later version.
10982
 
+ *
10983
 
+ * This program is distributed in the hope that it will be useful,
10984
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10985
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10986
 
+ * GNU General Public License for more details.
10987
 
+ *
10988
 
+ * You should have received a copy of the GNU General Public License
10989
 
+ * along with this program; if not, write to the Free Software
10990
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
10991
 
+ *
10992
 
+ */
10993
 
+
10994
 
+#include "config.h"
10995
 
+
10996
 
+#include <stdlib.h>
10997
 
+#include <stdio.h>
10998
 
+#include <unistd.h>
10999
 
+
11000
 
+#include <glib.h>
11001
 
+#include <glib/gi18n-lib.h>
11002
 
+
11003
 
+#include <pulse/pulseaudio.h>
11004
 
+#include <pulse/ext-stream-restore.h>
11005
 
+
11006
 
+#include "gvc-mixer-event-role.h"
11007
 
+#include "gvc-mixer-stream-private.h"
11008
 
+#include "gvc-channel-map-private.h"
11009
 
+
11010
 
+#define GVC_MIXER_EVENT_ROLE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRolePrivate))
11011
 
+
11012
 
+struct GvcMixerEventRolePrivate
11013
 
+{
11014
 
+        char          *device;
11015
 
+};
11016
 
+
11017
 
+enum
11018
 
+{
11019
 
+        PROP_0,
11020
 
+        PROP_DEVICE
11021
 
+};
11022
 
+
11023
 
+static void     gvc_mixer_event_role_class_init (GvcMixerEventRoleClass *klass);
11024
 
+static void     gvc_mixer_event_role_init       (GvcMixerEventRole      *mixer_event_role);
11025
 
+static void     gvc_mixer_event_role_finalize   (GObject            *object);
11026
 
+
11027
 
+G_DEFINE_TYPE (GvcMixerEventRole, gvc_mixer_event_role, GVC_TYPE_MIXER_STREAM)
11028
 
+
11029
 
+static gboolean
11030
 
+update_settings (GvcMixerEventRole *role,
11031
 
+                 gboolean           is_muted,
11032
 
+                 gpointer          *op)
11033
 
+{
11034
 
+        pa_operation              *o;
11035
 
+        const GvcChannelMap       *map;
11036
 
+        pa_context                *context;
11037
 
+        pa_ext_stream_restore_info info;
11038
 
+
11039
 
+        map = gvc_mixer_stream_get_channel_map (GVC_MIXER_STREAM(role));
11040
 
+
11041
 
+        info.volume = *gvc_channel_map_get_cvolume(map);
11042
 
+        info.name = "sink-input-by-media-role:event";
11043
 
+        info.channel_map = *gvc_channel_map_get_pa_channel_map(map);
11044
 
+        info.device = role->priv->device;
11045
 
+        info.mute = is_muted;
11046
 
+
11047
 
+        context = gvc_mixer_stream_get_pa_context (GVC_MIXER_STREAM (role));
11048
 
+
11049
 
+        o = pa_ext_stream_restore_write (context,
11050
 
+                                         PA_UPDATE_REPLACE,
11051
 
+                                         &info,
11052
 
+                                         1,
11053
 
+                                         TRUE,
11054
 
+                                         NULL,
11055
 
+                                         NULL);
11056
 
+
11057
 
+        if (o == NULL) {
11058
 
+                g_warning ("pa_ext_stream_restore_write() failed");
11059
 
+                return FALSE;
11060
 
+        }
11061
 
+
11062
 
+        if (op != NULL)
11063
 
+                *op = o;
11064
 
+
11065
 
+        return TRUE;
11066
 
+}
11067
 
+
11068
 
+static gboolean
11069
 
+gvc_mixer_event_role_push_volume (GvcMixerStream *stream, gpointer *op)
11070
 
+{
11071
 
+        return update_settings (GVC_MIXER_EVENT_ROLE (stream),
11072
 
+                                gvc_mixer_stream_get_is_muted (stream), op);
11073
 
+}
11074
 
+
11075
 
+static gboolean
11076
 
+gvc_mixer_event_role_change_is_muted (GvcMixerStream *stream,
11077
 
+                                      gboolean        is_muted)
11078
 
+{
11079
 
+        return update_settings (GVC_MIXER_EVENT_ROLE (stream),
11080
 
+                                is_muted, NULL);
11081
 
+}
11082
 
+
11083
 
+static gboolean
11084
 
+gvc_mixer_event_role_set_device (GvcMixerEventRole *role,
11085
 
+                                 const char        *device)
11086
 
+{
11087
 
+        g_return_val_if_fail (GVC_IS_MIXER_EVENT_ROLE (role), FALSE);
11088
 
+
11089
 
+        g_free (role->priv->device);
11090
 
+        role->priv->device = g_strdup (device);
11091
 
+        g_object_notify (G_OBJECT (role), "device");
11092
 
+
11093
 
+        return TRUE;
11094
 
+}
11095
 
+
11096
 
+static void
11097
 
+gvc_mixer_event_role_set_property (GObject       *object,
11098
 
+                                   guint          prop_id,
11099
 
+                                   const GValue  *value,
11100
 
+                                   GParamSpec    *pspec)
11101
 
+{
11102
 
+        GvcMixerEventRole *self = GVC_MIXER_EVENT_ROLE (object);
11103
 
+
11104
 
+        switch (prop_id) {
11105
 
+        case PROP_DEVICE:
11106
 
+                gvc_mixer_event_role_set_device (self, g_value_get_string (value));
11107
 
+                break;
11108
 
+        default:
11109
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
11110
 
+                break;
11111
 
+        }
11112
 
+}
11113
 
+
11114
 
+static void
11115
 
+gvc_mixer_event_role_get_property (GObject     *object,
11116
 
+                                   guint        prop_id,
11117
 
+                                   GValue      *value,
11118
 
+                                   GParamSpec  *pspec)
11119
 
+{
11120
 
+        GvcMixerEventRole *self = GVC_MIXER_EVENT_ROLE (object);
11121
 
+
11122
 
+        switch (prop_id) {
11123
 
+        case PROP_DEVICE:
11124
 
+                g_value_set_string (value, self->priv->device);
11125
 
+                break;
11126
 
+        default:
11127
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
11128
 
+                break;
11129
 
+        }
11130
 
+}
11131
 
+
11132
 
+static void
11133
 
+gvc_mixer_event_role_class_init (GvcMixerEventRoleClass *klass)
11134
 
+{
11135
 
+        GObjectClass        *object_class = G_OBJECT_CLASS (klass);
11136
 
+        GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
11137
 
+
11138
 
+        object_class->finalize = gvc_mixer_event_role_finalize;
11139
 
+        object_class->set_property = gvc_mixer_event_role_set_property;
11140
 
+        object_class->get_property = gvc_mixer_event_role_get_property;
11141
 
+
11142
 
+        stream_class->push_volume = gvc_mixer_event_role_push_volume;
11143
 
+        stream_class->change_is_muted = gvc_mixer_event_role_change_is_muted;
11144
 
+
11145
 
+        g_object_class_install_property (object_class,
11146
 
+                                         PROP_DEVICE,
11147
 
+                                         g_param_spec_string ("device",
11148
 
+                                                              "Device",
11149
 
+                                                              "Device",
11150
 
+                                                              NULL,
11151
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
11152
 
+
11153
 
+        g_type_class_add_private (klass, sizeof (GvcMixerEventRolePrivate));
11154
 
+}
11155
 
+
11156
 
+static void
11157
 
+gvc_mixer_event_role_init (GvcMixerEventRole *event_role)
11158
 
+{
11159
 
+        event_role->priv = GVC_MIXER_EVENT_ROLE_GET_PRIVATE (event_role);
11160
 
+
11161
 
+}
11162
 
+
11163
 
+static void
11164
 
+gvc_mixer_event_role_finalize (GObject *object)
11165
 
+{
11166
 
+        GvcMixerEventRole *mixer_event_role;
11167
 
+
11168
 
+        g_return_if_fail (object != NULL);
11169
 
+        g_return_if_fail (GVC_IS_MIXER_EVENT_ROLE (object));
11170
 
+
11171
 
+        mixer_event_role = GVC_MIXER_EVENT_ROLE (object);
11172
 
+
11173
 
+        g_return_if_fail (mixer_event_role->priv != NULL);
11174
 
+
11175
 
+        g_free (mixer_event_role->priv->device);
11176
 
+
11177
 
+        G_OBJECT_CLASS (gvc_mixer_event_role_parent_class)->finalize (object);
11178
 
+}
11179
 
+
11180
 
+/**
11181
 
+ * gvc_mixer_event_role_new: (skip)
11182
 
+ *
11183
 
+ * @context:
11184
 
+ * @index:
11185
 
+ * @channel_map:
11186
 
+ *
11187
 
+ * Returns:
11188
 
+ */
11189
 
+GvcMixerStream *
11190
 
+gvc_mixer_event_role_new (pa_context *context,
11191
 
+                          const char *device,
11192
 
+                          GvcChannelMap *channel_map)
11193
 
+{
11194
 
+        GObject *object;
11195
 
+
11196
 
+        object = g_object_new (GVC_TYPE_MIXER_EVENT_ROLE,
11197
 
+                               "pa-context", context,
11198
 
+                               "index", 0,
11199
 
+                               "device", device,
11200
 
+                               "channel-map", channel_map,
11201
 
+                               NULL);
11202
 
+
11203
 
+        return GVC_MIXER_STREAM (object);
11204
 
+}
11205
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-event-role.h
11206
 
===================================================================
11207
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
11208
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-event-role.h  2012-08-28 17:08:49.456516899 +0200
11209
 
@@ -0,0 +1,57 @@
11210
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11211
 
+ *
11212
 
+ * Copyright (C) 2008 Red Hat, Inc.
11213
 
+ *
11214
 
+ * This program is free software; you can redistribute it and/or modify
11215
 
+ * it under the terms of the GNU General Public License as published by
11216
 
+ * the Free Software Foundation; either version 2 of the License, or
11217
 
+ * (at your option) any later version.
11218
 
+ *
11219
 
+ * This program is distributed in the hope that it will be useful,
11220
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11221
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11222
 
+ * GNU General Public License for more details.
11223
 
+ *
11224
 
+ * You should have received a copy of the GNU General Public License
11225
 
+ * along with this program; if not, write to the Free Software
11226
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11227
 
+ *
11228
 
+ */
11229
 
+
11230
 
+#ifndef __GVC_MIXER_EVENT_ROLE_H
11231
 
+#define __GVC_MIXER_EVENT_ROLE_H
11232
 
+
11233
 
+#include <glib-object.h>
11234
 
+#include "gvc-mixer-stream.h"
11235
 
+
11236
 
+G_BEGIN_DECLS
11237
 
+
11238
 
+#define GVC_TYPE_MIXER_EVENT_ROLE         (gvc_mixer_event_role_get_type ())
11239
 
+#define GVC_MIXER_EVENT_ROLE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRole))
11240
 
+#define GVC_MIXER_EVENT_ROLE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRoleClass))
11241
 
+#define GVC_IS_MIXER_EVENT_ROLE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_EVENT_ROLE))
11242
 
+#define GVC_IS_MIXER_EVENT_ROLE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_EVENT_ROLE))
11243
 
+#define GVC_MIXER_EVENT_ROLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRoleClass))
11244
 
+
11245
 
+typedef struct GvcMixerEventRolePrivate GvcMixerEventRolePrivate;
11246
 
+
11247
 
+typedef struct
11248
 
+{
11249
 
+        GvcMixerStream            parent;
11250
 
+        GvcMixerEventRolePrivate *priv;
11251
 
+} GvcMixerEventRole;
11252
 
+
11253
 
+typedef struct
11254
 
+{
11255
 
+        GvcMixerStreamClass parent_class;
11256
 
+} GvcMixerEventRoleClass;
11257
 
+
11258
 
+GType               gvc_mixer_event_role_get_type      (void);
11259
 
+
11260
 
+GvcMixerStream *    gvc_mixer_event_role_new           (pa_context    *context,
11261
 
+                                                        const char    *device,
11262
 
+                                                        GvcChannelMap *channel_map);
11263
 
+
11264
 
+G_END_DECLS
11265
 
+
11266
 
+#endif /* __GVC_MIXER_EVENT_ROLE_H */
11267
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-sink-input.c
11268
 
===================================================================
11269
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
11270
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-sink-input.c  2012-08-28 17:08:49.456516899 +0200
11271
 
@@ -0,0 +1,166 @@
11272
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11273
 
+ *
11274
 
+ * Copyright (C) 2008 William Jon McCann
11275
 
+ *
11276
 
+ * This program is free software; you can redistribute it and/or modify
11277
 
+ * it under the terms of the GNU General Public License as published by
11278
 
+ * the Free Software Foundation; either version 2 of the License, or
11279
 
+ * (at your option) any later version.
11280
 
+ *
11281
 
+ * This program is distributed in the hope that it will be useful,
11282
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11283
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11284
 
+ * GNU General Public License for more details.
11285
 
+ *
11286
 
+ * You should have received a copy of the GNU General Public License
11287
 
+ * along with this program; if not, write to the Free Software
11288
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11289
 
+ *
11290
 
+ */
11291
 
+
11292
 
+#include "config.h"
11293
 
+
11294
 
+#include <stdlib.h>
11295
 
+#include <stdio.h>
11296
 
+#include <unistd.h>
11297
 
+
11298
 
+#include <glib.h>
11299
 
+#include <glib/gi18n-lib.h>
11300
 
+
11301
 
+#include <pulse/pulseaudio.h>
11302
 
+
11303
 
+#include "gvc-mixer-sink-input.h"
11304
 
+#include "gvc-mixer-stream-private.h"
11305
 
+#include "gvc-channel-map-private.h"
11306
 
+
11307
 
+#define GVC_MIXER_SINK_INPUT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputPrivate))
11308
 
+
11309
 
+struct GvcMixerSinkInputPrivate
11310
 
+{
11311
 
+        gpointer dummy;
11312
 
+};
11313
 
+
11314
 
+static void     gvc_mixer_sink_input_class_init (GvcMixerSinkInputClass *klass);
11315
 
+static void     gvc_mixer_sink_input_init       (GvcMixerSinkInput      *mixer_sink_input);
11316
 
+static void     gvc_mixer_sink_input_finalize   (GObject                *object);
11317
 
+
11318
 
+G_DEFINE_TYPE (GvcMixerSinkInput, gvc_mixer_sink_input, GVC_TYPE_MIXER_STREAM)
11319
 
+
11320
 
+static gboolean
11321
 
+gvc_mixer_sink_input_push_volume (GvcMixerStream *stream, gpointer *op)
11322
 
+{
11323
 
+        pa_operation        *o;
11324
 
+        guint                index;
11325
 
+        const GvcChannelMap *map;
11326
 
+        pa_context          *context;
11327
 
+        const pa_cvolume    *cv;
11328
 
+
11329
 
+        index = gvc_mixer_stream_get_index (stream);
11330
 
+
11331
 
+        map = gvc_mixer_stream_get_channel_map (stream);
11332
 
+
11333
 
+        cv = gvc_channel_map_get_cvolume(map);
11334
 
+
11335
 
+        context = gvc_mixer_stream_get_pa_context (stream);
11336
 
+
11337
 
+        o = pa_context_set_sink_input_volume (context,
11338
 
+                                              index,
11339
 
+                                              cv,
11340
 
+                                              NULL,
11341
 
+                                              NULL);
11342
 
+
11343
 
+        if (o == NULL) {
11344
 
+                g_warning ("pa_context_set_sink_input_volume() failed");
11345
 
+                return FALSE;
11346
 
+        }
11347
 
+
11348
 
+        *op = o;
11349
 
+
11350
 
+        return TRUE;
11351
 
+}
11352
 
+
11353
 
+static gboolean
11354
 
+gvc_mixer_sink_input_change_is_muted (GvcMixerStream *stream,
11355
 
+                                      gboolean        is_muted)
11356
 
+{
11357
 
+        pa_operation *o;
11358
 
+        guint         index;
11359
 
+        pa_context   *context;
11360
 
+
11361
 
+        index = gvc_mixer_stream_get_index (stream);
11362
 
+        context = gvc_mixer_stream_get_pa_context (stream);
11363
 
+
11364
 
+        o = pa_context_set_sink_input_mute (context,
11365
 
+                                            index,
11366
 
+                                            is_muted,
11367
 
+                                            NULL,
11368
 
+                                            NULL);
11369
 
+
11370
 
+        if (o == NULL) {
11371
 
+                g_warning ("pa_context_set_sink_input_mute_by_index() failed");
11372
 
+                return FALSE;
11373
 
+        }
11374
 
+
11375
 
+        pa_operation_unref(o);
11376
 
+
11377
 
+        return TRUE;
11378
 
+}
11379
 
+
11380
 
+static void
11381
 
+gvc_mixer_sink_input_class_init (GvcMixerSinkInputClass *klass)
11382
 
+{
11383
 
+        GObjectClass        *object_class = G_OBJECT_CLASS (klass);
11384
 
+        GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
11385
 
+
11386
 
+        object_class->finalize = gvc_mixer_sink_input_finalize;
11387
 
+
11388
 
+        stream_class->push_volume = gvc_mixer_sink_input_push_volume;
11389
 
+        stream_class->change_is_muted = gvc_mixer_sink_input_change_is_muted;
11390
 
+
11391
 
+        g_type_class_add_private (klass, sizeof (GvcMixerSinkInputPrivate));
11392
 
+}
11393
 
+
11394
 
+static void
11395
 
+gvc_mixer_sink_input_init (GvcMixerSinkInput *sink_input)
11396
 
+{
11397
 
+        sink_input->priv = GVC_MIXER_SINK_INPUT_GET_PRIVATE (sink_input);
11398
 
+}
11399
 
+
11400
 
+static void
11401
 
+gvc_mixer_sink_input_finalize (GObject *object)
11402
 
+{
11403
 
+        GvcMixerSinkInput *mixer_sink_input;
11404
 
+
11405
 
+        g_return_if_fail (object != NULL);
11406
 
+        g_return_if_fail (GVC_IS_MIXER_SINK_INPUT (object));
11407
 
+
11408
 
+        mixer_sink_input = GVC_MIXER_SINK_INPUT (object);
11409
 
+
11410
 
+        g_return_if_fail (mixer_sink_input->priv != NULL);
11411
 
+        G_OBJECT_CLASS (gvc_mixer_sink_input_parent_class)->finalize (object);
11412
 
+}
11413
 
+
11414
 
+/**
11415
 
+ * gvc_mixer_sink_input_new: (skip)
11416
 
+ *
11417
 
+ * @context:
11418
 
+ * @index:
11419
 
+ * @channel_map:
11420
 
+ *
11421
 
+ * Returns:
11422
 
+ */
11423
 
+GvcMixerStream *
11424
 
+gvc_mixer_sink_input_new (pa_context    *context,
11425
 
+                          guint          index,
11426
 
+                          GvcChannelMap *channel_map)
11427
 
+{
11428
 
+        GObject *object;
11429
 
+
11430
 
+        object = g_object_new (GVC_TYPE_MIXER_SINK_INPUT,
11431
 
+                               "pa-context", context,
11432
 
+                               "index", index,
11433
 
+                               "channel-map", channel_map,
11434
 
+                               NULL);
11435
 
+
11436
 
+        return GVC_MIXER_STREAM (object);
11437
 
+}
11438
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-sink-input.h
11439
 
===================================================================
11440
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
11441
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-sink-input.h  2012-08-28 17:08:49.456516899 +0200
11442
 
@@ -0,0 +1,57 @@
11443
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11444
 
+ *
11445
 
+ * Copyright (C) 2008 Red Hat, Inc.
11446
 
+ *
11447
 
+ * This program is free software; you can redistribute it and/or modify
11448
 
+ * it under the terms of the GNU General Public License as published by
11449
 
+ * the Free Software Foundation; either version 2 of the License, or
11450
 
+ * (at your option) any later version.
11451
 
+ *
11452
 
+ * This program is distributed in the hope that it will be useful,
11453
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11454
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11455
 
+ * GNU General Public License for more details.
11456
 
+ *
11457
 
+ * You should have received a copy of the GNU General Public License
11458
 
+ * along with this program; if not, write to the Free Software
11459
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11460
 
+ *
11461
 
+ */
11462
 
+
11463
 
+#ifndef __GVC_MIXER_SINK_INPUT_H
11464
 
+#define __GVC_MIXER_SINK_INPUT_H
11465
 
+
11466
 
+#include <glib-object.h>
11467
 
+#include "gvc-mixer-stream.h"
11468
 
+
11469
 
+G_BEGIN_DECLS
11470
 
+
11471
 
+#define GVC_TYPE_MIXER_SINK_INPUT         (gvc_mixer_sink_input_get_type ())
11472
 
+#define GVC_MIXER_SINK_INPUT(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInput))
11473
 
+#define GVC_MIXER_SINK_INPUT_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputClass))
11474
 
+#define GVC_IS_MIXER_SINK_INPUT(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SINK_INPUT))
11475
 
+#define GVC_IS_MIXER_SINK_INPUT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SINK_INPUT))
11476
 
+#define GVC_MIXER_SINK_INPUT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputClass))
11477
 
+
11478
 
+typedef struct GvcMixerSinkInputPrivate GvcMixerSinkInputPrivate;
11479
 
+
11480
 
+typedef struct
11481
 
+{
11482
 
+        GvcMixerStream            parent;
11483
 
+        GvcMixerSinkInputPrivate *priv;
11484
 
+} GvcMixerSinkInput;
11485
 
+
11486
 
+typedef struct
11487
 
+{
11488
 
+        GvcMixerStreamClass parent_class;
11489
 
+} GvcMixerSinkInputClass;
11490
 
+
11491
 
+GType               gvc_mixer_sink_input_get_type      (void);
11492
 
+
11493
 
+GvcMixerStream *    gvc_mixer_sink_input_new           (pa_context    *context,
11494
 
+                                                        guint          index,
11495
 
+                                                        GvcChannelMap *map);
11496
 
+
11497
 
+G_END_DECLS
11498
 
+
11499
 
+#endif /* __GVC_MIXER_SINK_INPUT_H */
11500
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-sink.c
11501
 
===================================================================
11502
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
11503
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-sink.c        2012-08-28 17:08:49.456516899 +0200
11504
 
@@ -0,0 +1,196 @@
11505
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11506
 
+ *
11507
 
+ * Copyright (C) 2008 William Jon McCann
11508
 
+ *
11509
 
+ * This program is free software; you can redistribute it and/or modify
11510
 
+ * it under the terms of the GNU General Public License as published by
11511
 
+ * the Free Software Foundation; either version 2 of the License, or
11512
 
+ * (at your option) any later version.
11513
 
+ *
11514
 
+ * This program is distributed in the hope that it will be useful,
11515
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11516
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11517
 
+ * GNU General Public License for more details.
11518
 
+ *
11519
 
+ * You should have received a copy of the GNU General Public License
11520
 
+ * along with this program; if not, write to the Free Software
11521
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11522
 
+ *
11523
 
+ */
11524
 
+
11525
 
+#include "config.h"
11526
 
+
11527
 
+#include <stdlib.h>
11528
 
+#include <stdio.h>
11529
 
+#include <unistd.h>
11530
 
+
11531
 
+#include <glib.h>
11532
 
+#include <glib/gi18n-lib.h>
11533
 
+
11534
 
+#include <pulse/pulseaudio.h>
11535
 
+
11536
 
+#include "gvc-mixer-sink.h"
11537
 
+#include "gvc-mixer-stream-private.h"
11538
 
+#include "gvc-channel-map-private.h"
11539
 
+
11540
 
+#define GVC_MIXER_SINK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SINK, GvcMixerSinkPrivate))
11541
 
+
11542
 
+struct GvcMixerSinkPrivate
11543
 
+{
11544
 
+        gpointer dummy;
11545
 
+};
11546
 
+
11547
 
+static void     gvc_mixer_sink_class_init (GvcMixerSinkClass *klass);
11548
 
+static void     gvc_mixer_sink_init       (GvcMixerSink      *mixer_sink);
11549
 
+static void     gvc_mixer_sink_finalize   (GObject           *object);
11550
 
+
11551
 
+G_DEFINE_TYPE (GvcMixerSink, gvc_mixer_sink, GVC_TYPE_MIXER_STREAM)
11552
 
+
11553
 
+static gboolean
11554
 
+gvc_mixer_sink_push_volume (GvcMixerStream *stream, gpointer *op)
11555
 
+{
11556
 
+        pa_operation        *o;
11557
 
+        guint                index;
11558
 
+        const GvcChannelMap *map;
11559
 
+        pa_context          *context;
11560
 
+        const pa_cvolume    *cv;
11561
 
+
11562
 
+        index = gvc_mixer_stream_get_index (stream);
11563
 
+
11564
 
+        map = gvc_mixer_stream_get_channel_map (stream);
11565
 
+
11566
 
+        /* set the volume */
11567
 
+        cv = gvc_channel_map_get_cvolume(map);
11568
 
+
11569
 
+        context = gvc_mixer_stream_get_pa_context (stream);
11570
 
+
11571
 
+        o = pa_context_set_sink_volume_by_index (context,
11572
 
+                                                 index,
11573
 
+                                                 cv,
11574
 
+                                                 NULL,
11575
 
+                                                 NULL);
11576
 
+
11577
 
+        if (o == NULL) {
11578
 
+                g_warning ("pa_context_set_sink_volume_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
11579
 
+                return FALSE;
11580
 
+        }
11581
 
+
11582
 
+        *op = o;
11583
 
+
11584
 
+        return TRUE;
11585
 
+}
11586
 
+
11587
 
+static gboolean
11588
 
+gvc_mixer_sink_change_is_muted (GvcMixerStream *stream,
11589
 
+                                gboolean        is_muted)
11590
 
+{
11591
 
+        pa_operation *o;
11592
 
+        guint         index;
11593
 
+        pa_context   *context;
11594
 
+
11595
 
+        index = gvc_mixer_stream_get_index (stream);
11596
 
+        context = gvc_mixer_stream_get_pa_context (stream);
11597
 
+
11598
 
+        o = pa_context_set_sink_mute_by_index (context,
11599
 
+                                               index,
11600
 
+                                               is_muted,
11601
 
+                                               NULL,
11602
 
+                                               NULL);
11603
 
+
11604
 
+        if (o == NULL) {
11605
 
+                g_warning ("pa_context_set_sink_mute_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
11606
 
+                return FALSE;
11607
 
+        }
11608
 
+
11609
 
+        pa_operation_unref(o);
11610
 
+
11611
 
+        return TRUE;
11612
 
+}
11613
 
+
11614
 
+static gboolean
11615
 
+gvc_mixer_sink_change_port (GvcMixerStream *stream,
11616
 
+                            const char     *port)
11617
 
+{
11618
 
+        pa_operation *o;
11619
 
+        guint         index;
11620
 
+        pa_context   *context;
11621
 
+
11622
 
+        index = gvc_mixer_stream_get_index (stream);
11623
 
+        context = gvc_mixer_stream_get_pa_context (stream);
11624
 
+
11625
 
+        o = pa_context_set_sink_port_by_index (context,
11626
 
+                                               index,
11627
 
+                                               port,
11628
 
+                                               NULL,
11629
 
+                                               NULL);
11630
 
+
11631
 
+        if (o == NULL) {
11632
 
+                g_warning ("pa_context_set_sink_port_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
11633
 
+                return FALSE;
11634
 
+        }
11635
 
+
11636
 
+        pa_operation_unref(o);
11637
 
+
11638
 
+        return TRUE;
11639
 
+}
11640
 
+
11641
 
+static void
11642
 
+gvc_mixer_sink_class_init (GvcMixerSinkClass *klass)
11643
 
+{
11644
 
+        GObjectClass        *object_class = G_OBJECT_CLASS (klass);
11645
 
+        GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
11646
 
+
11647
 
+        object_class->finalize = gvc_mixer_sink_finalize;
11648
 
+
11649
 
+        stream_class->push_volume = gvc_mixer_sink_push_volume;
11650
 
+        stream_class->change_port = gvc_mixer_sink_change_port;
11651
 
+        stream_class->change_is_muted = gvc_mixer_sink_change_is_muted;
11652
 
+
11653
 
+        g_type_class_add_private (klass, sizeof (GvcMixerSinkPrivate));
11654
 
+}
11655
 
+
11656
 
+static void
11657
 
+gvc_mixer_sink_init (GvcMixerSink *sink)
11658
 
+{
11659
 
+        sink->priv = GVC_MIXER_SINK_GET_PRIVATE (sink);
11660
 
+}
11661
 
+
11662
 
+static void
11663
 
+gvc_mixer_sink_finalize (GObject *object)
11664
 
+{
11665
 
+        GvcMixerSink *mixer_sink;
11666
 
+
11667
 
+        g_return_if_fail (object != NULL);
11668
 
+        g_return_if_fail (GVC_IS_MIXER_SINK (object));
11669
 
+
11670
 
+        mixer_sink = GVC_MIXER_SINK (object);
11671
 
+
11672
 
+        g_return_if_fail (mixer_sink->priv != NULL);
11673
 
+        G_OBJECT_CLASS (gvc_mixer_sink_parent_class)->finalize (object);
11674
 
+}
11675
 
+
11676
 
+/**
11677
 
+ * gvc_mixer_sink_new: (skip)
11678
 
+ *
11679
 
+ * @context:
11680
 
+ * @index:
11681
 
+ * @channel_map:
11682
 
+ *
11683
 
+ * Returns:
11684
 
+ */
11685
 
+GvcMixerStream *
11686
 
+gvc_mixer_sink_new (pa_context    *context,
11687
 
+                    guint          index,
11688
 
+                    GvcChannelMap *channel_map)
11689
 
+
11690
 
+{
11691
 
+        GObject *object;
11692
 
+
11693
 
+        object = g_object_new (GVC_TYPE_MIXER_SINK,
11694
 
+                               "pa-context", context,
11695
 
+                               "index", index,
11696
 
+                               "channel-map", channel_map,
11697
 
+                               NULL);
11698
 
+
11699
 
+        return GVC_MIXER_STREAM (object);
11700
 
+}
11701
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-sink.h
11702
 
===================================================================
11703
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
11704
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-sink.h        2012-08-28 17:08:49.456516899 +0200
11705
 
@@ -0,0 +1,57 @@
11706
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11707
 
+ *
11708
 
+ * Copyright (C) 2008 Red Hat, Inc.
11709
 
+ *
11710
 
+ * This program is free software; you can redistribute it and/or modify
11711
 
+ * it under the terms of the GNU General Public License as published by
11712
 
+ * the Free Software Foundation; either version 2 of the License, or
11713
 
+ * (at your option) any later version.
11714
 
+ *
11715
 
+ * This program is distributed in the hope that it will be useful,
11716
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11717
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11718
 
+ * GNU General Public License for more details.
11719
 
+ *
11720
 
+ * You should have received a copy of the GNU General Public License
11721
 
+ * along with this program; if not, write to the Free Software
11722
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11723
 
+ *
11724
 
+ */
11725
 
+
11726
 
+#ifndef __GVC_MIXER_SINK_H
11727
 
+#define __GVC_MIXER_SINK_H
11728
 
+
11729
 
+#include <glib-object.h>
11730
 
+#include "gvc-mixer-stream.h"
11731
 
+
11732
 
+G_BEGIN_DECLS
11733
 
+
11734
 
+#define GVC_TYPE_MIXER_SINK         (gvc_mixer_sink_get_type ())
11735
 
+#define GVC_MIXER_SINK(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SINK, GvcMixerSink))
11736
 
+#define GVC_MIXER_SINK_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SINK, GvcMixerSinkClass))
11737
 
+#define GVC_IS_MIXER_SINK(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SINK))
11738
 
+#define GVC_IS_MIXER_SINK_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SINK))
11739
 
+#define GVC_MIXER_SINK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SINK, GvcMixerSinkClass))
11740
 
+
11741
 
+typedef struct GvcMixerSinkPrivate GvcMixerSinkPrivate;
11742
 
+
11743
 
+typedef struct
11744
 
+{
11745
 
+        GvcMixerStream       parent;
11746
 
+        GvcMixerSinkPrivate *priv;
11747
 
+} GvcMixerSink;
11748
 
+
11749
 
+typedef struct
11750
 
+{
11751
 
+        GvcMixerStreamClass parent_class;
11752
 
+} GvcMixerSinkClass;
11753
 
+
11754
 
+GType               gvc_mixer_sink_get_type            (void);
11755
 
+
11756
 
+GvcMixerStream *    gvc_mixer_sink_new                 (pa_context    *context,
11757
 
+                                                        guint          index,
11758
 
+                                                        GvcChannelMap *map);
11759
 
+
11760
 
+G_END_DECLS
11761
 
+
11762
 
+#endif /* __GVC_MIXER_SINK_H */
11763
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-source-output.c
11764
 
===================================================================
11765
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
11766
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-source-output.c       2012-08-28 17:08:49.456516899 +0200
11767
 
@@ -0,0 +1,121 @@
11768
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11769
 
+ *
11770
 
+ * Copyright (C) 2008 William Jon McCann
11771
 
+ *
11772
 
+ * This program is free software; you can redistribute it and/or modify
11773
 
+ * it under the terms of the GNU General Public License as published by
11774
 
+ * the Free Software Foundation; either version 2 of the License, or
11775
 
+ * (at your option) any later version.
11776
 
+ *
11777
 
+ * This program is distributed in the hope that it will be useful,
11778
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11779
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11780
 
+ * GNU General Public License for more details.
11781
 
+ *
11782
 
+ * You should have received a copy of the GNU General Public License
11783
 
+ * along with this program; if not, write to the Free Software
11784
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11785
 
+ *
11786
 
+ */
11787
 
+
11788
 
+#include "config.h"
11789
 
+
11790
 
+#include <stdlib.h>
11791
 
+#include <stdio.h>
11792
 
+#include <unistd.h>
11793
 
+
11794
 
+#include <glib.h>
11795
 
+#include <glib/gi18n-lib.h>
11796
 
+
11797
 
+#include <pulse/pulseaudio.h>
11798
 
+
11799
 
+#include "gvc-mixer-source-output.h"
11800
 
+
11801
 
+#define GVC_MIXER_SOURCE_OUTPUT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputPrivate))
11802
 
+
11803
 
+struct GvcMixerSourceOutputPrivate
11804
 
+{
11805
 
+        gpointer dummy;
11806
 
+};
11807
 
+
11808
 
+static void     gvc_mixer_source_output_class_init (GvcMixerSourceOutputClass *klass);
11809
 
+static void     gvc_mixer_source_output_init       (GvcMixerSourceOutput      *mixer_source_output);
11810
 
+static void     gvc_mixer_source_output_finalize   (GObject            *object);
11811
 
+
11812
 
+G_DEFINE_TYPE (GvcMixerSourceOutput, gvc_mixer_source_output, GVC_TYPE_MIXER_STREAM)
11813
 
+
11814
 
+static gboolean
11815
 
+gvc_mixer_source_output_push_volume (GvcMixerStream *stream, gpointer *op)
11816
 
+{
11817
 
+        /* FIXME: */
11818
 
+        *op = NULL;
11819
 
+        return TRUE;
11820
 
+}
11821
 
+
11822
 
+static gboolean
11823
 
+gvc_mixer_source_output_change_is_muted (GvcMixerStream *stream,
11824
 
+                                      gboolean        is_muted)
11825
 
+{
11826
 
+        /* FIXME: */
11827
 
+        return TRUE;
11828
 
+}
11829
 
+
11830
 
+static void
11831
 
+gvc_mixer_source_output_class_init (GvcMixerSourceOutputClass *klass)
11832
 
+{
11833
 
+        GObjectClass        *object_class = G_OBJECT_CLASS (klass);
11834
 
+        GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
11835
 
+
11836
 
+        object_class->finalize = gvc_mixer_source_output_finalize;
11837
 
+
11838
 
+        stream_class->push_volume = gvc_mixer_source_output_push_volume;
11839
 
+        stream_class->change_is_muted = gvc_mixer_source_output_change_is_muted;
11840
 
+
11841
 
+        g_type_class_add_private (klass, sizeof (GvcMixerSourceOutputPrivate));
11842
 
+}
11843
 
+
11844
 
+static void
11845
 
+gvc_mixer_source_output_init (GvcMixerSourceOutput *source_output)
11846
 
+{
11847
 
+        source_output->priv = GVC_MIXER_SOURCE_OUTPUT_GET_PRIVATE (source_output);
11848
 
+
11849
 
+}
11850
 
+
11851
 
+static void
11852
 
+gvc_mixer_source_output_finalize (GObject *object)
11853
 
+{
11854
 
+        GvcMixerSourceOutput *mixer_source_output;
11855
 
+
11856
 
+        g_return_if_fail (object != NULL);
11857
 
+        g_return_if_fail (GVC_IS_MIXER_SOURCE_OUTPUT (object));
11858
 
+
11859
 
+        mixer_source_output = GVC_MIXER_SOURCE_OUTPUT (object);
11860
 
+
11861
 
+        g_return_if_fail (mixer_source_output->priv != NULL);
11862
 
+        G_OBJECT_CLASS (gvc_mixer_source_output_parent_class)->finalize (object);
11863
 
+}
11864
 
+
11865
 
+/**
11866
 
+ * gvc_mixer_source_output_new: (skip)
11867
 
+ *
11868
 
+ * @context:
11869
 
+ * @index:
11870
 
+ * @channel_map:
11871
 
+ *
11872
 
+ * Returns:
11873
 
+ */
11874
 
+GvcMixerStream *
11875
 
+gvc_mixer_source_output_new (pa_context    *context,
11876
 
+                             guint          index,
11877
 
+                             GvcChannelMap *channel_map)
11878
 
+{
11879
 
+        GObject *object;
11880
 
+
11881
 
+        object = g_object_new (GVC_TYPE_MIXER_SOURCE_OUTPUT,
11882
 
+                               "pa-context", context,
11883
 
+                               "index", index,
11884
 
+                               "channel-map", channel_map,
11885
 
+                               NULL);
11886
 
+
11887
 
+        return GVC_MIXER_STREAM (object);
11888
 
+}
11889
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-source-output.h
11890
 
===================================================================
11891
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
11892
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-source-output.h       2012-08-28 17:08:49.456516899 +0200
11893
 
@@ -0,0 +1,57 @@
11894
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11895
 
+ *
11896
 
+ * Copyright (C) 2008 Red Hat, Inc.
11897
 
+ *
11898
 
+ * This program is free software; you can redistribute it and/or modify
11899
 
+ * it under the terms of the GNU General Public License as published by
11900
 
+ * the Free Software Foundation; either version 2 of the License, or
11901
 
+ * (at your option) any later version.
11902
 
+ *
11903
 
+ * This program is distributed in the hope that it will be useful,
11904
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11905
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11906
 
+ * GNU General Public License for more details.
11907
 
+ *
11908
 
+ * You should have received a copy of the GNU General Public License
11909
 
+ * along with this program; if not, write to the Free Software
11910
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11911
 
+ *
11912
 
+ */
11913
 
+
11914
 
+#ifndef __GVC_MIXER_SOURCE_OUTPUT_H
11915
 
+#define __GVC_MIXER_SOURCE_OUTPUT_H
11916
 
+
11917
 
+#include <glib-object.h>
11918
 
+#include "gvc-mixer-stream.h"
11919
 
+
11920
 
+G_BEGIN_DECLS
11921
 
+
11922
 
+#define GVC_TYPE_MIXER_SOURCE_OUTPUT         (gvc_mixer_source_output_get_type ())
11923
 
+#define GVC_MIXER_SOURCE_OUTPUT(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutput))
11924
 
+#define GVC_MIXER_SOURCE_OUTPUT_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputClass))
11925
 
+#define GVC_IS_MIXER_SOURCE_OUTPUT(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT))
11926
 
+#define GVC_IS_MIXER_SOURCE_OUTPUT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SOURCE_OUTPUT))
11927
 
+#define GVC_MIXER_SOURCE_OUTPUT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputClass))
11928
 
+
11929
 
+typedef struct GvcMixerSourceOutputPrivate GvcMixerSourceOutputPrivate;
11930
 
+
11931
 
+typedef struct
11932
 
+{
11933
 
+        GvcMixerStream               parent;
11934
 
+        GvcMixerSourceOutputPrivate *priv;
11935
 
+} GvcMixerSourceOutput;
11936
 
+
11937
 
+typedef struct
11938
 
+{
11939
 
+        GvcMixerStreamClass parent_class;
11940
 
+} GvcMixerSourceOutputClass;
11941
 
+
11942
 
+GType               gvc_mixer_source_output_get_type      (void);
11943
 
+
11944
 
+GvcMixerStream *    gvc_mixer_source_output_new           (pa_context    *context,
11945
 
+                                                           guint          index,
11946
 
+                                                           GvcChannelMap *map);
11947
 
+
11948
 
+G_END_DECLS
11949
 
+
11950
 
+#endif /* __GVC_MIXER_SOURCE_OUTPUT_H */
11951
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-source.c
11952
 
===================================================================
11953
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
11954
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-source.c      2012-08-28 17:08:49.460516899 +0200
11955
 
@@ -0,0 +1,196 @@
11956
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11957
 
+ *
11958
 
+ * Copyright (C) 2008 William Jon McCann
11959
 
+ *
11960
 
+ * This program is free software; you can redistribute it and/or modify
11961
 
+ * it under the terms of the GNU General Public License as published by
11962
 
+ * the Free Software Foundation; either version 2 of the License, or
11963
 
+ * (at your option) any later version.
11964
 
+ *
11965
 
+ * This program is distributed in the hope that it will be useful,
11966
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11967
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11968
 
+ * GNU General Public License for more details.
11969
 
+ *
11970
 
+ * You should have received a copy of the GNU General Public License
11971
 
+ * along with this program; if not, write to the Free Software
11972
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11973
 
+ *
11974
 
+ */
11975
 
+
11976
 
+#include "config.h"
11977
 
+
11978
 
+#include <stdlib.h>
11979
 
+#include <stdio.h>
11980
 
+#include <unistd.h>
11981
 
+
11982
 
+#include <glib.h>
11983
 
+#include <glib/gi18n-lib.h>
11984
 
+
11985
 
+#include <pulse/pulseaudio.h>
11986
 
+
11987
 
+#include "gvc-mixer-source.h"
11988
 
+#include "gvc-mixer-stream-private.h"
11989
 
+#include "gvc-channel-map-private.h"
11990
 
+
11991
 
+#define GVC_MIXER_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSourcePrivate))
11992
 
+
11993
 
+struct GvcMixerSourcePrivate
11994
 
+{
11995
 
+        gpointer dummy;
11996
 
+};
11997
 
+
11998
 
+static void     gvc_mixer_source_class_init (GvcMixerSourceClass *klass);
11999
 
+static void     gvc_mixer_source_init       (GvcMixerSource      *mixer_source);
12000
 
+static void     gvc_mixer_source_finalize   (GObject            *object);
12001
 
+
12002
 
+G_DEFINE_TYPE (GvcMixerSource, gvc_mixer_source, GVC_TYPE_MIXER_STREAM)
12003
 
+
12004
 
+static gboolean
12005
 
+gvc_mixer_source_push_volume (GvcMixerStream *stream, gpointer *op)
12006
 
+{
12007
 
+        pa_operation        *o;
12008
 
+        guint                index;
12009
 
+        const GvcChannelMap *map;
12010
 
+        pa_context          *context;
12011
 
+        const pa_cvolume    *cv;
12012
 
+
12013
 
+        index = gvc_mixer_stream_get_index (stream);
12014
 
+
12015
 
+        map = gvc_mixer_stream_get_channel_map (stream);
12016
 
+
12017
 
+        /* set the volume */
12018
 
+        cv = gvc_channel_map_get_cvolume (map);
12019
 
+
12020
 
+        context = gvc_mixer_stream_get_pa_context (stream);
12021
 
+
12022
 
+        o = pa_context_set_source_volume_by_index (context,
12023
 
+                                                   index,
12024
 
+                                                   cv,
12025
 
+                                                   NULL,
12026
 
+                                                   NULL);
12027
 
+
12028
 
+        if (o == NULL) {
12029
 
+                g_warning ("pa_context_set_source_volume_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
12030
 
+                return FALSE;
12031
 
+        }
12032
 
+
12033
 
+        *op = o;
12034
 
+
12035
 
+        return TRUE;
12036
 
+}
12037
 
+
12038
 
+static gboolean
12039
 
+gvc_mixer_source_change_is_muted (GvcMixerStream *stream,
12040
 
+                                gboolean        is_muted)
12041
 
+{
12042
 
+        pa_operation *o;
12043
 
+        guint         index;
12044
 
+        pa_context   *context;
12045
 
+
12046
 
+        index = gvc_mixer_stream_get_index (stream);
12047
 
+        context = gvc_mixer_stream_get_pa_context (stream);
12048
 
+
12049
 
+        o = pa_context_set_source_mute_by_index (context,
12050
 
+                                                 index,
12051
 
+                                                 is_muted,
12052
 
+                                                 NULL,
12053
 
+                                                 NULL);
12054
 
+
12055
 
+        if (o == NULL) {
12056
 
+                g_warning ("pa_context_set_source_mute_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
12057
 
+                return FALSE;
12058
 
+        }
12059
 
+
12060
 
+        pa_operation_unref(o);
12061
 
+
12062
 
+        return TRUE;
12063
 
+}
12064
 
+
12065
 
+static gboolean
12066
 
+gvc_mixer_source_change_port (GvcMixerStream *stream,
12067
 
+                              const char     *port)
12068
 
+{
12069
 
+        pa_operation *o;
12070
 
+        guint         index;
12071
 
+        pa_context   *context;
12072
 
+
12073
 
+        index = gvc_mixer_stream_get_index (stream);
12074
 
+        context = gvc_mixer_stream_get_pa_context (stream);
12075
 
+
12076
 
+        o = pa_context_set_source_port_by_index (context,
12077
 
+                                                 index,
12078
 
+                                                 port,
12079
 
+                                                 NULL,
12080
 
+                                                 NULL);
12081
 
+
12082
 
+        if (o == NULL) {
12083
 
+                g_warning ("pa_context_set_source_port_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
12084
 
+                return FALSE;
12085
 
+        }
12086
 
+
12087
 
+        pa_operation_unref(o);
12088
 
+
12089
 
+        return TRUE;
12090
 
+}
12091
 
+
12092
 
+static void
12093
 
+gvc_mixer_source_class_init (GvcMixerSourceClass *klass)
12094
 
+{
12095
 
+        GObjectClass        *object_class = G_OBJECT_CLASS (klass);
12096
 
+        GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
12097
 
+
12098
 
+        object_class->finalize = gvc_mixer_source_finalize;
12099
 
+
12100
 
+        stream_class->push_volume = gvc_mixer_source_push_volume;
12101
 
+        stream_class->change_is_muted = gvc_mixer_source_change_is_muted;
12102
 
+        stream_class->change_port = gvc_mixer_source_change_port;
12103
 
+
12104
 
+        g_type_class_add_private (klass, sizeof (GvcMixerSourcePrivate));
12105
 
+}
12106
 
+
12107
 
+static void
12108
 
+gvc_mixer_source_init (GvcMixerSource *source)
12109
 
+{
12110
 
+        source->priv = GVC_MIXER_SOURCE_GET_PRIVATE (source);
12111
 
+}
12112
 
+
12113
 
+static void
12114
 
+gvc_mixer_source_finalize (GObject *object)
12115
 
+{
12116
 
+        GvcMixerSource *mixer_source;
12117
 
+
12118
 
+        g_return_if_fail (object != NULL);
12119
 
+        g_return_if_fail (GVC_IS_MIXER_SOURCE (object));
12120
 
+
12121
 
+        mixer_source = GVC_MIXER_SOURCE (object);
12122
 
+
12123
 
+        g_return_if_fail (mixer_source->priv != NULL);
12124
 
+        G_OBJECT_CLASS (gvc_mixer_source_parent_class)->finalize (object);
12125
 
+}
12126
 
+
12127
 
+/**
12128
 
+ * gvc_mixer_source_new: (skip)
12129
 
+ *
12130
 
+ * @context:
12131
 
+ * @index:
12132
 
+ * @channel_map:
12133
 
+ *
12134
 
+ * Returns:
12135
 
+ */
12136
 
+GvcMixerStream *
12137
 
+gvc_mixer_source_new (pa_context    *context,
12138
 
+                      guint          index,
12139
 
+                      GvcChannelMap *channel_map)
12140
 
+
12141
 
+{
12142
 
+        GObject *object;
12143
 
+
12144
 
+        object = g_object_new (GVC_TYPE_MIXER_SOURCE,
12145
 
+                               "pa-context", context,
12146
 
+                               "index", index,
12147
 
+                               "channel-map", channel_map,
12148
 
+                               NULL);
12149
 
+
12150
 
+        return GVC_MIXER_STREAM (object);
12151
 
+}
12152
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-source.h
12153
 
===================================================================
12154
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
12155
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-source.h      2012-08-28 17:08:49.460516899 +0200
12156
 
@@ -0,0 +1,57 @@
12157
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
12158
 
+ *
12159
 
+ * Copyright (C) 2008 Red Hat, Inc.
12160
 
+ *
12161
 
+ * This program is free software; you can redistribute it and/or modify
12162
 
+ * it under the terms of the GNU General Public License as published by
12163
 
+ * the Free Software Foundation; either version 2 of the License, or
12164
 
+ * (at your option) any later version.
12165
 
+ *
12166
 
+ * This program is distributed in the hope that it will be useful,
12167
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12168
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12169
 
+ * GNU General Public License for more details.
12170
 
+ *
12171
 
+ * You should have received a copy of the GNU General Public License
12172
 
+ * along with this program; if not, write to the Free Software
12173
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
12174
 
+ *
12175
 
+ */
12176
 
+
12177
 
+#ifndef __GVC_MIXER_SOURCE_H
12178
 
+#define __GVC_MIXER_SOURCE_H
12179
 
+
12180
 
+#include <glib-object.h>
12181
 
+#include "gvc-mixer-stream.h"
12182
 
+
12183
 
+G_BEGIN_DECLS
12184
 
+
12185
 
+#define GVC_TYPE_MIXER_SOURCE         (gvc_mixer_source_get_type ())
12186
 
+#define GVC_MIXER_SOURCE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSource))
12187
 
+#define GVC_MIXER_SOURCE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SOURCE, GvcMixerSourceClass))
12188
 
+#define GVC_IS_MIXER_SOURCE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SOURCE))
12189
 
+#define GVC_IS_MIXER_SOURCE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SOURCE))
12190
 
+#define GVC_MIXER_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSourceClass))
12191
 
+
12192
 
+typedef struct GvcMixerSourcePrivate GvcMixerSourcePrivate;
12193
 
+
12194
 
+typedef struct
12195
 
+{
12196
 
+        GvcMixerStream       parent;
12197
 
+        GvcMixerSourcePrivate *priv;
12198
 
+} GvcMixerSource;
12199
 
+
12200
 
+typedef struct
12201
 
+{
12202
 
+        GvcMixerStreamClass parent_class;
12203
 
+} GvcMixerSourceClass;
12204
 
+
12205
 
+GType               gvc_mixer_source_get_type            (void);
12206
 
+
12207
 
+GvcMixerStream *    gvc_mixer_source_new               (pa_context    *context,
12208
 
+                                                        guint          index,
12209
 
+                                                        GvcChannelMap *map);
12210
 
+
12211
 
+G_END_DECLS
12212
 
+
12213
 
+#endif /* __GVC_MIXER_SOURCE_H */
12214
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-stream-private.h
12215
 
===================================================================
12216
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
12217
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-stream-private.h      2012-08-28 17:08:49.460516899 +0200
12218
 
@@ -0,0 +1,34 @@
12219
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
12220
 
+ *
12221
 
+ * Copyright (C) 2008 Red Hat, Inc.
12222
 
+ *
12223
 
+ * This program is free software; you can redistribute it and/or modify
12224
 
+ * it under the terms of the GNU General Public License as published by
12225
 
+ * the Free Software Foundation; either version 2 of the License, or
12226
 
+ * (at your option) any later version.
12227
 
+ *
12228
 
+ * This program is distributed in the hope that it will be useful,
12229
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12230
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12231
 
+ * GNU General Public License for more details.
12232
 
+ *
12233
 
+ * You should have received a copy of the GNU General Public License
12234
 
+ * along with this program; if not, write to the Free Software
12235
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
12236
 
+ *
12237
 
+ */
12238
 
+
12239
 
+#ifndef __GVC_MIXER_STREAM_PRIVATE_H
12240
 
+#define __GVC_MIXER_STREAM_PRIVATE_H
12241
 
+
12242
 
+#include <glib-object.h>
12243
 
+
12244
 
+#include "gvc-channel-map.h"
12245
 
+
12246
 
+G_BEGIN_DECLS
12247
 
+
12248
 
+pa_context *        gvc_mixer_stream_get_pa_context  (GvcMixerStream *stream);
12249
 
+
12250
 
+G_END_DECLS
12251
 
+
12252
 
+#endif /* __GVC_MIXER_STREAM_PRIVATE_H */
12253
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-stream.c
12254
 
===================================================================
12255
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
12256
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-stream.c      2012-08-28 17:08:49.460516899 +0200
12257
 
@@ -0,0 +1,968 @@
12258
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
12259
 
+ *
12260
 
+ * Copyright (C) 2008 William Jon McCann
12261
 
+ *
12262
 
+ * This program is free software; you can redistribute it and/or modify
12263
 
+ * it under the terms of the GNU General Public License as published by
12264
 
+ * the Free Software Foundation; either version 2 of the License, or
12265
 
+ * (at your option) any later version.
12266
 
+ *
12267
 
+ * This program is distributed in the hope that it will be useful,
12268
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12269
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12270
 
+ * GNU General Public License for more details.
12271
 
+ *
12272
 
+ * You should have received a copy of the GNU General Public License
12273
 
+ * along with this program; if not, write to the Free Software
12274
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
12275
 
+ *
12276
 
+ */
12277
 
+
12278
 
+#include "config.h"
12279
 
+
12280
 
+#include <stdlib.h>
12281
 
+#include <stdio.h>
12282
 
+#include <unistd.h>
12283
 
+
12284
 
+#include <glib.h>
12285
 
+#include <glib/gi18n-lib.h>
12286
 
+
12287
 
+#include <pulse/pulseaudio.h>
12288
 
+
12289
 
+#include "gvc-mixer-stream.h"
12290
 
+#include "gvc-mixer-stream-private.h"
12291
 
+#include "gvc-channel-map-private.h"
12292
 
+
12293
 
+#define GVC_MIXER_STREAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStreamPrivate))
12294
 
+
12295
 
+static guint32 stream_serial = 1;
12296
 
+
12297
 
+struct GvcMixerStreamPrivate
12298
 
+{
12299
 
+        pa_context    *pa_context;
12300
 
+        guint          id;
12301
 
+        guint          index;
12302
 
+        gint           card_index;
12303
 
+        GvcChannelMap *channel_map;
12304
 
+        char          *name;
12305
 
+        char          *description;
12306
 
+        char          *application_id;
12307
 
+        char          *icon_name;
12308
 
+        gboolean       is_muted;
12309
 
+        gboolean       can_decibel;
12310
 
+        gboolean       is_event_stream;
12311
 
+        gboolean       is_virtual;
12312
 
+        pa_volume_t    base_volume;
12313
 
+        pa_operation  *change_volume_op;
12314
 
+        char          *port;
12315
 
+        char          *human_port;
12316
 
+        GList         *ports;
12317
 
+};
12318
 
+
12319
 
+enum
12320
 
+{
12321
 
+        PROP_0,
12322
 
+        PROP_ID,
12323
 
+        PROP_PA_CONTEXT,
12324
 
+        PROP_CHANNEL_MAP,
12325
 
+        PROP_INDEX,
12326
 
+        PROP_NAME,
12327
 
+        PROP_DESCRIPTION,
12328
 
+        PROP_APPLICATION_ID,
12329
 
+        PROP_ICON_NAME,
12330
 
+        PROP_VOLUME,
12331
 
+        PROP_DECIBEL,
12332
 
+        PROP_IS_MUTED,
12333
 
+        PROP_CAN_DECIBEL,
12334
 
+        PROP_IS_EVENT_STREAM,
12335
 
+        PROP_IS_VIRTUAL,
12336
 
+        PROP_CARD_INDEX,
12337
 
+        PROP_PORT,
12338
 
+};
12339
 
+
12340
 
+static void     gvc_mixer_stream_class_init (GvcMixerStreamClass *klass);
12341
 
+static void     gvc_mixer_stream_init       (GvcMixerStream      *mixer_stream);
12342
 
+static void     gvc_mixer_stream_finalize   (GObject            *object);
12343
 
+
12344
 
+G_DEFINE_ABSTRACT_TYPE (GvcMixerStream, gvc_mixer_stream, G_TYPE_OBJECT)
12345
 
+
12346
 
+static guint32
12347
 
+get_next_stream_serial (void)
12348
 
+{
12349
 
+        guint32 serial;
12350
 
+
12351
 
+        serial = stream_serial++;
12352
 
+
12353
 
+        if ((gint32)stream_serial < 0) {
12354
 
+                stream_serial = 1;
12355
 
+        }
12356
 
+
12357
 
+        return serial;
12358
 
+}
12359
 
+
12360
 
+pa_context *
12361
 
+gvc_mixer_stream_get_pa_context (GvcMixerStream *stream)
12362
 
+{
12363
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
12364
 
+        return stream->priv->pa_context;
12365
 
+}
12366
 
+
12367
 
+guint
12368
 
+gvc_mixer_stream_get_index (GvcMixerStream *stream)
12369
 
+{
12370
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
12371
 
+        return stream->priv->index;
12372
 
+}
12373
 
+
12374
 
+guint
12375
 
+gvc_mixer_stream_get_id (GvcMixerStream *stream)
12376
 
+{
12377
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
12378
 
+        return stream->priv->id;
12379
 
+}
12380
 
+
12381
 
+const GvcChannelMap *
12382
 
+gvc_mixer_stream_get_channel_map (GvcMixerStream *stream)
12383
 
+{
12384
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12385
 
+        return stream->priv->channel_map;
12386
 
+}
12387
 
+
12388
 
+/**
12389
 
+ * gvc_mixer_stream_get_volume:
12390
 
+ *
12391
 
+ * @stream:
12392
 
+ *
12393
 
+ * Returns: (type guint32) (transfer none):
12394
 
+ */
12395
 
+pa_volume_t
12396
 
+gvc_mixer_stream_get_volume (GvcMixerStream *stream)
12397
 
+{
12398
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
12399
 
+
12400
 
+        return (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME];
12401
 
+}
12402
 
+
12403
 
+gdouble
12404
 
+gvc_mixer_stream_get_decibel (GvcMixerStream *stream)
12405
 
+{
12406
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
12407
 
+
12408
 
+        return pa_sw_volume_to_dB(
12409
 
+                        (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME]);
12410
 
+}
12411
 
+
12412
 
+/**
12413
 
+ * gvc_mixer_stream_set_volume:
12414
 
+ *
12415
 
+ * @stream:
12416
 
+ * @volume: (type guint32):
12417
 
+ *
12418
 
+ * Returns:
12419
 
+ */
12420
 
+gboolean
12421
 
+gvc_mixer_stream_set_volume (GvcMixerStream *stream,
12422
 
+                              pa_volume_t     volume)
12423
 
+{
12424
 
+        pa_cvolume cv;
12425
 
+
12426
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12427
 
+
12428
 
+        cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map);
12429
 
+        pa_cvolume_scale(&cv, volume);
12430
 
+
12431
 
+        if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) {
12432
 
+                gvc_channel_map_volume_changed(stream->priv->channel_map, &cv, FALSE);
12433
 
+                g_object_notify (G_OBJECT (stream), "volume");
12434
 
+                return TRUE;
12435
 
+        }
12436
 
+
12437
 
+        return FALSE;
12438
 
+}
12439
 
+
12440
 
+gboolean
12441
 
+gvc_mixer_stream_set_decibel (GvcMixerStream *stream,
12442
 
+                              gdouble         db)
12443
 
+{
12444
 
+        pa_cvolume cv;
12445
 
+
12446
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12447
 
+
12448
 
+        cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map);
12449
 
+        pa_cvolume_scale(&cv, pa_sw_volume_from_dB(db));
12450
 
+
12451
 
+        if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) {
12452
 
+                gvc_channel_map_volume_changed(stream->priv->channel_map, &cv, FALSE);
12453
 
+                g_object_notify (G_OBJECT (stream), "volume");
12454
 
+        }
12455
 
+
12456
 
+        return TRUE;
12457
 
+}
12458
 
+
12459
 
+gboolean
12460
 
+gvc_mixer_stream_get_is_muted  (GvcMixerStream *stream)
12461
 
+{
12462
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12463
 
+        return stream->priv->is_muted;
12464
 
+}
12465
 
+
12466
 
+gboolean
12467
 
+gvc_mixer_stream_get_can_decibel (GvcMixerStream *stream)
12468
 
+{
12469
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12470
 
+        return stream->priv->can_decibel;
12471
 
+}
12472
 
+
12473
 
+gboolean
12474
 
+gvc_mixer_stream_set_is_muted  (GvcMixerStream *stream,
12475
 
+                                gboolean        is_muted)
12476
 
+{
12477
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12478
 
+
12479
 
+        if (is_muted != stream->priv->is_muted) {
12480
 
+                stream->priv->is_muted = is_muted;
12481
 
+                g_object_notify (G_OBJECT (stream), "is-muted");
12482
 
+        }
12483
 
+
12484
 
+        return TRUE;
12485
 
+}
12486
 
+
12487
 
+gboolean
12488
 
+gvc_mixer_stream_set_can_decibel  (GvcMixerStream *stream,
12489
 
+                                   gboolean        can_decibel)
12490
 
+{
12491
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12492
 
+
12493
 
+        if (can_decibel != stream->priv->can_decibel) {
12494
 
+                stream->priv->can_decibel = can_decibel;
12495
 
+                g_object_notify (G_OBJECT (stream), "can-decibel");
12496
 
+        }
12497
 
+
12498
 
+        return TRUE;
12499
 
+}
12500
 
+
12501
 
+const char *
12502
 
+gvc_mixer_stream_get_name (GvcMixerStream *stream)
12503
 
+{
12504
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12505
 
+        return stream->priv->name;
12506
 
+}
12507
 
+
12508
 
+const char *
12509
 
+gvc_mixer_stream_get_description (GvcMixerStream *stream)
12510
 
+{
12511
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12512
 
+        return stream->priv->description;
12513
 
+}
12514
 
+
12515
 
+gboolean
12516
 
+gvc_mixer_stream_set_name (GvcMixerStream *stream,
12517
 
+                           const char     *name)
12518
 
+{
12519
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12520
 
+
12521
 
+        g_free (stream->priv->name);
12522
 
+        stream->priv->name = g_strdup (name);
12523
 
+        g_object_notify (G_OBJECT (stream), "name");
12524
 
+
12525
 
+        return TRUE;
12526
 
+}
12527
 
+
12528
 
+gboolean
12529
 
+gvc_mixer_stream_set_description (GvcMixerStream *stream,
12530
 
+                                  const char     *description)
12531
 
+{
12532
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12533
 
+
12534
 
+        g_free (stream->priv->description);
12535
 
+        stream->priv->description = g_strdup (description);
12536
 
+        g_object_notify (G_OBJECT (stream), "description");
12537
 
+
12538
 
+        return TRUE;
12539
 
+}
12540
 
+
12541
 
+gboolean
12542
 
+gvc_mixer_stream_is_event_stream (GvcMixerStream *stream)
12543
 
+{
12544
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12545
 
+
12546
 
+        return stream->priv->is_event_stream;
12547
 
+}
12548
 
+
12549
 
+gboolean
12550
 
+gvc_mixer_stream_set_is_event_stream (GvcMixerStream *stream,
12551
 
+                                      gboolean is_event_stream)
12552
 
+{
12553
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12554
 
+
12555
 
+        stream->priv->is_event_stream = is_event_stream;
12556
 
+        g_object_notify (G_OBJECT (stream), "is-event-stream");
12557
 
+
12558
 
+        return TRUE;
12559
 
+}
12560
 
+
12561
 
+gboolean
12562
 
+gvc_mixer_stream_is_virtual (GvcMixerStream *stream)
12563
 
+{
12564
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12565
 
+
12566
 
+        return stream->priv->is_virtual;
12567
 
+}
12568
 
+
12569
 
+gboolean
12570
 
+gvc_mixer_stream_set_is_virtual (GvcMixerStream *stream,
12571
 
+                                 gboolean is_virtual)
12572
 
+{
12573
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12574
 
+
12575
 
+        stream->priv->is_virtual = is_virtual;
12576
 
+        g_object_notify (G_OBJECT (stream), "is-virtual");
12577
 
+
12578
 
+        return TRUE;
12579
 
+}
12580
 
+
12581
 
+const char *
12582
 
+gvc_mixer_stream_get_application_id (GvcMixerStream *stream)
12583
 
+{
12584
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12585
 
+        return stream->priv->application_id;
12586
 
+}
12587
 
+
12588
 
+gboolean
12589
 
+gvc_mixer_stream_set_application_id (GvcMixerStream *stream,
12590
 
+                                     const char *application_id)
12591
 
+{
12592
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12593
 
+
12594
 
+        g_free (stream->priv->application_id);
12595
 
+        stream->priv->application_id = g_strdup (application_id);
12596
 
+        g_object_notify (G_OBJECT (stream), "application-id");
12597
 
+
12598
 
+        return TRUE;
12599
 
+}
12600
 
+
12601
 
+static void
12602
 
+on_channel_map_volume_changed (GvcChannelMap  *channel_map,
12603
 
+                               gboolean        set,
12604
 
+                               GvcMixerStream *stream)
12605
 
+{
12606
 
+        if (set == TRUE)
12607
 
+                gvc_mixer_stream_push_volume (stream);
12608
 
+
12609
 
+        g_object_notify (G_OBJECT (stream), "volume");
12610
 
+}
12611
 
+
12612
 
+static gboolean
12613
 
+gvc_mixer_stream_set_channel_map (GvcMixerStream *stream,
12614
 
+                                  GvcChannelMap  *channel_map)
12615
 
+{
12616
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12617
 
+
12618
 
+        if (channel_map != NULL) {
12619
 
+                g_object_ref (channel_map);
12620
 
+        }
12621
 
+
12622
 
+        if (stream->priv->channel_map != NULL) {
12623
 
+                g_signal_handlers_disconnect_by_func (stream->priv->channel_map,
12624
 
+                                                      on_channel_map_volume_changed,
12625
 
+                                                      stream);
12626
 
+                g_object_unref (stream->priv->channel_map);
12627
 
+        }
12628
 
+
12629
 
+        stream->priv->channel_map = channel_map;
12630
 
+
12631
 
+        if (stream->priv->channel_map != NULL) {
12632
 
+                g_signal_connect (stream->priv->channel_map,
12633
 
+                                  "volume-changed",
12634
 
+                                  G_CALLBACK (on_channel_map_volume_changed),
12635
 
+                                  stream);
12636
 
+
12637
 
+                g_object_notify (G_OBJECT (stream), "channel-map");
12638
 
+        }
12639
 
+
12640
 
+        return TRUE;
12641
 
+}
12642
 
+
12643
 
+const char *
12644
 
+gvc_mixer_stream_get_icon_name (GvcMixerStream *stream)
12645
 
+{
12646
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12647
 
+        return stream->priv->icon_name;
12648
 
+}
12649
 
+
12650
 
+/**
12651
 
+ * gvc_mixer_stream_get_gicon:
12652
 
+ * @stream: a #GvcMixerStream
12653
 
+ *
12654
 
+ * Returns: (transfer full): a new #GIcon
12655
 
+ */
12656
 
+GIcon *
12657
 
+gvc_mixer_stream_get_gicon (GvcMixerStream *stream)
12658
 
+{
12659
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12660
 
+        if (stream->priv->icon_name == NULL)
12661
 
+                return NULL;
12662
 
+        return g_themed_icon_new_with_default_fallbacks (stream->priv->icon_name);
12663
 
+}
12664
 
+
12665
 
+gboolean
12666
 
+gvc_mixer_stream_set_icon_name (GvcMixerStream *stream,
12667
 
+                                const char     *icon_name)
12668
 
+{
12669
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12670
 
+
12671
 
+        g_free (stream->priv->icon_name);
12672
 
+        stream->priv->icon_name = g_strdup (icon_name);
12673
 
+        g_object_notify (G_OBJECT (stream), "icon-name");
12674
 
+
12675
 
+        return TRUE;
12676
 
+}
12677
 
+
12678
 
+/**
12679
 
+ * gvc_mixer_stream_get_base_volume:
12680
 
+ *
12681
 
+ * @stream:
12682
 
+ *
12683
 
+ * Returns: (type guint32) (transfer none):
12684
 
+ */
12685
 
+pa_volume_t
12686
 
+gvc_mixer_stream_get_base_volume (GvcMixerStream *stream)
12687
 
+{
12688
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
12689
 
+
12690
 
+        return stream->priv->base_volume;
12691
 
+}
12692
 
+
12693
 
+/**
12694
 
+ * gvc_mixer_stream_set_base_volume:
12695
 
+ *
12696
 
+ * @stream:
12697
 
+ * @base_volume: (type guint32):
12698
 
+ *
12699
 
+ * Returns:
12700
 
+ */
12701
 
+gboolean
12702
 
+gvc_mixer_stream_set_base_volume (GvcMixerStream *stream,
12703
 
+                                  pa_volume_t base_volume)
12704
 
+{
12705
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12706
 
+
12707
 
+        stream->priv->base_volume = base_volume;
12708
 
+
12709
 
+        return TRUE;
12710
 
+}
12711
 
+
12712
 
+const GvcMixerStreamPort *
12713
 
+gvc_mixer_stream_get_port (GvcMixerStream *stream)
12714
 
+{
12715
 
+        GList *l;
12716
 
+
12717
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12718
 
+        g_return_val_if_fail (stream->priv->ports != NULL, NULL);
12719
 
+
12720
 
+        for (l = stream->priv->ports; l != NULL; l = l->next) {
12721
 
+                GvcMixerStreamPort *p = l->data;
12722
 
+                if (g_strcmp0 (stream->priv->port, p->port) == 0) {
12723
 
+                        return p;
12724
 
+                }
12725
 
+        }
12726
 
+
12727
 
+        g_assert_not_reached ();
12728
 
+
12729
 
+        return NULL;
12730
 
+}
12731
 
+
12732
 
+gboolean
12733
 
+gvc_mixer_stream_set_port (GvcMixerStream *stream,
12734
 
+                           const char     *port)
12735
 
+{
12736
 
+        GList *l;
12737
 
+
12738
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12739
 
+        g_return_val_if_fail (stream->priv->ports != NULL, FALSE);
12740
 
+
12741
 
+        g_free (stream->priv->port);
12742
 
+        stream->priv->port = g_strdup (port);
12743
 
+
12744
 
+        g_free (stream->priv->human_port);
12745
 
+        stream->priv->human_port = NULL;
12746
 
+
12747
 
+        for (l = stream->priv->ports; l != NULL; l = l->next) {
12748
 
+                GvcMixerStreamPort *p = l->data;
12749
 
+                if (g_str_equal (stream->priv->port, p->port)) {
12750
 
+                        stream->priv->human_port = g_strdup (p->human_port);
12751
 
+                        break;
12752
 
+                }
12753
 
+        }
12754
 
+
12755
 
+        g_object_notify (G_OBJECT (stream), "port");
12756
 
+
12757
 
+        return TRUE;
12758
 
+}
12759
 
+
12760
 
+gboolean
12761
 
+gvc_mixer_stream_change_port (GvcMixerStream *stream,
12762
 
+                              const char     *port)
12763
 
+{
12764
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12765
 
+        return GVC_MIXER_STREAM_GET_CLASS (stream)->change_port (stream, port);
12766
 
+}
12767
 
+
12768
 
+/**
12769
 
+ * gvc_mixer_stream_get_ports:
12770
 
+ *
12771
 
+ * Return value: (transfer none) (element-type GvcMixerStreamPort):
12772
 
+ */
12773
 
+const GList *
12774
 
+gvc_mixer_stream_get_ports (GvcMixerStream *stream)
12775
 
+{
12776
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12777
 
+        return stream->priv->ports;
12778
 
+}
12779
 
+
12780
 
+static int
12781
 
+sort_ports (GvcMixerStreamPort *a,
12782
 
+            GvcMixerStreamPort *b)
12783
 
+{
12784
 
+        if (a->priority == b->priority)
12785
 
+                return 0;
12786
 
+        if (a->priority > b->priority)
12787
 
+                return 1;
12788
 
+        return -1;
12789
 
+}
12790
 
+
12791
 
+/**
12792
 
+ * gvc_mixer_stream_set_ports:
12793
 
+ * @ports: (transfer full) (element-type GvcMixerStreamPort):
12794
 
+ */
12795
 
+gboolean
12796
 
+gvc_mixer_stream_set_ports (GvcMixerStream *stream,
12797
 
+                            GList          *ports)
12798
 
+{
12799
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12800
 
+        g_return_val_if_fail (stream->priv->ports == NULL, FALSE);
12801
 
+
12802
 
+        stream->priv->ports = g_list_sort (ports, (GCompareFunc) sort_ports);
12803
 
+
12804
 
+        return TRUE;
12805
 
+}
12806
 
+
12807
 
+gint
12808
 
+gvc_mixer_stream_get_card_index (GvcMixerStream *stream)
12809
 
+{
12810
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), PA_INVALID_INDEX);
12811
 
+        return stream->priv->card_index;
12812
 
+}
12813
 
+
12814
 
+gboolean
12815
 
+gvc_mixer_stream_set_card_index (GvcMixerStream *stream,
12816
 
+                                 gint            card_index)
12817
 
+{
12818
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12819
 
+
12820
 
+        stream->priv->card_index = card_index;
12821
 
+        g_object_notify (G_OBJECT (stream), "card-index");
12822
 
+
12823
 
+        return TRUE;
12824
 
+}
12825
 
+
12826
 
+static void
12827
 
+gvc_mixer_stream_set_property (GObject       *object,
12828
 
+                               guint          prop_id,
12829
 
+                               const GValue  *value,
12830
 
+                               GParamSpec    *pspec)
12831
 
+{
12832
 
+        GvcMixerStream *self = GVC_MIXER_STREAM (object);
12833
 
+
12834
 
+        switch (prop_id) {
12835
 
+        case PROP_PA_CONTEXT:
12836
 
+                self->priv->pa_context = g_value_get_pointer (value);
12837
 
+                break;
12838
 
+        case PROP_INDEX:
12839
 
+                self->priv->index = g_value_get_ulong (value);
12840
 
+                break;
12841
 
+        case PROP_ID:
12842
 
+                self->priv->id = g_value_get_ulong (value);
12843
 
+                break;
12844
 
+        case PROP_CHANNEL_MAP:
12845
 
+                gvc_mixer_stream_set_channel_map (self, g_value_get_object (value));
12846
 
+                break;
12847
 
+        case PROP_NAME:
12848
 
+                gvc_mixer_stream_set_name (self, g_value_get_string (value));
12849
 
+                break;
12850
 
+        case PROP_DESCRIPTION:
12851
 
+                gvc_mixer_stream_set_description (self, g_value_get_string (value));
12852
 
+                break;
12853
 
+        case PROP_APPLICATION_ID:
12854
 
+                gvc_mixer_stream_set_application_id (self, g_value_get_string (value));
12855
 
+                break;
12856
 
+        case PROP_ICON_NAME:
12857
 
+                gvc_mixer_stream_set_icon_name (self, g_value_get_string (value));
12858
 
+                break;
12859
 
+        case PROP_VOLUME:
12860
 
+                gvc_mixer_stream_set_volume (self, g_value_get_ulong (value));
12861
 
+                break;
12862
 
+        case PROP_DECIBEL:
12863
 
+                gvc_mixer_stream_set_decibel (self, g_value_get_double (value));
12864
 
+                break;
12865
 
+        case PROP_IS_MUTED:
12866
 
+                gvc_mixer_stream_set_is_muted (self, g_value_get_boolean (value));
12867
 
+                break;
12868
 
+        case PROP_IS_EVENT_STREAM:
12869
 
+                gvc_mixer_stream_set_is_event_stream (self, g_value_get_boolean (value));
12870
 
+                break;
12871
 
+        case PROP_IS_VIRTUAL:
12872
 
+                gvc_mixer_stream_set_is_virtual (self, g_value_get_boolean (value));
12873
 
+                break;
12874
 
+        case PROP_CAN_DECIBEL:
12875
 
+                gvc_mixer_stream_set_can_decibel (self, g_value_get_boolean (value));
12876
 
+                break;
12877
 
+        case PROP_PORT:
12878
 
+                gvc_mixer_stream_set_port (self, g_value_get_string (value));
12879
 
+                break;
12880
 
+        case PROP_CARD_INDEX:
12881
 
+                self->priv->card_index = g_value_get_long (value);
12882
 
+                break;
12883
 
+        default:
12884
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
12885
 
+                break;
12886
 
+        }
12887
 
+}
12888
 
+
12889
 
+static void
12890
 
+gvc_mixer_stream_get_property (GObject     *object,
12891
 
+                               guint        prop_id,
12892
 
+                               GValue      *value,
12893
 
+                               GParamSpec  *pspec)
12894
 
+{
12895
 
+        GvcMixerStream *self = GVC_MIXER_STREAM (object);
12896
 
+
12897
 
+        switch (prop_id) {
12898
 
+        case PROP_PA_CONTEXT:
12899
 
+                g_value_set_pointer (value, self->priv->pa_context);
12900
 
+                break;
12901
 
+        case PROP_INDEX:
12902
 
+                g_value_set_ulong (value, self->priv->index);
12903
 
+                break;
12904
 
+        case PROP_ID:
12905
 
+                g_value_set_ulong (value, self->priv->id);
12906
 
+                break;
12907
 
+        case PROP_CHANNEL_MAP:
12908
 
+                g_value_set_object (value, self->priv->channel_map);
12909
 
+                break;
12910
 
+        case PROP_NAME:
12911
 
+                g_value_set_string (value, self->priv->name);
12912
 
+                break;
12913
 
+        case PROP_DESCRIPTION:
12914
 
+                g_value_set_string (value, self->priv->description);
12915
 
+                break;
12916
 
+        case PROP_APPLICATION_ID:
12917
 
+                g_value_set_string (value, self->priv->application_id);
12918
 
+                break;
12919
 
+        case PROP_ICON_NAME:
12920
 
+                g_value_set_string (value, self->priv->icon_name);
12921
 
+                break;
12922
 
+        case PROP_VOLUME:
12923
 
+                g_value_set_ulong (value,
12924
 
+                                   pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map)));
12925
 
+                break;
12926
 
+        case PROP_DECIBEL:
12927
 
+                g_value_set_double (value,
12928
 
+                                    pa_sw_volume_to_dB(pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map))));
12929
 
+                break;
12930
 
+        case PROP_IS_MUTED:
12931
 
+                g_value_set_boolean (value, self->priv->is_muted);
12932
 
+                break;
12933
 
+        case PROP_IS_EVENT_STREAM:
12934
 
+                g_value_set_boolean (value, self->priv->is_event_stream);
12935
 
+                break;
12936
 
+        case PROP_IS_VIRTUAL:
12937
 
+                g_value_set_boolean (value, self->priv->is_virtual);
12938
 
+                break;
12939
 
+        case PROP_CAN_DECIBEL:
12940
 
+                g_value_set_boolean (value, self->priv->can_decibel);
12941
 
+                break;
12942
 
+        case PROP_PORT:
12943
 
+                g_value_set_string (value, self->priv->port);
12944
 
+                break;
12945
 
+        case PROP_CARD_INDEX:
12946
 
+                g_value_set_long (value, self->priv->card_index);
12947
 
+                break;
12948
 
+        default:
12949
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
12950
 
+                break;
12951
 
+        }
12952
 
+}
12953
 
+
12954
 
+static GObject *
12955
 
+gvc_mixer_stream_constructor (GType                  type,
12956
 
+                              guint                  n_construct_properties,
12957
 
+                              GObjectConstructParam *construct_params)
12958
 
+{
12959
 
+        GObject       *object;
12960
 
+        GvcMixerStream *self;
12961
 
+
12962
 
+        object = G_OBJECT_CLASS (gvc_mixer_stream_parent_class)->constructor (type, n_construct_properties, construct_params);
12963
 
+
12964
 
+        self = GVC_MIXER_STREAM (object);
12965
 
+
12966
 
+        self->priv->id = get_next_stream_serial ();
12967
 
+
12968
 
+        return object;
12969
 
+}
12970
 
+
12971
 
+static gboolean
12972
 
+gvc_mixer_stream_real_change_port (GvcMixerStream *stream,
12973
 
+                                   const char     *port)
12974
 
+{
12975
 
+        return FALSE;
12976
 
+}
12977
 
+
12978
 
+static gboolean
12979
 
+gvc_mixer_stream_real_push_volume (GvcMixerStream *stream, gpointer *op)
12980
 
+{
12981
 
+        return FALSE;
12982
 
+}
12983
 
+
12984
 
+static gboolean
12985
 
+gvc_mixer_stream_real_change_is_muted (GvcMixerStream *stream,
12986
 
+                                       gboolean        is_muted)
12987
 
+{
12988
 
+        return FALSE;
12989
 
+}
12990
 
+
12991
 
+gboolean
12992
 
+gvc_mixer_stream_push_volume (GvcMixerStream *stream)
12993
 
+{
12994
 
+        pa_operation *op;
12995
 
+        gboolean ret;
12996
 
+
12997
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12998
 
+
12999
 
+        if (stream->priv->is_event_stream != FALSE)
13000
 
+                return TRUE;
13001
 
+
13002
 
+        g_debug ("Pushing new volume to stream '%s' (%s)",
13003
 
+                 stream->priv->description, stream->priv->name);
13004
 
+
13005
 
+        ret = GVC_MIXER_STREAM_GET_CLASS (stream)->push_volume (stream, (gpointer *) &op);
13006
 
+        if (ret) {
13007
 
+                if (stream->priv->change_volume_op != NULL)
13008
 
+                        pa_operation_unref (stream->priv->change_volume_op);
13009
 
+                stream->priv->change_volume_op = op;
13010
 
+        }
13011
 
+        return ret;
13012
 
+}
13013
 
+
13014
 
+gboolean
13015
 
+gvc_mixer_stream_change_is_muted (GvcMixerStream *stream,
13016
 
+                                  gboolean        is_muted)
13017
 
+{
13018
 
+        gboolean ret;
13019
 
+        g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
13020
 
+        ret = GVC_MIXER_STREAM_GET_CLASS (stream)->change_is_muted (stream, is_muted);
13021
 
+        return ret;
13022
 
+}
13023
 
+
13024
 
+gboolean
13025
 
+gvc_mixer_stream_is_running (GvcMixerStream *stream)
13026
 
+{
13027
 
+        if (stream->priv->change_volume_op == NULL)
13028
 
+                return FALSE;
13029
 
+
13030
 
+        if ((pa_operation_get_state(stream->priv->change_volume_op) == PA_OPERATION_RUNNING))
13031
 
+                return TRUE;
13032
 
+
13033
 
+        pa_operation_unref(stream->priv->change_volume_op);
13034
 
+        stream->priv->change_volume_op = NULL;
13035
 
+
13036
 
+        return FALSE;
13037
 
+}
13038
 
+
13039
 
+static void
13040
 
+gvc_mixer_stream_class_init (GvcMixerStreamClass *klass)
13041
 
+{
13042
 
+        GObjectClass   *gobject_class = G_OBJECT_CLASS (klass);
13043
 
+
13044
 
+        gobject_class->constructor = gvc_mixer_stream_constructor;
13045
 
+        gobject_class->finalize = gvc_mixer_stream_finalize;
13046
 
+        gobject_class->set_property = gvc_mixer_stream_set_property;
13047
 
+        gobject_class->get_property = gvc_mixer_stream_get_property;
13048
 
+
13049
 
+        klass->push_volume = gvc_mixer_stream_real_push_volume;
13050
 
+        klass->change_port = gvc_mixer_stream_real_change_port;
13051
 
+        klass->change_is_muted = gvc_mixer_stream_real_change_is_muted;
13052
 
+
13053
 
+        g_object_class_install_property (gobject_class,
13054
 
+                                         PROP_INDEX,
13055
 
+                                         g_param_spec_ulong ("index",
13056
 
+                                                             "Index",
13057
 
+                                                             "The index for this stream",
13058
 
+                                                             0, G_MAXULONG, 0,
13059
 
+                                                             G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
13060
 
+        g_object_class_install_property (gobject_class,
13061
 
+                                         PROP_ID,
13062
 
+                                         g_param_spec_ulong ("id",
13063
 
+                                                             "id",
13064
 
+                                                             "The id for this stream",
13065
 
+                                                             0, G_MAXULONG, 0,
13066
 
+                                                             G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
13067
 
+        g_object_class_install_property (gobject_class,
13068
 
+                                         PROP_CHANNEL_MAP,
13069
 
+                                         g_param_spec_object ("channel-map",
13070
 
+                                                              "channel map",
13071
 
+                                                              "The channel map for this stream",
13072
 
+                                                              GVC_TYPE_CHANNEL_MAP,
13073
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13074
 
+        g_object_class_install_property (gobject_class,
13075
 
+                                         PROP_PA_CONTEXT,
13076
 
+                                         g_param_spec_pointer ("pa-context",
13077
 
+                                                               "PulseAudio context",
13078
 
+                                                               "The PulseAudio context for this stream",
13079
 
+                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
13080
 
+        g_object_class_install_property (gobject_class,
13081
 
+                                         PROP_VOLUME,
13082
 
+                                         g_param_spec_ulong ("volume",
13083
 
+                                                             "Volume",
13084
 
+                                                             "The volume for this stream",
13085
 
+                                                             0, G_MAXULONG, 0,
13086
 
+                                                             G_PARAM_READWRITE));
13087
 
+        g_object_class_install_property (gobject_class,
13088
 
+                                         PROP_DECIBEL,
13089
 
+                                         g_param_spec_double ("decibel",
13090
 
+                                                              "Decibel",
13091
 
+                                                              "The decibel level for this stream",
13092
 
+                                                              -G_MAXDOUBLE, G_MAXDOUBLE, 0,
13093
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13094
 
+
13095
 
+        g_object_class_install_property (gobject_class,
13096
 
+                                         PROP_NAME,
13097
 
+                                         g_param_spec_string ("name",
13098
 
+                                                              "Name",
13099
 
+                                                              "Name to display for this stream",
13100
 
+                                                              NULL,
13101
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13102
 
+        g_object_class_install_property (gobject_class,
13103
 
+                                         PROP_DESCRIPTION,
13104
 
+                                         g_param_spec_string ("description",
13105
 
+                                                              "Description",
13106
 
+                                                              "Description to display for this stream",
13107
 
+                                                              NULL,
13108
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13109
 
+        g_object_class_install_property (gobject_class,
13110
 
+                                         PROP_APPLICATION_ID,
13111
 
+                                         g_param_spec_string ("application-id",
13112
 
+                                                              "Application identifier",
13113
 
+                                                              "Application identifier for this stream",
13114
 
+                                                              NULL,
13115
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13116
 
+        g_object_class_install_property (gobject_class,
13117
 
+                                         PROP_ICON_NAME,
13118
 
+                                         g_param_spec_string ("icon-name",
13119
 
+                                                              "Icon Name",
13120
 
+                                                              "Name of icon to display for this stream",
13121
 
+                                                              NULL,
13122
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13123
 
+        g_object_class_install_property (gobject_class,
13124
 
+                                         PROP_IS_MUTED,
13125
 
+                                         g_param_spec_boolean ("is-muted",
13126
 
+                                                               "is muted",
13127
 
+                                                               "Whether stream is muted",
13128
 
+                                                               FALSE,
13129
 
+                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13130
 
+        g_object_class_install_property (gobject_class,
13131
 
+                                         PROP_CAN_DECIBEL,
13132
 
+                                         g_param_spec_boolean ("can-decibel",
13133
 
+                                                               "can decibel",
13134
 
+                                                               "Whether stream volume can be converted to decibel units",
13135
 
+                                                               FALSE,
13136
 
+                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13137
 
+        g_object_class_install_property (gobject_class,
13138
 
+                                         PROP_IS_EVENT_STREAM,
13139
 
+                                         g_param_spec_boolean ("is-event-stream",
13140
 
+                                                               "is event stream",
13141
 
+                                                               "Whether stream's role is to play an event",
13142
 
+                                                               FALSE,
13143
 
+                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13144
 
+        g_object_class_install_property (gobject_class,
13145
 
+                                         PROP_IS_VIRTUAL,
13146
 
+                                         g_param_spec_boolean ("is-virtual",
13147
 
+                                                               "is virtual stream",
13148
 
+                                                               "Whether the stream is virtual",
13149
 
+                                                               FALSE,
13150
 
+                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13151
 
+        g_object_class_install_property (gobject_class,
13152
 
+                                         PROP_PORT,
13153
 
+                                         g_param_spec_string ("port",
13154
 
+                                                              "Port",
13155
 
+                                                              "The name of the current port for this stream",
13156
 
+                                                              NULL,
13157
 
+                                                              G_PARAM_READWRITE));
13158
 
+        g_object_class_install_property (gobject_class,
13159
 
+                                         PROP_CARD_INDEX,
13160
 
+                                         g_param_spec_long ("card-index",
13161
 
+                                                             "Card index",
13162
 
+                                                             "The index of the card for this stream",
13163
 
+                                                             PA_INVALID_INDEX, G_MAXLONG, PA_INVALID_INDEX,
13164
 
+                                                             G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13165
 
+        g_type_class_add_private (klass, sizeof (GvcMixerStreamPrivate));
13166
 
+}
13167
 
+
13168
 
+static void
13169
 
+gvc_mixer_stream_init (GvcMixerStream *stream)
13170
 
+{
13171
 
+        stream->priv = GVC_MIXER_STREAM_GET_PRIVATE (stream);
13172
 
+}
13173
 
+
13174
 
+static void
13175
 
+free_port (GvcMixerStreamPort *p)
13176
 
+{
13177
 
+        g_free (p->port);
13178
 
+        g_free (p->human_port);
13179
 
+        g_free (p);
13180
 
+}
13181
 
+
13182
 
+static void
13183
 
+gvc_mixer_stream_finalize (GObject *object)
13184
 
+{
13185
 
+        GvcMixerStream *mixer_stream;
13186
 
+
13187
 
+        g_return_if_fail (object != NULL);
13188
 
+        g_return_if_fail (GVC_IS_MIXER_STREAM (object));
13189
 
+
13190
 
+        mixer_stream = GVC_MIXER_STREAM (object);
13191
 
+
13192
 
+        g_return_if_fail (mixer_stream->priv != NULL);
13193
 
+
13194
 
+        g_object_unref (mixer_stream->priv->channel_map);
13195
 
+        mixer_stream->priv->channel_map = NULL;
13196
 
+
13197
 
+        g_free (mixer_stream->priv->name);
13198
 
+        mixer_stream->priv->name = NULL;
13199
 
+
13200
 
+        g_free (mixer_stream->priv->description);
13201
 
+        mixer_stream->priv->description = NULL;
13202
 
+
13203
 
+        g_free (mixer_stream->priv->application_id);
13204
 
+        mixer_stream->priv->application_id = NULL;
13205
 
+
13206
 
+        g_free (mixer_stream->priv->icon_name);
13207
 
+        mixer_stream->priv->icon_name = NULL;
13208
 
+
13209
 
+        g_free (mixer_stream->priv->port);
13210
 
+        mixer_stream->priv->port = NULL;
13211
 
+
13212
 
+        g_free (mixer_stream->priv->human_port);
13213
 
+        mixer_stream->priv->human_port = NULL;
13214
 
+
13215
 
+        g_list_foreach (mixer_stream->priv->ports, (GFunc) free_port, NULL);
13216
 
+        g_list_free (mixer_stream->priv->ports);
13217
 
+        mixer_stream->priv->ports = NULL;
13218
 
+
13219
 
+       if (mixer_stream->priv->change_volume_op) {
13220
 
+               pa_operation_unref(mixer_stream->priv->change_volume_op);
13221
 
+               mixer_stream->priv->change_volume_op = NULL;
13222
 
+       }
13223
 
+
13224
 
+        G_OBJECT_CLASS (gvc_mixer_stream_parent_class)->finalize (object);
13225
 
+}
13226
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-stream.h
13227
 
===================================================================
13228
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
13229
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-stream.h      2012-08-28 17:08:49.460516899 +0200
13230
 
@@ -0,0 +1,128 @@
13231
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
13232
 
+ *
13233
 
+ * Copyright (C) 2008 Red Hat, Inc.
13234
 
+ *
13235
 
+ * This program is free software; you can redistribute it and/or modify
13236
 
+ * it under the terms of the GNU General Public License as published by
13237
 
+ * the Free Software Foundation; either version 2 of the License, or
13238
 
+ * (at your option) any later version.
13239
 
+ *
13240
 
+ * This program is distributed in the hope that it will be useful,
13241
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13242
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13243
 
+ * GNU General Public License for more details.
13244
 
+ *
13245
 
+ * You should have received a copy of the GNU General Public License
13246
 
+ * along with this program; if not, write to the Free Software
13247
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
13248
 
+ *
13249
 
+ */
13250
 
+
13251
 
+#ifndef __GVC_MIXER_STREAM_H
13252
 
+#define __GVC_MIXER_STREAM_H
13253
 
+
13254
 
+#include <glib-object.h>
13255
 
+#include "gvc-pulseaudio-fake.h"
13256
 
+#include "gvc-channel-map.h"
13257
 
+#include <gio/gio.h>
13258
 
+
13259
 
+G_BEGIN_DECLS
13260
 
+
13261
 
+#define GVC_TYPE_MIXER_STREAM         (gvc_mixer_stream_get_type ())
13262
 
+#define GVC_MIXER_STREAM(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStream))
13263
 
+#define GVC_MIXER_STREAM_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_STREAM, GvcMixerStreamClass))
13264
 
+#define GVC_IS_MIXER_STREAM(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_STREAM))
13265
 
+#define GVC_IS_MIXER_STREAM_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_STREAM))
13266
 
+#define GVC_MIXER_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStreamClass))
13267
 
+
13268
 
+typedef struct GvcMixerStreamPrivate GvcMixerStreamPrivate;
13269
 
+
13270
 
+typedef struct
13271
 
+{
13272
 
+        GObject                parent;
13273
 
+        GvcMixerStreamPrivate *priv;
13274
 
+} GvcMixerStream;
13275
 
+
13276
 
+typedef struct
13277
 
+{
13278
 
+        GObjectClass           parent_class;
13279
 
+
13280
 
+        /* vtable */
13281
 
+        gboolean (*push_volume)     (GvcMixerStream *stream,
13282
 
+                                     gpointer *operation);
13283
 
+        gboolean (*change_is_muted) (GvcMixerStream *stream,
13284
 
+                                     gboolean        is_muted);
13285
 
+        gboolean (*change_port)     (GvcMixerStream *stream,
13286
 
+                                     const char     *port);
13287
 
+} GvcMixerStreamClass;
13288
 
+
13289
 
+typedef struct
13290
 
+{
13291
 
+        char *port;
13292
 
+        char *human_port;
13293
 
+        guint priority;
13294
 
+        gboolean available;        
13295
 
+} GvcMixerStreamPort;
13296
 
+
13297
 
+GType               gvc_mixer_stream_get_type        (void);
13298
 
+
13299
 
+guint               gvc_mixer_stream_get_index       (GvcMixerStream *stream);
13300
 
+guint               gvc_mixer_stream_get_id          (GvcMixerStream *stream);
13301
 
+const GvcChannelMap *gvc_mixer_stream_get_channel_map(GvcMixerStream *stream);
13302
 
+const GvcMixerStreamPort *gvc_mixer_stream_get_port  (GvcMixerStream *stream);
13303
 
+const GList *       gvc_mixer_stream_get_ports       (GvcMixerStream *stream);
13304
 
+gboolean            gvc_mixer_stream_change_port     (GvcMixerStream *stream,
13305
 
+                                                      const char     *port);
13306
 
+
13307
 
+pa_volume_t         gvc_mixer_stream_get_volume      (GvcMixerStream *stream);
13308
 
+gdouble             gvc_mixer_stream_get_decibel     (GvcMixerStream *stream);
13309
 
+gboolean            gvc_mixer_stream_push_volume     (GvcMixerStream *stream);
13310
 
+pa_volume_t         gvc_mixer_stream_get_base_volume (GvcMixerStream *stream);
13311
 
+
13312
 
+gboolean            gvc_mixer_stream_get_is_muted    (GvcMixerStream *stream);
13313
 
+gboolean            gvc_mixer_stream_get_can_decibel (GvcMixerStream *stream);
13314
 
+gboolean            gvc_mixer_stream_change_is_muted (GvcMixerStream *stream,
13315
 
+                                                      gboolean        is_muted);
13316
 
+gboolean            gvc_mixer_stream_is_running      (GvcMixerStream *stream);
13317
 
+const char *        gvc_mixer_stream_get_name        (GvcMixerStream *stream);
13318
 
+const char *        gvc_mixer_stream_get_icon_name   (GvcMixerStream *stream);
13319
 
+GIcon *             gvc_mixer_stream_get_gicon       (GvcMixerStream *stream);
13320
 
+const char *        gvc_mixer_stream_get_description (GvcMixerStream *stream);
13321
 
+const char *        gvc_mixer_stream_get_application_id (GvcMixerStream *stream);
13322
 
+gboolean            gvc_mixer_stream_is_event_stream (GvcMixerStream *stream);
13323
 
+gboolean            gvc_mixer_stream_is_virtual      (GvcMixerStream *stream);
13324
 
+gint                gvc_mixer_stream_get_card_index  (GvcMixerStream *stream);
13325
 
+
13326
 
+/* private */
13327
 
+gboolean            gvc_mixer_stream_set_volume      (GvcMixerStream *stream,
13328
 
+                                                      pa_volume_t     volume);
13329
 
+gboolean            gvc_mixer_stream_set_decibel     (GvcMixerStream *stream,
13330
 
+                                                      gdouble         db);
13331
 
+gboolean            gvc_mixer_stream_set_is_muted    (GvcMixerStream *stream,
13332
 
+                                                      gboolean        is_muted);
13333
 
+gboolean            gvc_mixer_stream_set_can_decibel (GvcMixerStream *stream,
13334
 
+                                                      gboolean        can_decibel);
13335
 
+gboolean            gvc_mixer_stream_set_name        (GvcMixerStream *stream,
13336
 
+                                                      const char     *name);
13337
 
+gboolean            gvc_mixer_stream_set_description (GvcMixerStream *stream,
13338
 
+                                                      const char     *description);
13339
 
+gboolean            gvc_mixer_stream_set_icon_name   (GvcMixerStream *stream,
13340
 
+                                                      const char     *name);
13341
 
+gboolean            gvc_mixer_stream_set_is_event_stream (GvcMixerStream *stream,
13342
 
+                                                          gboolean is_event_stream);
13343
 
+gboolean            gvc_mixer_stream_set_is_virtual  (GvcMixerStream *stream,
13344
 
+                                                      gboolean is_event_stream);
13345
 
+gboolean            gvc_mixer_stream_set_application_id (GvcMixerStream *stream,
13346
 
+                                                         const char *application_id);
13347
 
+gboolean            gvc_mixer_stream_set_base_volume (GvcMixerStream *stream,
13348
 
+                                                      pa_volume_t     base_volume);
13349
 
+gboolean            gvc_mixer_stream_set_port        (GvcMixerStream *stream,
13350
 
+                                                      const char     *port);
13351
 
+gboolean            gvc_mixer_stream_set_ports       (GvcMixerStream *stream,
13352
 
+                                                      GList          *ports);
13353
 
+gboolean            gvc_mixer_stream_set_card_index  (GvcMixerStream *stream,
13354
 
+                                                      gint            card_index);
13355
 
+
13356
 
+G_END_DECLS
13357
 
+
13358
 
+#endif /* __GVC_MIXER_STREAM_H */
13359
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-ui-device.c
13360
 
===================================================================
13361
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
13362
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-ui-device.c   2012-08-28 17:08:49.460516899 +0200
13363
 
@@ -0,0 +1,664 @@
13364
 
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
13365
 
+/*
13366
 
+ * gvc-mixer-ui-device.c
13367
 
+ * Copyright (C) Conor Curran 2011 <conor.curran@canonical.com>
13368
 
+ * 
13369
 
+ * gvc-mixer-ui-device.c is free software: you can redistribute it and/or modify it
13370
 
+ * under the terms of the GNU General Public License as published by the
13371
 
+ * Free Software Foundation, either version 3 of the License, or
13372
 
+ * (at your option) any later version.
13373
 
+ * 
13374
 
+ * gvc-mixer-ui-device.c is distributed in the hope that it will be useful, but
13375
 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
13376
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13377
 
+ * See the GNU General Public License for more details.
13378
 
+ * 
13379
 
+ * You should have received a copy of the GNU General Public License along
13380
 
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
13381
 
+ */
13382
 
+
13383
 
+#include <string.h>
13384
 
+#include "gvc-mixer-ui-device.h"
13385
 
+#include "gvc-mixer-card.h"
13386
 
+
13387
 
+#define GVC_MIXER_UI_DEVICE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GVC_TYPE_MIXER_UI_DEVICE, GvcMixerUIDevicePrivate))
13388
 
+
13389
 
+static guint32 output_serial = 1;
13390
 
+
13391
 
+struct GvcMixerUIDevicePrivate
13392
 
+{
13393
 
+       gchar*                  first_line_desc;
13394
 
+       gchar*                  second_line_desc;
13395
 
+       gint                    card_id; 
13396
 
+       gchar*                  port_name;
13397
 
+       gint                    stream_id;
13398
 
+       guint                   id;
13399
 
+       gboolean                port_available;
13400
 
+       GList*                  supported_profiles;
13401
 
+       UiDeviceDirection       type;
13402
 
+       GHashTable*             profiles;
13403
 
+       gboolean                disable_profile_swapping;
13404
 
+       gchar*                  user_preferred_profile;
13405
 
+};
13406
 
+
13407
 
+enum
13408
 
+{
13409
 
+       PROP_0,
13410
 
+       PROP_DESC_LINE_1,
13411
 
+       PROP_DESC_LINE_2,
13412
 
+       PROP_CARD_ID,
13413
 
+       PROP_PORT_NAME, 
13414
 
+       PROP_STREAM_ID,
13415
 
+       PROP_UI_DEVICE_TYPE,
13416
 
+       PROP_PORT_AVAILABLE,
13417
 
+};
13418
 
+
13419
 
+static void     gvc_mixer_ui_device_class_init (GvcMixerUIDeviceClass *klass);
13420
 
+static void     gvc_mixer_ui_device_init       (GvcMixerUIDevice      *op);
13421
 
+static void     gvc_mixer_ui_device_finalize   (GObject             *object);
13422
 
+
13423
 
+G_DEFINE_TYPE (GvcMixerUIDevice, gvc_mixer_ui_device, G_TYPE_OBJECT);
13424
 
+
13425
 
+static guint32
13426
 
+get_next_output_serial (void)
13427
 
+{
13428
 
+        guint32 serial;
13429
 
+
13430
 
+        serial = output_serial++;
13431
 
+
13432
 
+        if ((gint32)output_serial < 0) {
13433
 
+                output_serial = 1;
13434
 
+        }
13435
 
+        return serial;
13436
 
+}
13437
 
+
13438
 
+static void
13439
 
+gvc_mixer_ui_device_get_property  (GObject       *object,
13440
 
+                                  guint         property_id,
13441
 
+                                  GValue        *value,
13442
 
+                                  GParamSpec    *pspec)
13443
 
+{
13444
 
+         GvcMixerUIDevice *self = GVC_MIXER_UI_DEVICE (object);
13445
 
+
13446
 
+         switch (property_id)
13447
 
+               {
13448
 
+               case PROP_DESC_LINE_1:
13449
 
+                       g_value_set_string (value, self->priv->first_line_desc);
13450
 
+                       break;
13451
 
+               case PROP_DESC_LINE_2:
13452
 
+                       g_value_set_string (value, self->priv->second_line_desc);
13453
 
+                       break;
13454
 
+               case PROP_CARD_ID:
13455
 
+                       g_value_set_int (value, self->priv->card_id);
13456
 
+                       break;
13457
 
+               case PROP_PORT_NAME:
13458
 
+                       g_value_set_string (value, self->priv->port_name);
13459
 
+                       break;
13460
 
+               case PROP_STREAM_ID:
13461
 
+                       g_value_set_int (value, self->priv->stream_id);
13462
 
+                       break;
13463
 
+               case PROP_UI_DEVICE_TYPE:
13464
 
+                       g_value_set_uint (value, (guint)self->priv->type);
13465
 
+                       break;
13466
 
+               case PROP_PORT_AVAILABLE:
13467
 
+                       g_value_set_boolean (value, self->priv->port_available);
13468
 
+                       break;
13469
 
+               default:
13470
 
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
13471
 
+                       break;
13472
 
+               }
13473
 
+}
13474
 
+
13475
 
+static void
13476
 
+gvc_mixer_ui_device_set_property  (GObject      *object,
13477
 
+                               guint         property_id,
13478
 
+                               const GValue *value,
13479
 
+                               GParamSpec   *pspec)
13480
 
+{
13481
 
+         GvcMixerUIDevice *self = GVC_MIXER_UI_DEVICE (object);
13482
 
+
13483
 
+         switch (property_id)
13484
 
+               {
13485
 
+               case PROP_DESC_LINE_1:
13486
 
+                       g_free (self->priv->first_line_desc);
13487
 
+                       self->priv->first_line_desc = g_value_dup_string (value);
13488
 
+                       g_debug ("gvc-mixer-output-set-property - 1st line: %s\n",
13489
 
+                                self->priv->first_line_desc);
13490
 
+                       break;
13491
 
+               case PROP_DESC_LINE_2:
13492
 
+                       g_free (self->priv->second_line_desc);
13493
 
+                       self->priv->second_line_desc = g_value_dup_string (value);
13494
 
+                       g_debug ("gvc-mixer-output-set-property - 2nd line: %s\n",
13495
 
+                                self->priv->second_line_desc);
13496
 
+                       break;  
13497
 
+               case PROP_CARD_ID:
13498
 
+                       self->priv->card_id = g_value_get_int (value);
13499
 
+                       g_debug ("gvc-mixer-output-set-property - card id: %i\n",
13500
 
+                                self->priv->card_id);
13501
 
+                       break;  
13502
 
+               case PROP_PORT_NAME:
13503
 
+                       g_free (self->priv->port_name);
13504
 
+                       self->priv->port_name = g_value_dup_string (value);
13505
 
+                       g_debug ("gvc-mixer-output-set-property - card port name: %s\n",
13506
 
+                                self->priv->port_name);
13507
 
+                       break;  
13508
 
+               case PROP_STREAM_ID:
13509
 
+                       self->priv->stream_id = g_value_get_int (value);
13510
 
+                       g_debug ("gvc-mixer-output-set-property - sink id: %i\n",
13511
 
+                                self->priv->stream_id);
13512
 
+                       break;  
13513
 
+               case PROP_UI_DEVICE_TYPE:
13514
 
+                       self->priv->type = (UiDeviceDirection)g_value_get_uint (value);
13515
 
+                       break;
13516
 
+               case PROP_PORT_AVAILABLE:
13517
 
+                       self->priv->port_available = g_value_get_boolean (value);
13518
 
+                       g_debug ("gvc-mixer-output-set-property - port available %i, value passed in %i \n",
13519
 
+                                self->priv->port_available, g_value_get_boolean (value));
13520
 
+                       break;                  
13521
 
+               default:
13522
 
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
13523
 
+                       break;
13524
 
+           }
13525
 
+}
13526
 
+
13527
 
+static GObject *
13528
 
+gvc_mixer_ui_device_constructor (GType                  type,
13529
 
+                                guint                  n_construct_properties,
13530
 
+                                GObjectConstructParam *construct_params)
13531
 
+{
13532
 
+        GObject         *object;
13533
 
+        GvcMixerUIDevice  *self;
13534
 
+
13535
 
+        object = G_OBJECT_CLASS (gvc_mixer_ui_device_parent_class)->constructor (type, n_construct_properties, construct_params);
13536
 
+
13537
 
+        self = GVC_MIXER_UI_DEVICE (object);
13538
 
+        self->priv->id = get_next_output_serial ();
13539
 
+        self->priv->profiles = g_hash_table_new_full (g_str_hash,
13540
 
+                                                     g_str_equal,
13541
 
+                                                     g_free,
13542
 
+                                                     NULL);
13543
 
+       self->priv->stream_id = GVC_MIXER_UI_DEVICE_INVALID;
13544
 
+       self->priv->card_id = GVC_MIXER_UI_DEVICE_INVALID;
13545
 
+       self->priv->port_name = NULL;
13546
 
+       self->priv->disable_profile_swapping = FALSE;
13547
 
+       self->priv->user_preferred_profile = NULL;
13548
 
+        return object;
13549
 
+}
13550
 
+
13551
 
+static void
13552
 
+gvc_mixer_ui_device_init (GvcMixerUIDevice *object)
13553
 
+{
13554
 
+       object->priv  = GVC_MIXER_UI_DEVICE_GET_PRIVATE (object);       
13555
 
+}
13556
 
+
13557
 
+static void 
13558
 
+gvc_mixer_ui_device_dispose (GObject *object)
13559
 
+{
13560
 
+        g_return_if_fail (object != NULL);
13561
 
+        g_return_if_fail (GVC_MIXER_UI_DEVICE (object));
13562
 
+
13563
 
+       GvcMixerUIDevice *device;
13564
 
+       device = GVC_MIXER_UI_DEVICE (object);
13565
 
+       
13566
 
+       if (device->priv->port_name != NULL){
13567
 
+               g_free (device->priv->port_name);
13568
 
+               device->priv->port_name = NULL;
13569
 
+       }
13570
 
+       if (device->priv->first_line_desc != NULL){             
13571
 
+               g_free (device->priv->first_line_desc);
13572
 
+               device->priv->first_line_desc = NULL;
13573
 
+       }
13574
 
+       if (device->priv->second_line_desc != NULL){
13575
 
+               g_free (device->priv->second_line_desc);
13576
 
+               device->priv->second_line_desc = NULL;
13577
 
+       }
13578
 
+       if (device->priv->profiles != NULL){
13579
 
+               g_hash_table_destroy (device->priv->profiles);
13580
 
+               device->priv->profiles = NULL;
13581
 
+       }
13582
 
+       if (device->priv->user_preferred_profile != NULL){
13583
 
+               g_free (device->priv->user_preferred_profile);
13584
 
+               device->priv->user_preferred_profile = NULL;
13585
 
+       }
13586
 
+    G_OBJECT_CLASS (gvc_mixer_ui_device_parent_class)->dispose (object);       
13587
 
+}
13588
 
+
13589
 
+static void
13590
 
+gvc_mixer_ui_device_finalize (GObject *object)
13591
 
+{
13592
 
+       G_OBJECT_CLASS (gvc_mixer_ui_device_parent_class)->finalize (object);
13593
 
+}
13594
 
+
13595
 
+static void
13596
 
+gvc_mixer_ui_device_class_init (GvcMixerUIDeviceClass *klass)
13597
 
+{
13598
 
+       GObjectClass* object_class = G_OBJECT_CLASS (klass);
13599
 
+
13600
 
+       object_class->constructor = gvc_mixer_ui_device_constructor;
13601
 
+       object_class->dispose = gvc_mixer_ui_device_dispose;        
13602
 
+       object_class->finalize = gvc_mixer_ui_device_finalize;
13603
 
+       object_class->set_property = gvc_mixer_ui_device_set_property;
13604
 
+       object_class->get_property = gvc_mixer_ui_device_get_property;
13605
 
+
13606
 
+       GParamSpec *pspec;
13607
 
+
13608
 
+       pspec = g_param_spec_string ("description",
13609
 
+                               "Description construct prop",
13610
 
+                               "Set first line description",
13611
 
+                               "no-name-set",
13612
 
+                               G_PARAM_READWRITE);
13613
 
+       g_object_class_install_property (object_class,
13614
 
+                                        PROP_DESC_LINE_1,
13615
 
+                                        pspec);        
13616
 
+                                
13617
 
+       pspec = g_param_spec_string ("origin",
13618
 
+                                "origin construct prop",
13619
 
+                                "Set second line description name",
13620
 
+                                "no-name-set",
13621
 
+                                 G_PARAM_READWRITE);
13622
 
+       g_object_class_install_property (object_class,
13623
 
+                                       PROP_DESC_LINE_2,
13624
 
+                                       pspec); 
13625
 
+
13626
 
+       pspec = g_param_spec_int ("card-id",
13627
 
+                                 "Card id from pulse",
13628
 
+                                 "Set/Get card id",
13629
 
+                                 -1 ,
13630
 
+                                 1000 ,
13631
 
+                                 GVC_MIXER_UI_DEVICE_INVALID,
13632
 
+                                 G_PARAM_READWRITE);
13633
 
+
13634
 
+       g_object_class_install_property (object_class,
13635
 
+                                        PROP_CARD_ID,
13636
 
+                                        pspec);
13637
 
+                                                                
13638
 
+       pspec = g_param_spec_string ("port-name",
13639
 
+                                "port-name construct prop",
13640
 
+                                "Set port-name",
13641
 
+                                NULL,
13642
 
+                                G_PARAM_READWRITE);
13643
 
+       g_object_class_install_property (object_class,
13644
 
+                                        PROP_PORT_NAME,
13645
 
+                                        pspec);        
13646
 
+
13647
 
+       pspec = g_param_spec_int ("stream-id",
13648
 
+                                 "stream id assigned by gvc-stream",
13649
 
+                                 "Set/Get stream id",
13650
 
+                                 -1,  
13651
 
+                                  10000, 
13652
 
+                                  GVC_MIXER_UI_DEVICE_INVALID,
13653
 
+                                  G_PARAM_READWRITE);
13654
 
+       g_object_class_install_property (object_class,
13655
 
+                                        PROP_STREAM_ID,
13656
 
+                                        pspec);
13657
 
+
13658
 
+       pspec = g_param_spec_uint ("type",
13659
 
+                                  "ui-device type",
13660
 
+                                  "determine whether its an input and output",
13661
 
+                               0,
13662
 
+                                   1,
13663
 
+                                   0,
13664
 
+                                   G_PARAM_READWRITE);
13665
 
+       g_object_class_install_property (object_class,
13666
 
+                                        PROP_UI_DEVICE_TYPE,
13667
 
+                                        pspec);
13668
 
+
13669
 
+       pspec = g_param_spec_boolean ( "port-available",
13670
 
+                                       "available",
13671
 
+                                       "determine whether this port is available",
13672
 
+                                       FALSE,
13673
 
+                                       G_PARAM_READWRITE);                                    
13674
 
+       g_object_class_install_property (object_class,
13675
 
+                                       PROP_PORT_AVAILABLE,
13676
 
+                                       pspec);        
13677
 
+                                
13678
 
+       g_type_class_add_private (klass, sizeof (GvcMixerUIDevicePrivate));                                                                     
13679
 
+}
13680
 
+
13681
 
+/*
13682
 
+ gvc_mixer_ui_device_set_profiles (GvcMixerUIDevice *device, const GList *in_profiles)
13683
 
+
13684
 
+ This method attempts to reduce the list of profiles visible to the user by figuring out 
13685
 
+ from the context of that device (whether it's an input or an output) what profiles actually provide an alternative.
13686
 
13687
 
+ It does this by the following.
13688
 
+  - It ignores off profiles.
13689
 
+  - Sorts the incoming profiles by attempting to split each profile on the char '+'.
13690
 
+     -- This will pull out the relevant aspect of the profile for the type of device this is.
13691
 
+        e.g stereo analog out, bluetooth or HDMI for an output, stereo analog in or bluetooth for the input coming from  
13692
 
+        a typical setup of a onboard HDA intel card and bluetooth headset.
13693
 
+     -- Will store this shortened string against the profile full length name.
13694
 
13695
 
+  - Next it tries to determine from our prepared hash above if we want to allow the user to change
13696
 
+    the profile on the device i.e.  if the profile combo should be visible to the user on the UI.
13697
 
+    -- Is there any actual choice or just much of the same thing from the 
13698
 
+       context of the direction on this device.
13699
 
+  -If there is a choice
13700
 
+    -- It will gather the groups of identical profiles and choose the one that has the highest priority to insert
13701
 
+       into the final list to be presented to the user.
13702
 
+    - if the shortened profiles are identical so that the profile combo is to be hidden from the user
13703
 
+     -- It will choose the profile with the highest priority. (the pattern assumes a device will always have a profile in it's profile list)
13704
 
+Note: 
13705
 
+ I think this algorithm is inherently flawed.
13706
 
+ https://bugs.launchpad.net/ubuntu/+source/gnome-control-center/+bug/972554
13707
 
+ An issue arises in this bug whereby the user needs to get at a specific profile which allows him a certain input and output
13708
 
+ configuration. But this algorithem because of priority values etc will reject that one profile that he needs to get at. 
13709
 
+TODO
13710
 
+ Optimise so as on the first pass you can 'choose' which profiles to hold on to and
13711
 
+ which are useles because they are essentially duplicates.
13712
 
+ => a depthfirst like approach is needed ...
13713
 
+*/
13714
 
+
13715
 
+
13716
 
+/**
13717
 
+ * get_profile_canonical_name - removes the part of the string that starts with
13718
 
+ * skip_prefix, i e corresponding to the other direction. Normally either
13719
 
+ * "input:" or "output:"
13720
 
+ * @returns string must be freed by user 
13721
 
+ */
13722
 
+static gchar *
13723
 
+get_profile_canonical_name(const gchar *profile_name, const gchar *skip_prefix)
13724
 
+{
13725
 
+    gchar *result = g_strdup(profile_name);
13726
 
+    gchar *c = result;
13727
 
+   
13728
 
+    while (*c) {
13729
 
+        /* Find '\0' or past next '+' */
13730
 
+        gchar *d = c;
13731
 
+        while (*d) {
13732
 
+            if (*d == '+') {
13733
 
+               d++;
13734
 
+               break;
13735
 
+            }
13736
 
+            d++;
13737
 
+        }
13738
 
+
13739
 
+        if (g_str_has_prefix(c, skip_prefix)) {
13740
 
+            /* It's the other direction, so remove it from result */
13741
 
+            gchar *newresult;
13742
 
+            int i = c - result;
13743
 
+            result[i] = '\0';
13744
 
+            newresult = g_strjoin("", result, d, NULL);
13745
 
+            g_free(result);
13746
 
+            result = newresult;
13747
 
+            c = result + i; 
13748
 
+        }
13749
 
+        else 
13750
 
+            c = d;
13751
 
+    }
13752
 
+    
13753
 
+    /* Cut a final '+' off */
13754
 
+    if (g_str_has_suffix(result, "+"))
13755
 
+        result[strlen(result)-1] = '\0';
13756
 
+
13757
 
+    return result;
13758
 
+}
13759
 
+
13760
 
+const gchar*
13761
 
+gvc_mixer_ui_device_get_matching_profile (GvcMixerUIDevice *device, const gchar *profile)
13762
 
+{
13763
 
+       gchar *skip_prefix = device->priv->type == UiDeviceInput ? "output:" : "input:";
13764
 
+       gchar *target_cname = get_profile_canonical_name(profile, skip_prefix);
13765
 
+       GList *t, *values = g_hash_table_get_values(device->priv->profiles);
13766
 
+       gchar *result = NULL;
13767
 
+
13768
 
+       for (t = values; t != NULL; t = t->next) {
13769
 
+               GvcMixerCardProfile* p = t->data;
13770
 
+               gchar *canonical_name = get_profile_canonical_name(p->profile, skip_prefix);
13771
 
+        g_debug("analysing %s", p->profile);
13772
 
+               if (!strcmp(canonical_name, target_cname)) {
13773
 
+                       result = p->profile;
13774
 
+               }
13775
 
+               g_free(canonical_name);
13776
 
+    }
13777
 
+
13778
 
+       g_free(target_cname);
13779
 
+       g_debug("Matching profile for '%s' is '%s'", profile, result ? result : "(null)");
13780
 
+       return result;
13781
 
+}
13782
 
+
13783
 
+
13784
 
+/** gvc_mixer_ui_device_set_profiles
13785
 
+   @param in_profiles a list of GvcMixerCardProfile
13786
 
+   assigns value to
13787
 
+    * device->priv->profiles (profiles to be added to combobox)
13788
 
+    * device->priv->supported_profiles (all profiles of this port)
13789
 
+    * device->priv->disable_profile_swapping (whether to show the combobox)
13790
 
+*/
13791
 
+void
13792
 
+gvc_mixer_ui_device_set_profiles (GvcMixerUIDevice *device, const GList *in_profiles)
13793
 
+{
13794
 
+       g_debug ("=== SET PROFILES === '%s'", gvc_mixer_ui_device_get_description(device));
13795
 
+               
13796
 
+       GList* t;
13797
 
+       GHashTable *profile_descriptions;
13798
 
+       GHashTable *added_profiles; 
13799
 
+       int only_canonical;
13800
 
+       gchar *skip_prefix = device->priv->type == UiDeviceInput ? "output:" : "input:";
13801
 
+       
13802
 
+       if (in_profiles == NULL)
13803
 
+               return;
13804
 
+
13805
 
+       device->priv->supported_profiles = g_list_copy ((GList*) in_profiles);
13806
 
+
13807
 
+       added_profiles = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
13808
 
+    
13809
 
+       /* Run two iterations: First, add profiles which are canonical themselves,
13810
 
+          Second, add profiles for which the canonical name is not added already 
13811
 
+       */
13812
 
+       for (only_canonical = 1; only_canonical >= 0; only_canonical--) {
13813
 
+       for (t = (GList *) in_profiles; t != NULL; t = t->next) {
13814
 
+                       GvcMixerCardProfile* p = t->data;
13815
 
+                       gchar *canonical_name = get_profile_canonical_name(p->profile, skip_prefix);
13816
 
+                       g_debug("The canonical name for '%s' is '%s'", p->profile, canonical_name);
13817
 
+
13818
 
+                       /* Have we already added the canonical version of this profile? */
13819
 
+                       if (g_hash_table_contains(added_profiles, canonical_name)) {
13820
 
+                               g_free(canonical_name);
13821
 
+                               continue;
13822
 
+                       }
13823
 
+
13824
 
+                       if (only_canonical && strcmp(p->profile, canonical_name)) {
13825
 
+                               g_free(canonical_name);
13826
 
+                               continue;
13827
 
+            }
13828
 
+
13829
 
+                       g_free(canonical_name);
13830
 
+
13831
 
+                       g_debug("Adding profile to combobox: '%s' - '%s'", p->profile, p->human_profile);
13832
 
+            g_hash_table_insert(added_profiles, g_strdup(p->profile), p);
13833
 
+            g_hash_table_insert(device->priv->profiles, g_strdup(p->human_profile), p);
13834
 
+        }
13835
 
+    }
13836
 
+
13837
 
+    /* TODO: Consider adding the "Off" profile here */
13838
 
+
13839
 
+       device->priv->disable_profile_swapping = g_hash_table_size(added_profiles) <= 1;
13840
 
+    
13841
 
+    g_hash_table_destroy(added_profiles);
13842
 
+}
13843
 
+
13844
 
+/** gvc_mixer_ui_device_get_best_profile
13845
 
+  * @param selected the selected profile or its canonical name - can be NULL
13846
 
+  * if any profile is okay
13847
 
+  * @param current the currently selected profile
13848
 
+  * @returns a profile name, does not need to be freed, valid as long as the 
13849
 
+  * ui device profiles are
13850
 
+  */
13851
 
+const gchar*                   
13852
 
+gvc_mixer_ui_device_get_best_profile (GvcMixerUIDevice *device, const gchar *selected, 
13853
 
+const gchar *current)
13854
 
+{
13855
 
+       GList *t;
13856
 
+       GList *candidates = NULL;
13857
 
+       const gchar *result = NULL;
13858
 
+       gchar *skip_prefix = device->priv->type == UiDeviceInput ? "output:" : "input:";
13859
 
+    gchar *canonical_name_selected = NULL;
13860
 
+
13861
 
+       /* First make a list of profiles acceptable to switch to */
13862
 
+       if (selected) 
13863
 
+               canonical_name_selected = get_profile_canonical_name(selected, skip_prefix);
13864
 
+
13865
 
+       for (t = device->priv->supported_profiles; t != NULL; t = t->next) {
13866
 
+               GvcMixerCardProfile* p = t->data;
13867
 
+               gchar *canonical_name = get_profile_canonical_name(p->profile, skip_prefix);
13868
 
+               if (!canonical_name_selected || !strcmp(canonical_name, canonical_name_selected)) {
13869
 
+                       candidates = g_list_append(candidates, p);
13870
 
+                       g_debug("Candidate for profile switching: '%s'", p->profile);
13871
 
+               }
13872
 
+       }
13873
 
+
13874
 
+       if (!candidates) {
13875
 
+               g_warning("No suitable profile candidates for '%s'", selected ? selected : "(null)");
13876
 
+               g_free(canonical_name_selected);
13877
 
+               return current; 
13878
 
+       }
13879
 
+
13880
 
+       /* 1) Maybe we can skip profile switching altogether? */
13881
 
+       for (t = candidates; (result == NULL) && (t != NULL); t = t->next) {
13882
 
+               GvcMixerCardProfile* p = t->data;               
13883
 
+               if (!strcmp(current, p->profile))
13884
 
+                       result = p->profile;
13885
 
+       }
13886
 
+
13887
 
+       /* 2) Try to keep the other side unchanged if possible */
13888
 
+       if (result == NULL) {
13889
 
+               guint prio = 0;
13890
 
+               gchar *skip_prefix_reverse = device->priv->type == UiDeviceInput ? "input:" : "output:";
13891
 
+               gchar *current_reverse = get_profile_canonical_name(current, skip_prefix_reverse);
13892
 
+               for (t = candidates; t != NULL; t = t->next) {
13893
 
+                       GvcMixerCardProfile* p = t->data;
13894
 
+                       gchar *p_reverse = get_profile_canonical_name(p->profile, skip_prefix_reverse);
13895
 
+                       g_debug("Comparing '%s' (from '%s') with '%s', prio %d", p_reverse, p->profile, current_reverse, p->priority); 
13896
 
+                       if (!strcmp(p_reverse, current_reverse) && (!result || p->priority > prio)) {
13897
 
+                               result = p->profile;
13898
 
+                               prio = p->priority;
13899
 
+                       }
13900
 
+                       g_free(p_reverse);
13901
 
+               }
13902
 
+               g_free(current_reverse);
13903
 
+       }
13904
 
+
13905
 
+       /* 3) All right, let's just pick the profile with highest priority. 
13906
 
+               TODO: We could consider asking a GUI question if this stops streams 
13907
 
+               in the other direction */
13908
 
+       if (result == NULL) {
13909
 
+               guint prio = 0;
13910
 
+               for (t = candidates; t != NULL; t = t->next) {
13911
 
+                       GvcMixerCardProfile* p = t->data;
13912
 
+                       if ((p->priority > prio) || !result) {
13913
 
+                               result = p->profile;
13914
 
+                               prio = p->priority;
13915
 
+                       }
13916
 
+               }
13917
 
+       }
13918
 
+
13919
 
+       g_list_free(candidates);
13920
 
+       g_free(canonical_name_selected);
13921
 
+       return result;
13922
 
+}
13923
 
+
13924
 
+
13925
 
+gboolean
13926
 
+gvc_mixer_ui_device_should_profiles_be_hidden (GvcMixerUIDevice *device)
13927
 
+{
13928
 
+       return device->priv->disable_profile_swapping;
13929
 
+}
13930
 
+
13931
 
+GHashTable*
13932
 
+gvc_mixer_ui_device_get_profiles (GvcMixerUIDevice *device)
13933
 
+{
13934
 
+       return device->priv->profiles; 
13935
 
+}
13936
 
+
13937
 
+GList*
13938
 
+gvc_mixer_ui_device_get_supported_profiles (GvcMixerUIDevice *device)
13939
 
+{
13940
 
+       return device->priv->supported_profiles;
13941
 
+}
13942
 
+
13943
 
+guint
13944
 
+gvc_mixer_ui_device_get_id (GvcMixerUIDevice *op)
13945
 
+{
13946
 
+        g_return_val_if_fail (GVC_IS_MIXER_UI_DEVICE (op), 0);
13947
 
+        return op->priv->id;
13948
 
+}
13949
 
+
13950
 
+gint
13951
 
+gvc_mixer_ui_device_get_stream_id (GvcMixerUIDevice *op)
13952
 
+{
13953
 
+       gint sink_id;
13954
 
+       g_object_get (G_OBJECT (op),
13955
 
+                     "stream-id", &sink_id, NULL);
13956
 
+        return sink_id;                        
13957
 
+}
13958
 
+
13959
 
+void                                   
13960
 
+gvc_mixer_ui_device_invalidate_stream (GvcMixerUIDevice *self)
13961
 
+{
13962
 
+       self->priv->stream_id = GVC_MIXER_UI_DEVICE_INVALID;
13963
 
+}
13964
 
+
13965
 
+
13966
 
+const gchar*
13967
 
+gvc_mixer_ui_device_get_description (GvcMixerUIDevice *op)
13968
 
+{
13969
 
+       return op->priv->first_line_desc;
13970
 
+}
13971
 
+
13972
 
+const gchar*
13973
 
+gvc_mixer_ui_device_get_origin (GvcMixerUIDevice *op)
13974
 
+{
13975
 
+       return op->priv->second_line_desc;
13976
 
+}
13977
 
+
13978
 
+const gchar*
13979
 
+gvc_mixer_ui_device_get_user_preferred_profile (GvcMixerUIDevice *dev)
13980
 
+{
13981
 
+       return dev->priv->user_preferred_profile;
13982
 
+}
13983
 
+
13984
 
+const gchar*
13985
 
+gvc_mixer_ui_device_get_top_priority_profile (GvcMixerUIDevice *dev)
13986
 
+{
13987
 
+       GList *last;
13988
 
+       last = g_list_last (dev->priv->supported_profiles);
13989
 
+       GvcMixerCardProfile *profile;
13990
 
+       profile = last->data;                        
13991
 
+       return profile->profile;
13992
 
+}
13993
 
+
13994
 
+void 
13995
 
+gvc_mixer_ui_device_set_user_preferred_profile (GvcMixerUIDevice *device, const gchar* profile)
13996
 
+{
13997
 
+       if (device->priv->user_preferred_profile != NULL){
13998
 
+               g_free (device->priv->user_preferred_profile);
13999
 
+               device->priv->user_preferred_profile = NULL;
14000
 
+       }
14001
 
+       device->priv->user_preferred_profile = g_strdup (profile);
14002
 
+}
14003
 
+
14004
 
+const gchar*
14005
 
+gvc_mixer_ui_device_get_port (GvcMixerUIDevice *op)
14006
 
+{
14007
 
+       return op->priv->port_name;
14008
 
+}
14009
 
+
14010
 
+gboolean
14011
 
+gvc_mixer_ui_device_is_software (GvcMixerUIDevice *dev)
14012
 
+{
14013
 
+       return dev->priv->port_name == NULL && dev->priv->card_id == GVC_MIXER_UI_DEVICE_INVALID;
14014
 
+}
14015
 
+
14016
 
+gboolean
14017
 
+gvc_mixer_ui_device_is_bluetooth (GvcMixerUIDevice *dev)
14018
 
+{
14019
 
+       return dev->priv->port_name == NULL && dev->priv->card_id != GVC_MIXER_UI_DEVICE_INVALID;       
14020
 
+}
14021
 
+
14022
 
+gboolean
14023
 
+gvc_mixer_ui_device_is_output (GvcMixerUIDevice *dev)
14024
 
+{
14025
 
+       return dev->priv->type == UiDeviceOutput;       
14026
 
+}
14027
 
+
14028
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-ui-device.h
14029
 
===================================================================
14030
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
14031
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-mixer-ui-device.h   2012-08-28 17:08:49.464516900 +0200
14032
 
@@ -0,0 +1,76 @@
14033
 
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
14034
 
+/*
14035
 
+ * Copyright (C) Conor Curran 2011 <conor.curran@canonical.com>
14036
 
+ * 
14037
 
+ * This is free software: you can redistribute it and/or modify it
14038
 
+ * under the terms of the GNU General Public License as published by the
14039
 
+ * Free Software Foundation, either version 3 of the License, or
14040
 
+ * (at your option) any later version.
14041
 
+ * 
14042
 
+ * gvc-mixer-output.c is distributed in the hope that it will be useful, but
14043
 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
14044
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14045
 
+ * See the GNU General Public License for more details.
14046
 
+ * 
14047
 
+ * You should have received a copy of the GNU General Public License along
14048
 
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
14049
 
+ */
14050
 
+
14051
 
+#ifndef _GVC_MIXER_UI_DEVICE_H_
14052
 
+#define _GVC_MIXER_UI_DEVICE_H_
14053
 
+
14054
 
+#include <glib-object.h>
14055
 
+
14056
 
+
14057
 
+G_BEGIN_DECLS
14058
 
+
14059
 
+#define GVC_TYPE_MIXER_UI_DEVICE             (gvc_mixer_ui_device_get_type ())
14060
 
+#define GVC_MIXER_UI_DEVICE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GVC_TYPE_MIXER_UI_DEVICE, GvcMixerUIDevice))
14061
 
+#define GVC_MIXER_UI_DEVICE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GVC_TYPE_MIXER_UI_DEVICE, GvcMixerUIDeviceClass))
14062
 
+#define GVC_IS_MIXER_UI_DEVICE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GVC_TYPE_MIXER_UI_DEVICE))
14063
 
+#define GVC_IS_MIXER_UI_DEVICE_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GVC_TYPE_MIXER_UI_DEVICE))
14064
 
+#define GVC_MIXER_UI_DEVICE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GVC_TYPE_MIXER_UI_DEVICE, GvcMixerUIDeviceClass))
14065
 
+#define GVC_MIXER_UI_DEVICE_INVALID          -1
14066
 
+
14067
 
+typedef struct GvcMixerUIDevicePrivate GvcMixerUIDevicePrivate;
14068
 
+
14069
 
+typedef struct
14070
 
+{
14071
 
+       GObjectClass parent_class;
14072
 
+}GvcMixerUIDeviceClass;
14073
 
+
14074
 
+typedef struct
14075
 
+{
14076
 
+       GObject parent_instance;
14077
 
+       GvcMixerUIDevicePrivate *priv;  
14078
 
+}GvcMixerUIDevice;
14079
 
+
14080
 
+typedef enum
14081
 
+{
14082
 
+       UiDeviceInput,
14083
 
+       UiDeviceOutput, 
14084
 
+}UiDeviceDirection;
14085
 
+
14086
 
+GType gvc_mixer_ui_device_get_type (void) G_GNUC_CONST;
14087
 
+
14088
 
+guint                          gvc_mixer_ui_device_get_id                              (GvcMixerUIDevice *dev);
14089
 
+gint                           gvc_mixer_ui_device_get_stream_id                       (GvcMixerUIDevice *dev);
14090
 
+const gchar*                   gvc_mixer_ui_device_get_description                     (GvcMixerUIDevice *dev);
14091
 
+const gchar*                   gvc_mixer_ui_device_get_origin                                          (GvcMixerUIDevice *dev);
14092
 
+const gchar*                   gvc_mixer_ui_device_get_port                                            (GvcMixerUIDevice *dev);
14093
 
+const gchar*                   gvc_mixer_ui_device_get_best_profile                            (GvcMixerUIDevice *dev, const gchar *selected, const gchar *current);
14094
 
+const gchar*                   gvc_mixer_ui_device_get_matching_profile                        (GvcMixerUIDevice *dev, const gchar *profile);
14095
 
+const gchar*                   gvc_mixer_ui_device_get_user_preferred_profile          (GvcMixerUIDevice *dev);
14096
 
+const gchar*                   gvc_mixer_ui_device_get_top_priority_profile            (GvcMixerUIDevice *dev);
14097
 
+GHashTable*                            gvc_mixer_ui_device_get_profiles                                        (GvcMixerUIDevice *dev);
14098
 
+GList*                                 gvc_mixer_ui_device_get_supported_profiles                      (GvcMixerUIDevice *device);
14099
 
+gboolean                       gvc_mixer_ui_device_should_profiles_be_hidden           (GvcMixerUIDevice *device);
14100
 
+void                                   gvc_mixer_ui_device_set_profiles                                        (GvcMixerUIDevice *device, const GList *profiles);
14101
 
+void                                   gvc_mixer_ui_device_set_user_preferred_profile          (GvcMixerUIDevice *device, const gchar *profile);
14102
 
+void                                   gvc_mixer_ui_device_invalidate_stream                           (GvcMixerUIDevice *dev);
14103
 
+gboolean                               gvc_mixer_ui_device_is_software_stream                          (GvcMixerUIDevice *dev);
14104
 
+
14105
 
+
14106
 
+G_END_DECLS
14107
 
+
14108
 
+#endif /* _GVC_MIXER_UI_DEVICE_H_ */
14109
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-pulseaudio-fake.h
14110
 
===================================================================
14111
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
14112
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-pulseaudio-fake.h   2012-08-28 17:08:49.464516900 +0200
14113
 
@@ -0,0 +1,34 @@
14114
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
14115
 
+ *
14116
 
+ * Copyright (C) 2008 Red Hat, Inc.
14117
 
+ *
14118
 
+ * This program is free software; you can redistribute it and/or modify
14119
 
+ * it under the terms of the GNU General Public License as published by
14120
 
+ * the Free Software Foundation; either version 2 of the License, or
14121
 
+ * (at your option) any later version.
14122
 
+ *
14123
 
+ * This program is distributed in the hope that it will be useful,
14124
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14125
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14126
 
+ * GNU General Public License for more details.
14127
 
+ *
14128
 
+ * You should have received a copy of the GNU General Public License
14129
 
+ * along with this program; if not, write to the Free Software
14130
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
14131
 
+ *
14132
 
+ */
14133
 
+
14134
 
+#ifndef __GVC_PULSEAUDIO_FAKE_H
14135
 
+#define __GVC_PULSEAUDIO_FAKE_H
14136
 
+
14137
 
+#ifdef WITH_INTROSPECTION
14138
 
+
14139
 
+#ifndef PA_API_VERSION
14140
 
+#define pa_channel_position_t int
14141
 
+#define pa_volume_t guint32
14142
 
+#define pa_context gpointer
14143
 
+#endif /* PA_API_VERSION */
14144
 
+
14145
 
+#endif /* WITH_INTROSPECTION */
14146
 
+
14147
 
+#endif /* __GVC_PULSEAUDIO_FAKE_H */
14148
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-sound-theme-chooser.c
14149
 
===================================================================
14150
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
14151
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-sound-theme-chooser.c       2012-08-28 17:09:13.256518052 +0200
14152
 
@@ -0,0 +1,833 @@
14153
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
14154
 
+ *
14155
 
+ * Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
14156
 
+ * Copyright (C) 2008 William Jon McCann
14157
 
+ *
14158
 
+ * This program is free software; you can redistribute it and/or modify
14159
 
+ * it under the terms of the GNU General Public License as published by
14160
 
+ * the Free Software Foundation; either version 2 of the License, or
14161
 
+ * (at your option) any later version.
14162
 
+ *
14163
 
+ * This program is distributed in the hope that it will be useful,
14164
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14165
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14166
 
+ * GNU General Public License for more details.
14167
 
+ *
14168
 
+ * You should have received a copy of the GNU General Public License
14169
 
+ * along with this program; if not, write to the Free Software
14170
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
14171
 
+ *
14172
 
+ */
14173
 
+
14174
 
+#include "config.h"
14175
 
+
14176
 
+#include <stdlib.h>
14177
 
+#include <stdio.h>
14178
 
+#include <unistd.h>
14179
 
+#include <utime.h>
14180
 
+#include <errno.h>
14181
 
+
14182
 
+#include <glib.h>
14183
 
+#include <glib/gi18n-lib.h>
14184
 
+#include <gtk/gtk.h>
14185
 
+#include <canberra-gtk.h>
14186
 
+#include <libxml/tree.h>
14187
 
+
14188
 
+#include <gsettings-desktop-schemas/gdesktop-enums.h>
14189
 
+
14190
 
+#include "gvc-sound-theme-chooser.h"
14191
 
+#include "sound-theme-file-utils.h"
14192
 
+
14193
 
+#define GVC_SOUND_THEME_CHOOSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_SOUND_THEME_CHOOSER, GvcSoundThemeChooserPrivate))
14194
 
+
14195
 
+struct GvcSoundThemeChooserPrivate
14196
 
+{
14197
 
+        GtkWidget *treeview;
14198
 
+        GtkWidget *selection_box;
14199
 
+        GSettings *settings;
14200
 
+        GSettings *sound_settings;
14201
 
+        char *current_theme;
14202
 
+        char *current_parent;
14203
 
+};
14204
 
+
14205
 
+static void     gvc_sound_theme_chooser_class_init (GvcSoundThemeChooserClass *klass);
14206
 
+static void     gvc_sound_theme_chooser_init       (GvcSoundThemeChooser      *sound_theme_chooser);
14207
 
+static void     gvc_sound_theme_chooser_finalize   (GObject            *object);
14208
 
+
14209
 
+G_DEFINE_TYPE (GvcSoundThemeChooser, gvc_sound_theme_chooser, GTK_TYPE_VBOX)
14210
 
+
14211
 
+#define KEY_SOUNDS_SCHEMA          "org.gnome.desktop.sound"
14212
 
+#define EVENT_SOUNDS_KEY           "event-sounds"
14213
 
+#define INPUT_SOUNDS_KEY           "input-feedback-sounds"
14214
 
+#define SOUND_THEME_KEY            "theme-name"
14215
 
+
14216
 
+#define WM_SCHEMA                  "org.gnome.desktop.wm.preferences"
14217
 
+#define AUDIO_BELL_KEY             "audible-bell"
14218
 
+
14219
 
+#define DEFAULT_ALERT_ID        "__default"
14220
 
+#define CUSTOM_THEME_NAME       "__custom"
14221
 
+#define NO_SOUNDS_THEME_NAME    "__no_sounds"
14222
 
+#define DEFAULT_THEME           "ubuntu"
14223
 
+
14224
 
+enum {
14225
 
+        THEME_DISPLAY_COL,
14226
 
+        THEME_IDENTIFIER_COL,
14227
 
+        THEME_PARENT_ID_COL,
14228
 
+        THEME_NUM_COLS
14229
 
+};
14230
 
+
14231
 
+enum {
14232
 
+        ALERT_DISPLAY_COL,
14233
 
+        ALERT_IDENTIFIER_COL,
14234
 
+        ALERT_SOUND_TYPE_COL,
14235
 
+        ALERT_NUM_COLS
14236
 
+};
14237
 
+
14238
 
+enum {
14239
 
+        SOUND_TYPE_UNSET,
14240
 
+        SOUND_TYPE_OFF,
14241
 
+        SOUND_TYPE_DEFAULT_FROM_THEME,
14242
 
+        SOUND_TYPE_BUILTIN,
14243
 
+        SOUND_TYPE_CUSTOM
14244
 
+};
14245
 
+
14246
 
+#define GVC_SOUND_SOUND    (xmlChar *) "sound"
14247
 
+#define GVC_SOUND_NAME     (xmlChar *) "name"
14248
 
+#define GVC_SOUND_FILENAME (xmlChar *) "filename"
14249
 
+
14250
 
+/* Adapted from yelp-toc-pager.c */
14251
 
+static xmlChar *
14252
 
+xml_get_and_trim_names (xmlNodePtr node)
14253
 
+{
14254
 
+        xmlNodePtr cur;
14255
 
+        xmlChar *keep_lang = NULL;
14256
 
+        xmlChar *value;
14257
 
+        int j, keep_pri = INT_MAX;
14258
 
+
14259
 
+        const gchar * const * langs = g_get_language_names ();
14260
 
+
14261
 
+        value = NULL;
14262
 
+
14263
 
+        for (cur = node->children; cur; cur = cur->next) {
14264
 
+                if (! xmlStrcmp (cur->name, GVC_SOUND_NAME)) {
14265
 
+                        xmlChar *cur_lang = NULL;
14266
 
+                        int cur_pri = INT_MAX;
14267
 
+
14268
 
+                        cur_lang = xmlNodeGetLang (cur);
14269
 
+
14270
 
+                        if (cur_lang) {
14271
 
+                                for (j = 0; langs[j]; j++) {
14272
 
+                                        if (g_str_equal (cur_lang, langs[j])) {
14273
 
+                                                cur_pri = j;
14274
 
+                                                break;
14275
 
+                                        }
14276
 
+                                }
14277
 
+                        } else {
14278
 
+                                cur_pri = INT_MAX - 1;
14279
 
+                        }
14280
 
+
14281
 
+                        if (cur_pri <= keep_pri) {
14282
 
+                                if (keep_lang)
14283
 
+                                        xmlFree (keep_lang);
14284
 
+                                if (value)
14285
 
+                                        xmlFree (value);
14286
 
+
14287
 
+                                value = xmlNodeGetContent (cur);
14288
 
+
14289
 
+                                keep_lang = cur_lang;
14290
 
+                                keep_pri = cur_pri;
14291
 
+                        } else {
14292
 
+                                if (cur_lang)
14293
 
+                                        xmlFree (cur_lang);
14294
 
+                        }
14295
 
+                }
14296
 
+        }
14297
 
+
14298
 
+        /* Delete all GVC_SOUND_NAME nodes */
14299
 
+        cur = node->children;
14300
 
+        while (cur) {
14301
 
+                xmlNodePtr this = cur;
14302
 
+                cur = cur->next;
14303
 
+                if (! xmlStrcmp (this->name, GVC_SOUND_NAME)) {
14304
 
+                        xmlUnlinkNode (this);
14305
 
+                        xmlFreeNode (this);
14306
 
+                }
14307
 
+        }
14308
 
+
14309
 
+        return value;
14310
 
+}
14311
 
+
14312
 
+static void
14313
 
+populate_model_from_node (GvcSoundThemeChooser *chooser,
14314
 
+                          GtkTreeModel         *model,
14315
 
+                          xmlNodePtr            node)
14316
 
+{
14317
 
+        xmlNodePtr child;
14318
 
+        xmlChar   *filename;
14319
 
+        xmlChar   *name;
14320
 
+
14321
 
+        filename = NULL;
14322
 
+        name = xml_get_and_trim_names (node);
14323
 
+        for (child = node->children; child; child = child->next) {
14324
 
+                if (xmlNodeIsText (child)) {
14325
 
+                        continue;
14326
 
+                }
14327
 
+
14328
 
+                if (xmlStrcmp (child->name, GVC_SOUND_FILENAME) == 0) {
14329
 
+                        filename = xmlNodeGetContent (child);
14330
 
+                } else if (xmlStrcmp (child->name, GVC_SOUND_NAME) == 0) {
14331
 
+                        /* EH? should have been trimmed */
14332
 
+                }
14333
 
+        }
14334
 
+
14335
 
+        if (filename != NULL && name != NULL) {
14336
 
+                gtk_list_store_insert_with_values (GTK_LIST_STORE (model),
14337
 
+                                                   NULL,
14338
 
+                                                   G_MAXINT,
14339
 
+                                                   ALERT_IDENTIFIER_COL, filename,
14340
 
+                                                   ALERT_DISPLAY_COL, name,
14341
 
+                                                   ALERT_SOUND_TYPE_COL, _("Built-in"),
14342
 
+                                                   -1);
14343
 
+        }
14344
 
+
14345
 
+        xmlFree (filename);
14346
 
+        xmlFree (name);
14347
 
+}
14348
 
+
14349
 
+static void
14350
 
+populate_model_from_file (GvcSoundThemeChooser *chooser,
14351
 
+                          GtkTreeModel         *model,
14352
 
+                          const char           *filename)
14353
 
+{
14354
 
+        xmlDocPtr  doc;
14355
 
+        xmlNodePtr root;
14356
 
+        xmlNodePtr child;
14357
 
+        gboolean   exists;
14358
 
+
14359
 
+        exists = g_file_test (filename, G_FILE_TEST_EXISTS);
14360
 
+        if (! exists) {
14361
 
+                return;
14362
 
+        }
14363
 
+
14364
 
+        doc = xmlParseFile (filename);
14365
 
+        if (doc == NULL) {
14366
 
+                return;
14367
 
+        }
14368
 
+
14369
 
+        root = xmlDocGetRootElement (doc);
14370
 
+
14371
 
+        for (child = root->children; child; child = child->next) {
14372
 
+                if (xmlNodeIsText (child)) {
14373
 
+                        continue;
14374
 
+                }
14375
 
+                if (xmlStrcmp (child->name, GVC_SOUND_SOUND) != 0) {
14376
 
+                        continue;
14377
 
+                }
14378
 
+
14379
 
+                populate_model_from_node (chooser, model, child);
14380
 
+        }
14381
 
+
14382
 
+        xmlFreeDoc (doc);
14383
 
+}
14384
 
+
14385
 
+static void
14386
 
+populate_model_from_dir (GvcSoundThemeChooser *chooser,
14387
 
+                         GtkTreeModel         *model,
14388
 
+                         const char           *dirname)
14389
 
+{
14390
 
+        GDir       *d;
14391
 
+        const char *name;
14392
 
+
14393
 
+        d = g_dir_open (dirname, 0, NULL);
14394
 
+        if (d == NULL) {
14395
 
+                return;
14396
 
+        }
14397
 
+
14398
 
+        while ((name = g_dir_read_name (d)) != NULL) {
14399
 
+                char *path;
14400
 
+
14401
 
+                if (! g_str_has_suffix (name, ".xml")) {
14402
 
+                        continue;
14403
 
+                }
14404
 
+
14405
 
+                path = g_build_filename (dirname, name, NULL);
14406
 
+                populate_model_from_file (chooser, model, path);
14407
 
+                g_free (path);
14408
 
+        }
14409
 
+}
14410
 
+
14411
 
+static gboolean
14412
 
+save_alert_sounds (GvcSoundThemeChooser  *chooser,
14413
 
+                   const char            *id)
14414
 
+{
14415
 
+        const char *sounds[3] = { "bell-terminal", "bell-window-system", NULL };
14416
 
+        char *path;
14417
 
+
14418
 
+        if (strcmp (id, DEFAULT_ALERT_ID) == 0) {
14419
 
+                delete_old_files (sounds);
14420
 
+                delete_disabled_files (sounds);
14421
 
+        } else {
14422
 
+                delete_old_files (sounds);
14423
 
+                delete_disabled_files (sounds);
14424
 
+                add_custom_file (sounds, id);
14425
 
+        }
14426
 
+
14427
 
+        /* And poke the directory so the theme gets updated */
14428
 
+        path = custom_theme_dir_path (NULL);
14429
 
+        if (utime (path, NULL) != 0) {
14430
 
+                g_warning ("Failed to update mtime for directory '%s': %s",
14431
 
+                           path, g_strerror (errno));
14432
 
+        }
14433
 
+        g_free (path);
14434
 
+
14435
 
+        return FALSE;
14436
 
+}
14437
 
+
14438
 
+
14439
 
+static void
14440
 
+update_alert_model (GvcSoundThemeChooser  *chooser,
14441
 
+                    const char            *id)
14442
 
+{
14443
 
+        GtkTreeModel *model;
14444
 
+        GtkTreeIter   iter;
14445
 
+
14446
 
+        model = gtk_tree_view_get_model (GTK_TREE_VIEW (chooser->priv->treeview));
14447
 
+        gtk_tree_model_get_iter_first (model, &iter);
14448
 
+        do {
14449
 
+                char    *this_id;
14450
 
+
14451
 
+                gtk_tree_model_get (model, &iter,
14452
 
+                                    ALERT_IDENTIFIER_COL, &this_id,
14453
 
+                                    -1);
14454
 
+
14455
 
+                if (strcmp (this_id, id) == 0) {
14456
 
+                        GtkTreeSelection *selection;
14457
 
+
14458
 
+                        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (chooser->priv->treeview));
14459
 
+                        gtk_tree_selection_select_iter (selection, &iter);
14460
 
+                }
14461
 
+
14462
 
+                g_free (this_id);
14463
 
+        } while (gtk_tree_model_iter_next (model, &iter));
14464
 
+}
14465
 
+
14466
 
+static void
14467
 
+save_theme_name (GvcSoundThemeChooser *chooser,
14468
 
+                 const char           *theme_name)
14469
 
+{
14470
 
+        /* If the name is empty, use "freedesktop" */
14471
 
+        if (theme_name == NULL || *theme_name == '\0') {
14472
 
+                theme_name = DEFAULT_THEME;
14473
 
+        }
14474
 
+
14475
 
+        /* special case for no sounds */
14476
 
+        if (strcmp (theme_name, NO_SOUNDS_THEME_NAME) == 0) {
14477
 
+                g_settings_set_boolean (chooser->priv->sound_settings, EVENT_SOUNDS_KEY, FALSE);
14478
 
+                return;
14479
 
+        } else {
14480
 
+                g_settings_set_boolean (chooser->priv->sound_settings, EVENT_SOUNDS_KEY, TRUE);
14481
 
+        }
14482
 
+
14483
 
+        g_settings_set_string (chooser->priv->sound_settings, SOUND_THEME_KEY, theme_name);
14484
 
+}
14485
 
+
14486
 
+static gboolean
14487
 
+load_theme_file (const char *path,
14488
 
+                 char      **parent)
14489
 
+{
14490
 
+        GKeyFile *file;
14491
 
+        gboolean hidden;
14492
 
+
14493
 
+        file = g_key_file_new ();
14494
 
+        if (g_key_file_load_from_file (file, path, G_KEY_FILE_KEEP_TRANSLATIONS, NULL) == FALSE) {
14495
 
+                g_key_file_free (file);
14496
 
+                return FALSE;
14497
 
+        }
14498
 
+        /* Don't add hidden themes to the list */
14499
 
+        hidden = g_key_file_get_boolean (file, "Sound Theme", "Hidden", NULL);
14500
 
+        if (!hidden) {
14501
 
+                /* Save the parent theme, if there's one */
14502
 
+                if (parent != NULL) {
14503
 
+                        *parent = g_key_file_get_string (file,
14504
 
+                                                         "Sound Theme",
14505
 
+                                                         "Inherits",
14506
 
+                                                         NULL);
14507
 
+                }
14508
 
+        }
14509
 
+
14510
 
+        g_key_file_free (file);
14511
 
+
14512
 
+        return TRUE;
14513
 
+}
14514
 
+
14515
 
+static gboolean
14516
 
+load_theme_name (const char *name,
14517
 
+                 char      **parent)
14518
 
+{
14519
 
+        const char * const   *data_dirs;
14520
 
+        const char           *data_dir;
14521
 
+        char                 *path;
14522
 
+        guint                 i;
14523
 
+        gboolean              res;
14524
 
+
14525
 
+        data_dir = g_get_user_data_dir ();
14526
 
+        path = g_build_filename (data_dir, "sounds", name, "index.theme", NULL);
14527
 
+        res = load_theme_file (path, parent);
14528
 
+        g_free (path);
14529
 
+        if (res)
14530
 
+                return TRUE;
14531
 
+
14532
 
+        data_dirs = g_get_system_data_dirs ();
14533
 
+        for (i = 0; data_dirs[i] != NULL; i++) {
14534
 
+                path = g_build_filename (data_dirs[i], "sounds", name, "index.theme", NULL);
14535
 
+                res = load_theme_file (path, parent);
14536
 
+                g_free (path);
14537
 
+                if (res)
14538
 
+                        return TRUE;
14539
 
+        }
14540
 
+
14541
 
+        return FALSE;
14542
 
+}
14543
 
+
14544
 
+static void
14545
 
+update_alert (GvcSoundThemeChooser *chooser,
14546
 
+              const char           *alert_id)
14547
 
+{
14548
 
+        gboolean      is_custom;
14549
 
+        gboolean      is_default;
14550
 
+        gboolean      add_custom;
14551
 
+        gboolean      remove_custom;
14552
 
+
14553
 
+        is_custom = strcmp (chooser->priv->current_theme, CUSTOM_THEME_NAME) == 0;
14554
 
+        is_default = strcmp (alert_id, DEFAULT_ALERT_ID) == 0;
14555
 
+
14556
 
+        /* So a few possibilities:
14557
 
+         * 1. Named theme, default alert selected: noop
14558
 
+         * 2. Named theme, alternate alert selected: create new custom with sound
14559
 
+         * 3. Custom theme, default alert selected: remove sound and possibly custom
14560
 
+         * 4. Custom theme, alternate alert selected: update custom sound
14561
 
+         */
14562
 
+        add_custom = FALSE;
14563
 
+        remove_custom = FALSE;
14564
 
+        if (! is_custom && is_default) {
14565
 
+                /* remove custom just in case */
14566
 
+                remove_custom = TRUE;
14567
 
+        } else if (! is_custom && ! is_default) {
14568
 
+                if (chooser->priv->current_parent)
14569
 
+                        create_custom_theme (chooser->priv->current_parent);
14570
 
+                else
14571
 
+                        create_custom_theme (DEFAULT_THEME);
14572
 
+                save_alert_sounds (chooser, alert_id);
14573
 
+                add_custom = TRUE;
14574
 
+        } else if (is_custom && is_default) {
14575
 
+                save_alert_sounds (chooser, alert_id);
14576
 
+                /* after removing files check if it is empty */
14577
 
+                if (custom_theme_dir_is_empty ()) {
14578
 
+                        remove_custom = TRUE;
14579
 
+                }
14580
 
+        } else if (is_custom && ! is_default) {
14581
 
+                save_alert_sounds (chooser, alert_id);
14582
 
+        }
14583
 
+
14584
 
+        if (add_custom) {
14585
 
+                save_theme_name (chooser, CUSTOM_THEME_NAME);
14586
 
+        } else if (remove_custom) {
14587
 
+                delete_custom_theme_dir ();
14588
 
+                if (is_custom) {
14589
 
+                        save_theme_name (chooser, chooser->priv->current_parent);
14590
 
+                }
14591
 
+        }
14592
 
+
14593
 
+        update_alert_model (chooser, alert_id);
14594
 
+}
14595
 
+
14596
 
+static void
14597
 
+play_preview_for_id (GvcSoundThemeChooser *chooser,
14598
 
+                     const char           *id)
14599
 
+{
14600
 
+        g_return_if_fail (id != NULL);
14601
 
+
14602
 
+        /* special case: for the default item on custom themes
14603
 
+         * play the alert for the parent theme */
14604
 
+        if (strcmp (id, DEFAULT_ALERT_ID) == 0) {
14605
 
+                if (chooser->priv->current_parent != NULL) {
14606
 
+                        ca_gtk_play_for_widget (GTK_WIDGET (chooser), 0,
14607
 
+                                                CA_PROP_APPLICATION_NAME, _("Sound Preferences"),
14608
 
+                                                CA_PROP_EVENT_ID, "bell-window-system",
14609
 
+                                                CA_PROP_CANBERRA_XDG_THEME_NAME, chooser->priv->current_parent,
14610
 
+                                                CA_PROP_EVENT_DESCRIPTION, _("Testing event sound"),
14611
 
+                                                CA_PROP_CANBERRA_CACHE_CONTROL, "never",
14612
 
+                                                CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl",
14613
 
+#ifdef CA_PROP_CANBERRA_ENABLE
14614
 
+                                                CA_PROP_CANBERRA_ENABLE, "1",
14615
 
+#endif
14616
 
+                                                NULL);
14617
 
+                } else {
14618
 
+                        ca_gtk_play_for_widget (GTK_WIDGET (chooser), 0,
14619
 
+                                                CA_PROP_APPLICATION_NAME, _("Sound Preferences"),
14620
 
+                                                CA_PROP_EVENT_ID, "bell-window-system",
14621
 
+                                                CA_PROP_EVENT_DESCRIPTION, _("Testing event sound"),
14622
 
+                                                CA_PROP_CANBERRA_CACHE_CONTROL, "never",
14623
 
+                                                CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl",
14624
 
+#ifdef CA_PROP_CANBERRA_ENABLE
14625
 
+                                                CA_PROP_CANBERRA_ENABLE, "1",
14626
 
+#endif
14627
 
+                                                NULL);
14628
 
+                }
14629
 
+        } else {
14630
 
+                ca_gtk_play_for_widget (GTK_WIDGET (chooser), 0,
14631
 
+                                        CA_PROP_APPLICATION_NAME, _("Sound Preferences"),
14632
 
+                                        CA_PROP_MEDIA_FILENAME, id,
14633
 
+                                        CA_PROP_EVENT_DESCRIPTION, _("Testing event sound"),
14634
 
+                                        CA_PROP_CANBERRA_CACHE_CONTROL, "never",
14635
 
+                                        CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl",
14636
 
+#ifdef CA_PROP_CANBERRA_ENABLE
14637
 
+                                        CA_PROP_CANBERRA_ENABLE, "1",
14638
 
+#endif
14639
 
+                                        NULL);
14640
 
+
14641
 
+        }
14642
 
+}
14643
 
+
14644
 
+static void
14645
 
+on_treeview_selection_changed (GtkTreeSelection     *selection,
14646
 
+                               GvcSoundThemeChooser *chooser)
14647
 
+{
14648
 
+        GtkTreeModel *model;
14649
 
+        GtkTreeIter   iter;
14650
 
+        char         *id;
14651
 
+
14652
 
+        if (chooser->priv->treeview == NULL) {
14653
 
+                return;
14654
 
+        }
14655
 
+
14656
 
+        model = gtk_tree_view_get_model (GTK_TREE_VIEW (chooser->priv->treeview));
14657
 
+
14658
 
+        if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) {
14659
 
+                return;
14660
 
+        }
14661
 
+
14662
 
+        id = NULL;
14663
 
+        gtk_tree_model_get (model, &iter,
14664
 
+                            ALERT_IDENTIFIER_COL, &id,
14665
 
+                            -1);
14666
 
+        if (id == NULL) {
14667
 
+                return;
14668
 
+        }
14669
 
+
14670
 
+        play_preview_for_id (chooser, id);
14671
 
+        update_alert (chooser, id);
14672
 
+        g_free (id);
14673
 
+}
14674
 
+
14675
 
+static gboolean
14676
 
+on_treeview_button_pressed (GtkTreeView          *treeview,
14677
 
+                            GdkEventButton       *event,
14678
 
+                            GvcSoundThemeChooser *chooser)
14679
 
+{
14680
 
+        GtkTreeSelection *selection;
14681
 
+        GtkTreePath      *path;
14682
 
+
14683
 
+        selection = gtk_tree_view_get_selection (treeview);
14684
 
+        if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (treeview),
14685
 
+                                           event->x, event->y, &path, NULL, NULL, NULL) == FALSE) {
14686
 
+                return FALSE;
14687
 
+        }
14688
 
+
14689
 
+        if (gtk_tree_selection_path_is_selected (selection, path) == FALSE) {
14690
 
+                gtk_tree_path_free (path);
14691
 
+                return FALSE;
14692
 
+        }
14693
 
+        gtk_tree_path_free (path);
14694
 
+
14695
 
+        on_treeview_selection_changed (selection, chooser);
14696
 
+
14697
 
+        return FALSE;
14698
 
+}
14699
 
+
14700
 
+static GtkWidget *
14701
 
+create_alert_treeview (GvcSoundThemeChooser *chooser)
14702
 
+{
14703
 
+        GtkListStore         *store;
14704
 
+        GtkWidget            *treeview;
14705
 
+        GtkCellRenderer      *renderer;
14706
 
+        GtkTreeViewColumn    *column;
14707
 
+        GtkTreeSelection     *selection;
14708
 
+
14709
 
+        treeview = gtk_tree_view_new ();
14710
 
+        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
14711
 
+        g_signal_connect (treeview,
14712
 
+                          "button-press-event",
14713
 
+                          G_CALLBACK (on_treeview_button_pressed),
14714
 
+                          chooser);
14715
 
+
14716
 
+        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
14717
 
+        gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
14718
 
+        g_signal_connect (selection,
14719
 
+                          "changed",
14720
 
+                          G_CALLBACK (on_treeview_selection_changed),
14721
 
+                          chooser);
14722
 
+
14723
 
+        /* Setup the tree model, 3 columns:
14724
 
+         * - display name
14725
 
+         * - sound id
14726
 
+         * - sound type
14727
 
+         */
14728
 
+        store = gtk_list_store_new (ALERT_NUM_COLS,
14729
 
+                                    G_TYPE_STRING,
14730
 
+                                    G_TYPE_STRING,
14731
 
+                                    G_TYPE_STRING);
14732
 
+
14733
 
+        gtk_list_store_insert_with_values (store,
14734
 
+                                           NULL,
14735
 
+                                           G_MAXINT,
14736
 
+                                           ALERT_IDENTIFIER_COL, DEFAULT_ALERT_ID,
14737
 
+                                           ALERT_DISPLAY_COL, _("Default"),
14738
 
+                                           ALERT_SOUND_TYPE_COL, _("From theme"),
14739
 
+                                           -1);
14740
 
+
14741
 
+        populate_model_from_dir (chooser, GTK_TREE_MODEL (store), SOUND_SET_DIR);
14742
 
+
14743
 
+        gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
14744
 
+                                 GTK_TREE_MODEL (store));
14745
 
+
14746
 
+        renderer = gtk_cell_renderer_text_new ();
14747
 
+        column = gtk_tree_view_column_new_with_attributes (_("Name"),
14748
 
+                                                           renderer,
14749
 
+                                                           "text", ALERT_DISPLAY_COL,
14750
 
+                                                           NULL);
14751
 
+        gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
14752
 
+
14753
 
+        return treeview;
14754
 
+}
14755
 
+
14756
 
+static int
14757
 
+get_file_type (const char *sound_name,
14758
 
+               char      **linked_name)
14759
 
+{
14760
 
+        char *name, *filename;
14761
 
+
14762
 
+        *linked_name = NULL;
14763
 
+
14764
 
+        name = g_strdup_printf ("%s.disabled", sound_name);
14765
 
+        filename = custom_theme_dir_path (name);
14766
 
+        g_free (name);
14767
 
+
14768
 
+        if (g_file_test (filename, G_FILE_TEST_IS_REGULAR) != FALSE) {
14769
 
+                g_free (filename);
14770
 
+                return SOUND_TYPE_OFF;
14771
 
+        }
14772
 
+        g_free (filename);
14773
 
+
14774
 
+        /* We only check for .ogg files because those are the
14775
 
+         * only ones we create */
14776
 
+        name = g_strdup_printf ("%s.ogg", sound_name);
14777
 
+        filename = custom_theme_dir_path (name);
14778
 
+        g_free (name);
14779
 
+
14780
 
+        if (g_file_test (filename, G_FILE_TEST_IS_SYMLINK) != FALSE) {
14781
 
+                *linked_name = g_file_read_link (filename, NULL);
14782
 
+                g_free (filename);
14783
 
+                return SOUND_TYPE_CUSTOM;
14784
 
+        }
14785
 
+        g_free (filename);
14786
 
+
14787
 
+        return SOUND_TYPE_BUILTIN;
14788
 
+}
14789
 
+
14790
 
+static void
14791
 
+update_alerts_from_theme_name (GvcSoundThemeChooser *chooser,
14792
 
+                               const char           *name)
14793
 
+{
14794
 
+        if (strcmp (name, CUSTOM_THEME_NAME) != 0) {
14795
 
+                /* reset alert to default */
14796
 
+                update_alert (chooser, DEFAULT_ALERT_ID);
14797
 
+        } else {
14798
 
+                int   sound_type;
14799
 
+                char *linkname;
14800
 
+
14801
 
+                linkname = NULL;
14802
 
+                sound_type = get_file_type ("bell-terminal", &linkname);
14803
 
+                g_debug ("Found link: %s", linkname);
14804
 
+                if (sound_type == SOUND_TYPE_CUSTOM) {
14805
 
+                        update_alert (chooser, linkname);
14806
 
+                }
14807
 
+        }
14808
 
+}
14809
 
+
14810
 
+static void
14811
 
+update_theme (GvcSoundThemeChooser *chooser)
14812
 
+{
14813
 
+        gboolean     events_enabled;
14814
 
+        char        *last_theme;
14815
 
+
14816
 
+        events_enabled = g_settings_get_boolean (chooser->priv->sound_settings, EVENT_SOUNDS_KEY);
14817
 
+
14818
 
+        last_theme = chooser->priv->current_theme;
14819
 
+        if (events_enabled) {
14820
 
+                chooser->priv->current_theme = g_settings_get_string (chooser->priv->sound_settings, SOUND_THEME_KEY);
14821
 
+        } else {
14822
 
+                chooser->priv->current_theme = g_strdup (NO_SOUNDS_THEME_NAME);
14823
 
+        }
14824
 
+
14825
 
+        if (g_strcmp0 (last_theme, chooser->priv->current_theme) != 0) {
14826
 
+                g_free (chooser->priv->current_parent);
14827
 
+                if (load_theme_name (chooser->priv->current_theme,
14828
 
+                                     &chooser->priv->current_parent) == FALSE) {
14829
 
+                        g_free (chooser->priv->current_theme);
14830
 
+                        chooser->priv->current_theme = g_strdup (DEFAULT_THEME);
14831
 
+                        load_theme_name (DEFAULT_THEME,
14832
 
+                                         &chooser->priv->current_parent);
14833
 
+                }
14834
 
+        }
14835
 
+        g_free (last_theme);
14836
 
+
14837
 
+        gtk_widget_set_sensitive (chooser->priv->selection_box, events_enabled);
14838
 
+
14839
 
+        update_alerts_from_theme_name (chooser, chooser->priv->current_theme);
14840
 
+}
14841
 
+
14842
 
+static GObject *
14843
 
+gvc_sound_theme_chooser_constructor (GType                  type,
14844
 
+                                     guint                  n_construct_properties,
14845
 
+                                     GObjectConstructParam *construct_params)
14846
 
+{
14847
 
+        GObject              *object;
14848
 
+        GvcSoundThemeChooser *self;
14849
 
+
14850
 
+        object = G_OBJECT_CLASS (gvc_sound_theme_chooser_parent_class)->constructor (type, n_construct_properties, construct_params);
14851
 
+
14852
 
+        self = GVC_SOUND_THEME_CHOOSER (object);
14853
 
+
14854
 
+        update_theme (self);
14855
 
+
14856
 
+        return object;
14857
 
+}
14858
 
+
14859
 
+static void
14860
 
+gvc_sound_theme_chooser_class_init (GvcSoundThemeChooserClass *klass)
14861
 
+{
14862
 
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
14863
 
+
14864
 
+        object_class->constructor = gvc_sound_theme_chooser_constructor;
14865
 
+        object_class->finalize = gvc_sound_theme_chooser_finalize;
14866
 
+
14867
 
+        g_type_class_add_private (klass, sizeof (GvcSoundThemeChooserPrivate));
14868
 
+}
14869
 
+
14870
 
+static void
14871
 
+on_sound_settings_changed (GSettings            *settings,
14872
 
+                           const char           *key,
14873
 
+                           GvcSoundThemeChooser *chooser)
14874
 
+{
14875
 
+        if (strcmp (key, EVENT_SOUNDS_KEY) == 0) {
14876
 
+                update_theme (chooser);
14877
 
+        } else if (strcmp (key, SOUND_THEME_KEY) == 0) {
14878
 
+                update_theme (chooser);
14879
 
+        } else if (strcmp (key, INPUT_SOUNDS_KEY) == 0) {
14880
 
+                update_theme (chooser);
14881
 
+        }
14882
 
+}
14883
 
+
14884
 
+static void
14885
 
+on_audible_bell_changed (GSettings            *settings,
14886
 
+                         const char           *key,
14887
 
+                         GvcSoundThemeChooser *chooser)
14888
 
+{
14889
 
+        update_theme (chooser);
14890
 
+}
14891
 
+
14892
 
+static void
14893
 
+setup_list_size_constraint (GtkWidget *widget,
14894
 
+                            GtkWidget *to_size)
14895
 
+{
14896
 
+        GtkRequisition req;
14897
 
+        int            max_height;
14898
 
+
14899
 
+        /* constrain height to be the tree height up to a max */
14900
 
+        max_height = (gdk_screen_get_height (gtk_widget_get_screen (widget))) / 4;
14901
 
+
14902
 
+        gtk_widget_get_preferred_size (to_size, NULL, &req);
14903
 
+
14904
 
+        gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (widget),
14905
 
+                                                    MIN (req.height, max_height));
14906
 
+}
14907
 
+
14908
 
+static void
14909
 
+gvc_sound_theme_chooser_init (GvcSoundThemeChooser *chooser)
14910
 
+{
14911
 
+        GtkWidget   *box;
14912
 
+        GtkWidget   *label;
14913
 
+        GtkWidget   *scrolled_window;
14914
 
+        GtkWidget   *alignment;
14915
 
+        char        *str;
14916
 
+
14917
 
+        chooser->priv = GVC_SOUND_THEME_CHOOSER_GET_PRIVATE (chooser);
14918
 
+
14919
 
+        chooser->priv->settings = g_settings_new (WM_SCHEMA);
14920
 
+        chooser->priv->sound_settings = g_settings_new (KEY_SOUNDS_SCHEMA);
14921
 
+
14922
 
+        str = g_strdup_printf ("<b>%s</b>", _("C_hoose an alert sound:"));
14923
 
+        chooser->priv->selection_box = box = gtk_frame_new (str);
14924
 
+        g_free (str);
14925
 
+        label = gtk_frame_get_label_widget (GTK_FRAME (box));
14926
 
+        gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
14927
 
+        gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
14928
 
+        gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
14929
 
+
14930
 
+        alignment = gtk_alignment_new (0, 0, 1, 1);
14931
 
+        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0);
14932
 
+        gtk_container_add (GTK_CONTAINER (alignment), box);
14933
 
+        gtk_box_pack_start (GTK_BOX (chooser), alignment, TRUE, TRUE, 6);
14934
 
+
14935
 
+        alignment = gtk_alignment_new (0, 0, 1, 1);
14936
 
+        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0);
14937
 
+        gtk_container_add (GTK_CONTAINER (box), alignment);
14938
 
+
14939
 
+        chooser->priv->treeview = create_alert_treeview (chooser);
14940
 
+        gtk_label_set_mnemonic_widget (GTK_LABEL (label), chooser->priv->treeview);
14941
 
+
14942
 
+        scrolled_window = gtk_scrolled_window_new (NULL, NULL);
14943
 
+        setup_list_size_constraint (scrolled_window, chooser->priv->treeview);
14944
 
+
14945
 
+        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
14946
 
+                                        GTK_POLICY_NEVER,
14947
 
+                                        GTK_POLICY_AUTOMATIC);
14948
 
+        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
14949
 
+                                             GTK_SHADOW_IN);
14950
 
+        gtk_container_add (GTK_CONTAINER (scrolled_window), chooser->priv->treeview);
14951
 
+        gtk_container_add (GTK_CONTAINER (alignment), scrolled_window);
14952
 
+
14953
 
+        g_signal_connect (G_OBJECT (chooser->priv->sound_settings), "changed",
14954
 
+                          G_CALLBACK (on_sound_settings_changed), chooser);
14955
 
+        g_signal_connect (chooser->priv->settings, "changed::" AUDIO_BELL_KEY,
14956
 
+                          G_CALLBACK (on_audible_bell_changed), chooser);
14957
 
+}
14958
 
+
14959
 
+static void
14960
 
+gvc_sound_theme_chooser_finalize (GObject *object)
14961
 
+{
14962
 
+        GvcSoundThemeChooser *sound_theme_chooser;
14963
 
+
14964
 
+        g_return_if_fail (object != NULL);
14965
 
+        g_return_if_fail (GVC_IS_SOUND_THEME_CHOOSER (object));
14966
 
+
14967
 
+        sound_theme_chooser = GVC_SOUND_THEME_CHOOSER (object);
14968
 
+
14969
 
+        if (sound_theme_chooser->priv != NULL) {
14970
 
+                g_object_unref (sound_theme_chooser->priv->settings);
14971
 
+                g_object_unref (sound_theme_chooser->priv->sound_settings);
14972
 
+        }
14973
 
+
14974
 
+        G_OBJECT_CLASS (gvc_sound_theme_chooser_parent_class)->finalize (object);
14975
 
+}
14976
 
+
14977
 
+GtkWidget *
14978
 
+gvc_sound_theme_chooser_new (void)
14979
 
+{
14980
 
+        GObject *chooser;
14981
 
+        chooser = g_object_new (GVC_TYPE_SOUND_THEME_CHOOSER,
14982
 
+                                "spacing", 6,
14983
 
+                                NULL);
14984
 
+        return GTK_WIDGET (chooser);
14985
 
+}
14986
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-sound-theme-chooser.h
14987
 
===================================================================
14988
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
14989
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-sound-theme-chooser.h       2012-08-28 17:08:49.464516900 +0200
14990
 
@@ -0,0 +1,54 @@
14991
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
14992
 
+ *
14993
 
+ * Copyright (C) 2008 Red Hat, Inc.
14994
 
+ *
14995
 
+ * This program is free software; you can redistribute it and/or modify
14996
 
+ * it under the terms of the GNU General Public License as published by
14997
 
+ * the Free Software Foundation; either version 2 of the License, or
14998
 
+ * (at your option) any later version.
14999
 
+ *
15000
 
+ * This program is distributed in the hope that it will be useful,
15001
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15002
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15003
 
+ * GNU General Public License for more details.
15004
 
+ *
15005
 
+ * You should have received a copy of the GNU General Public License
15006
 
+ * along with this program; if not, write to the Free Software
15007
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15008
 
+ *
15009
 
+ */
15010
 
+
15011
 
+#ifndef __GVC_SOUND_THEME_CHOOSER_H
15012
 
+#define __GVC_SOUND_THEME_CHOOSER_H
15013
 
+
15014
 
+#include <glib-object.h>
15015
 
+
15016
 
+G_BEGIN_DECLS
15017
 
+
15018
 
+#define GVC_TYPE_SOUND_THEME_CHOOSER         (gvc_sound_theme_chooser_get_type ())
15019
 
+#define GVC_SOUND_THEME_CHOOSER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_SOUND_THEME_CHOOSER, GvcSoundThemeChooser))
15020
 
+#define GVC_SOUND_THEME_CHOOSER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_SOUND_THEME_CHOOSER, GvcSoundThemeChooserClass))
15021
 
+#define GVC_IS_SOUND_THEME_CHOOSER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_SOUND_THEME_CHOOSER))
15022
 
+#define GVC_IS_SOUND_THEME_CHOOSER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_SOUND_THEME_CHOOSER))
15023
 
+#define GVC_SOUND_THEME_CHOOSER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_SOUND_THEME_CHOOSER, GvcSoundThemeChooserClass))
15024
 
+
15025
 
+typedef struct GvcSoundThemeChooserPrivate GvcSoundThemeChooserPrivate;
15026
 
+
15027
 
+typedef struct
15028
 
+{
15029
 
+        GtkVBox                      parent;
15030
 
+        GvcSoundThemeChooserPrivate *priv;
15031
 
+} GvcSoundThemeChooser;
15032
 
+
15033
 
+typedef struct
15034
 
+{
15035
 
+        GtkVBoxClass          parent_class;
15036
 
+} GvcSoundThemeChooserClass;
15037
 
+
15038
 
+GType               gvc_sound_theme_chooser_get_type            (void);
15039
 
+
15040
 
+GtkWidget *         gvc_sound_theme_chooser_new                 (void);
15041
 
+
15042
 
+G_END_DECLS
15043
 
+
15044
 
+#endif /* __GVC_SOUND_THEME_CHOOSER_H */
15045
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-speaker-test.c
15046
 
===================================================================
15047
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
15048
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-speaker-test.c      2012-08-28 17:08:49.464516900 +0200
15049
 
@@ -0,0 +1,531 @@
15050
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
15051
 
+ *
15052
 
+ * Copyright (C) 2009 Bastien Nocera
15053
 
+ *
15054
 
+ * This program is free software; you can redistribute it and/or modify
15055
 
+ * it under the terms of the GNU General Public License as published by
15056
 
+ * the Free Software Foundation; either version 2 of the License, or
15057
 
+ * (at your option) any later version.
15058
 
+ *
15059
 
+ * This program is distributed in the hope that it will be useful,
15060
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15061
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15062
 
+ * GNU General Public License for more details.
15063
 
+ *
15064
 
+ * You should have received a copy of the GNU General Public License
15065
 
+ * along with this program; if not, write to the Free Software
15066
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15067
 
+ *
15068
 
+ */
15069
 
+
15070
 
+#include "config.h"
15071
 
+
15072
 
+#include <stdlib.h>
15073
 
+#include <stdio.h>
15074
 
+#include <unistd.h>
15075
 
+
15076
 
+#include <glib.h>
15077
 
+#include <glib/gi18n-lib.h>
15078
 
+#include <gtk/gtk.h>
15079
 
+#include <canberra.h>
15080
 
+#include <canberra-gtk.h>
15081
 
+#include <pulse/pulseaudio.h>
15082
 
+
15083
 
+#include "gvc-speaker-test.h"
15084
 
+#include "gvc-mixer-stream.h"
15085
 
+/* #include "gvc-mixer-card.h" */
15086
 
+
15087
 
+#define GVC_SPEAKER_TEST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_SPEAKER_TEST, GvcSpeakerTestPrivate))
15088
 
+
15089
 
+struct GvcSpeakerTestPrivate
15090
 
+{
15091
 
+        GtkWidget       *channel_controls[PA_CHANNEL_POSITION_MAX];
15092
 
+        ca_context      *canberra;
15093
 
+        GvcMixerStream  *stream;
15094
 
+        GvcMixerControl *control;
15095
 
+};
15096
 
+
15097
 
+enum {
15098
 
+        COL_NAME,
15099
 
+        COL_HUMAN_NAME,
15100
 
+        NUM_COLS
15101
 
+};
15102
 
+
15103
 
+enum {
15104
 
+        PROP_0,
15105
 
+        PROP_STREAM,
15106
 
+        PROP_CONTROL
15107
 
+};
15108
 
+
15109
 
+static void     gvc_speaker_test_class_init (GvcSpeakerTestClass *klass);
15110
 
+static void     gvc_speaker_test_init       (GvcSpeakerTest      *speaker_test);
15111
 
+static void     gvc_speaker_test_finalize   (GObject            *object);
15112
 
+static void     update_channel_map          (GvcSpeakerTest *speaker_test);
15113
 
+
15114
 
+G_DEFINE_TYPE (GvcSpeakerTest, gvc_speaker_test, GTK_TYPE_TABLE)
15115
 
+
15116
 
+static const int position_table[] = {
15117
 
+        /* Position, X, Y */
15118
 
+        PA_CHANNEL_POSITION_FRONT_LEFT, 0, 0,
15119
 
+        PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, 1, 0,
15120
 
+        PA_CHANNEL_POSITION_FRONT_CENTER, 2, 0,
15121
 
+        PA_CHANNEL_POSITION_MONO, 2, 0,
15122
 
+        PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, 3, 0,
15123
 
+        PA_CHANNEL_POSITION_FRONT_RIGHT, 4, 0,
15124
 
+        PA_CHANNEL_POSITION_SIDE_LEFT, 0, 1,
15125
 
+        PA_CHANNEL_POSITION_SIDE_RIGHT, 4, 1,
15126
 
+        PA_CHANNEL_POSITION_REAR_LEFT, 0, 2,
15127
 
+        PA_CHANNEL_POSITION_REAR_CENTER, 2, 2,
15128
 
+        PA_CHANNEL_POSITION_REAR_RIGHT, 4, 2,
15129
 
+        PA_CHANNEL_POSITION_LFE, 3, 2
15130
 
+};
15131
 
+
15132
 
+static void
15133
 
+gvc_speaker_test_set_property (GObject       *object,
15134
 
+                               guint          prop_id,
15135
 
+                               const GValue  *value,
15136
 
+                               GParamSpec    *pspec)
15137
 
+{
15138
 
+        GvcSpeakerTest *self = GVC_SPEAKER_TEST (object);
15139
 
+
15140
 
+        switch (prop_id) {
15141
 
+        case PROP_STREAM:
15142
 
+                self->priv->stream = g_value_dup_object (value);
15143
 
+                if (self->priv->control != NULL)
15144
 
+                        update_channel_map (self);
15145
 
+                break;
15146
 
+        case PROP_CONTROL:
15147
 
+                self->priv->control = g_value_dup_object (value);
15148
 
+                if (self->priv->stream != NULL)
15149
 
+                        update_channel_map (self);
15150
 
+                break;
15151
 
+        default:
15152
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
15153
 
+                break;
15154
 
+        }
15155
 
+}
15156
 
+
15157
 
+static void
15158
 
+gvc_speaker_test_get_property (GObject     *object,
15159
 
+                               guint        prop_id,
15160
 
+                               GValue      *value,
15161
 
+                               GParamSpec  *pspec)
15162
 
+{
15163
 
+        GvcSpeakerTest *self = GVC_SPEAKER_TEST (object);
15164
 
+
15165
 
+        switch (prop_id) {
15166
 
+        case PROP_STREAM:
15167
 
+                g_value_set_object (value, self->priv->stream);
15168
 
+                break;
15169
 
+        case PROP_CONTROL:
15170
 
+                g_value_set_object (value, self->priv->control);
15171
 
+                break;
15172
 
+        default:
15173
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
15174
 
+                break;
15175
 
+        }
15176
 
+}
15177
 
+
15178
 
+static void
15179
 
+gvc_speaker_test_class_init (GvcSpeakerTestClass *klass)
15180
 
+{
15181
 
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
15182
 
+
15183
 
+        object_class->finalize = gvc_speaker_test_finalize;
15184
 
+        object_class->set_property = gvc_speaker_test_set_property;
15185
 
+        object_class->get_property = gvc_speaker_test_get_property;
15186
 
+
15187
 
+        g_object_class_install_property (object_class,
15188
 
+                                         PROP_STREAM,
15189
 
+                                         g_param_spec_object ("stream",
15190
 
+                                                              "stream",
15191
 
+                                                              "The stream",
15192
 
+                                                              GVC_TYPE_MIXER_STREAM,
15193
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
15194
 
+        g_object_class_install_property (object_class,
15195
 
+                                         PROP_CONTROL,
15196
 
+                                         g_param_spec_object ("control",
15197
 
+                                                              "control",
15198
 
+                                                              "The mixer controller",
15199
 
+                                                              GVC_TYPE_MIXER_CONTROL,
15200
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
15201
 
+        g_type_class_add_private (klass, sizeof (GvcSpeakerTestPrivate));
15202
 
+}
15203
 
+
15204
 
+static const char *
15205
 
+sound_name (pa_channel_position_t position)
15206
 
+{
15207
 
+        switch (position) {
15208
 
+        case PA_CHANNEL_POSITION_FRONT_LEFT:
15209
 
+                return "audio-channel-front-left";
15210
 
+        case PA_CHANNEL_POSITION_FRONT_RIGHT:
15211
 
+                return "audio-channel-front-right";
15212
 
+        case PA_CHANNEL_POSITION_FRONT_CENTER:
15213
 
+                return "audio-channel-front-center";
15214
 
+        case PA_CHANNEL_POSITION_REAR_LEFT:
15215
 
+                return "audio-channel-rear-left";
15216
 
+        case PA_CHANNEL_POSITION_REAR_RIGHT:
15217
 
+                return "audio-channel-rear-right";
15218
 
+        case PA_CHANNEL_POSITION_REAR_CENTER:
15219
 
+                return "audio-channel-rear-center";
15220
 
+        case PA_CHANNEL_POSITION_LFE:
15221
 
+                return "audio-channel-lfe";
15222
 
+        case PA_CHANNEL_POSITION_SIDE_LEFT:
15223
 
+                return "audio-channel-side-left";
15224
 
+        case PA_CHANNEL_POSITION_SIDE_RIGHT:
15225
 
+                return "audio-channel-side-right";
15226
 
+        default:
15227
 
+                return NULL;
15228
 
+        }
15229
 
+}
15230
 
+
15231
 
+static const char *
15232
 
+icon_name (pa_channel_position_t position, gboolean playing)
15233
 
+{
15234
 
+        switch (position) {
15235
 
+        case PA_CHANNEL_POSITION_FRONT_LEFT:
15236
 
+                return playing ? "audio-speaker-left-testing" : "audio-speaker-left";
15237
 
+        case PA_CHANNEL_POSITION_FRONT_RIGHT:
15238
 
+                return playing ? "audio-speaker-right-testing" : "audio-speaker-right";
15239
 
+        case PA_CHANNEL_POSITION_FRONT_CENTER:
15240
 
+                return playing ? "audio-speaker-center-testing" : "audio-speaker-center";
15241
 
+        case PA_CHANNEL_POSITION_REAR_LEFT:
15242
 
+                return playing ? "audio-speaker-left-back-testing" : "audio-speaker-left-back";
15243
 
+        case PA_CHANNEL_POSITION_REAR_RIGHT:
15244
 
+                return playing ? "audio-speaker-right-back-testing" : "audio-speaker-right-back";
15245
 
+        case PA_CHANNEL_POSITION_REAR_CENTER:
15246
 
+                return playing ? "audio-speaker-center-back-testing" : "audio-speaker-center-back";
15247
 
+        case PA_CHANNEL_POSITION_LFE:
15248
 
+                return playing ? "audio-subwoofer-testing" : "audio-subwoofer";
15249
 
+        case PA_CHANNEL_POSITION_SIDE_LEFT:
15250
 
+                return playing ? "audio-speaker-left-side-testing" : "audio-speaker-left-side";
15251
 
+        case PA_CHANNEL_POSITION_SIDE_RIGHT:
15252
 
+                return playing ? "audio-speaker-right-side-testing" : "audio-speaker-right-side";
15253
 
+        default:
15254
 
+                return NULL;
15255
 
+        }
15256
 
+}
15257
 
+
15258
 
+static void
15259
 
+update_button (GtkWidget *control)
15260
 
+{
15261
 
+        GtkWidget *button;
15262
 
+        GtkWidget *image;
15263
 
+        pa_channel_position_t position;
15264
 
+        gboolean playing;
15265
 
+
15266
 
+        button = g_object_get_data (G_OBJECT (control), "button");
15267
 
+        image = g_object_get_data (G_OBJECT (control), "image");
15268
 
+        position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (control), "position"));
15269
 
+        playing = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (control), "playing"));
15270
 
+        gtk_button_set_label (GTK_BUTTON (button), playing ? _("Stop") : _("Test"));
15271
 
+        gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name (position, playing), GTK_ICON_SIZE_DIALOG);
15272
 
+}
15273
 
+
15274
 
+static const char *
15275
 
+pretty_position (pa_channel_position_t position)
15276
 
+{
15277
 
+        if (position == PA_CHANNEL_POSITION_LFE)
15278
 
+                return N_("Subwoofer");
15279
 
+
15280
 
+        return pa_channel_position_to_pretty_string (position);
15281
 
+}
15282
 
+
15283
 
+static gboolean
15284
 
+idle_cb (GtkWidget *control)
15285
 
+{
15286
 
+        if (control == NULL)
15287
 
+                return FALSE;
15288
 
+
15289
 
+        /* This is called in the background thread, hence
15290
 
+         * forward to main thread via idle callback */
15291
 
+        g_object_set_data (G_OBJECT (control), "playing", GINT_TO_POINTER(FALSE));
15292
 
+        update_button (control);
15293
 
+
15294
 
+        return FALSE;
15295
 
+}
15296
 
+
15297
 
+static void
15298
 
+finish_cb (ca_context *c, uint32_t id, int error_code, void *userdata)
15299
 
+{
15300
 
+        GtkWidget *control = (GtkWidget *) userdata;
15301
 
+
15302
 
+        if (error_code == CA_ERROR_DESTROYED || control == NULL)
15303
 
+                return;
15304
 
+        g_idle_add ((GSourceFunc) idle_cb, control);
15305
 
+}
15306
 
+
15307
 
+static void
15308
 
+on_test_button_clicked (GtkButton *button,
15309
 
+                        GtkWidget *control)
15310
 
+{
15311
 
+        gboolean playing;
15312
 
+        ca_context *canberra;
15313
 
+
15314
 
+        canberra = g_object_get_data (G_OBJECT (control), "canberra");
15315
 
+
15316
 
+        ca_context_cancel (canberra, 1);
15317
 
+
15318
 
+        playing = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (control), "playing"));
15319
 
+
15320
 
+        if (playing) {
15321
 
+                g_object_set_data (G_OBJECT (control), "playing", GINT_TO_POINTER(FALSE));
15322
 
+        } else {
15323
 
+                pa_channel_position_t position;
15324
 
+                const char *name;
15325
 
+                ca_proplist *proplist;
15326
 
+
15327
 
+                position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (control), "position"));
15328
 
+
15329
 
+                ca_proplist_create (&proplist);
15330
 
+                ca_proplist_sets (proplist, CA_PROP_MEDIA_ROLE, "test");
15331
 
+                ca_proplist_sets (proplist, CA_PROP_MEDIA_NAME, pretty_position (position));
15332
 
+                ca_proplist_sets (proplist, CA_PROP_CANBERRA_FORCE_CHANNEL,
15333
 
+                                  pa_channel_position_to_string (position));
15334
 
+                ca_proplist_sets (proplist, CA_PROP_CANBERRA_ENABLE, "1");
15335
 
+
15336
 
+                name = sound_name (position);
15337
 
+                if (name != NULL) {
15338
 
+                        ca_proplist_sets (proplist, CA_PROP_EVENT_ID, name);
15339
 
+                        playing = ca_context_play_full (canberra, 1, proplist, finish_cb, control) >= 0;
15340
 
+                }
15341
 
+
15342
 
+                if (!playing) {
15343
 
+                        ca_proplist_sets (proplist, CA_PROP_EVENT_ID, "audio-test-signal");
15344
 
+                        playing = ca_context_play_full (canberra, 1, proplist, finish_cb, control) >= 0;
15345
 
+                }
15346
 
+
15347
 
+                if (!playing) {
15348
 
+                        ca_proplist_sets(proplist, CA_PROP_EVENT_ID, "bell-window-system");
15349
 
+                        playing = ca_context_play_full (canberra, 1, proplist, finish_cb, control) >= 0;
15350
 
+                }
15351
 
+                g_object_set_data (G_OBJECT (control), "playing", GINT_TO_POINTER(playing));
15352
 
+        }
15353
 
+
15354
 
+        update_button (control);
15355
 
+}
15356
 
+
15357
 
+static GtkWidget *
15358
 
+channel_control_new (ca_context *canberra, pa_channel_position_t position)
15359
 
+{
15360
 
+        GtkWidget *control;
15361
 
+        GtkWidget *box;
15362
 
+        GtkWidget *label;
15363
 
+        GtkWidget *image;
15364
 
+        GtkWidget *test_button;
15365
 
+        const char *name;
15366
 
+
15367
 
+        control = gtk_vbox_new (FALSE, 6);
15368
 
+        g_object_set_data (G_OBJECT (control), "playing", GINT_TO_POINTER(FALSE));
15369
 
+        g_object_set_data (G_OBJECT (control), "position", GINT_TO_POINTER(position));
15370
 
+        g_object_set_data (G_OBJECT (control), "canberra", canberra);
15371
 
+
15372
 
+        name = icon_name (position, FALSE);
15373
 
+        if (name == NULL)
15374
 
+                name = "audio-volume-medium";
15375
 
+        image = gtk_image_new_from_icon_name (name, GTK_ICON_SIZE_DIALOG);
15376
 
+        g_object_set_data (G_OBJECT (control), "image", image);
15377
 
+        gtk_box_pack_start (GTK_BOX (control), image, FALSE, FALSE, 0);
15378
 
+
15379
 
+        label = gtk_label_new (pretty_position (position));
15380
 
+        gtk_box_pack_start (GTK_BOX (control), label, FALSE, FALSE, 0);
15381
 
+
15382
 
+        test_button = gtk_button_new_with_label (_("Test"));
15383
 
+        
15384
 
+        g_signal_connect (G_OBJECT (test_button), "clicked",
15385
 
+                          G_CALLBACK (on_test_button_clicked), control);
15386
 
+        g_object_set_data (G_OBJECT (control), "button", test_button);
15387
 
+
15388
 
+        atk_object_add_relationship (gtk_widget_get_accessible (test_button),
15389
 
+                                     ATK_RELATION_LABELLED_BY,
15390
 
+                                     gtk_widget_get_accessible (label));
15391
 
+
15392
 
+        box = gtk_hbox_new (FALSE, 0);
15393
 
+        gtk_box_pack_start (GTK_BOX (box), test_button, TRUE, FALSE, 0);
15394
 
+        gtk_box_pack_start (GTK_BOX (control), box, FALSE, FALSE, 0);
15395
 
+
15396
 
+        gtk_widget_show_all (control);
15397
 
+
15398
 
+        return control;
15399
 
+}
15400
 
+
15401
 
+static void
15402
 
+create_channel_controls (GvcSpeakerTest *speaker_test)
15403
 
+{
15404
 
+        guint i;
15405
 
+
15406
 
+        for (i = 0; i < G_N_ELEMENTS (position_table); i += 3) {
15407
 
+                speaker_test->priv->channel_controls[position_table[i]] = channel_control_new (speaker_test->priv->canberra, (pa_channel_position_t) position_table[i]);
15408
 
+                gtk_table_attach (GTK_TABLE (speaker_test),
15409
 
+                                  speaker_test->priv->channel_controls[position_table[i]],
15410
 
+                                  position_table[i+1],
15411
 
+                                  position_table[i+1]+1,
15412
 
+                                  position_table[i+2],
15413
 
+                                  position_table[i+2]+1,
15414
 
+                                  GTK_EXPAND, GTK_EXPAND, 0, 0);
15415
 
+        }
15416
 
+}
15417
 
+
15418
 
+#if 0
15419
 
+static const GvcChannelMap *
15420
 
+get_channel_map_for_card (GvcMixerControl *control,
15421
 
+                          GvcMixerCard    *card,
15422
 
+                          char           **output_name)
15423
 
+{
15424
 
+        int card_index;
15425
 
+        GSList *sinks, *l;
15426
 
+        GvcMixerStream *stream;
15427
 
+        const GvcChannelMap *map;
15428
 
+
15429
 
+        /* This gets the channel map for the only
15430
 
+         * output for the card */
15431
 
+
15432
 
+        card_index = gvc_mixer_card_get_index (card);
15433
 
+        if (card_index == PA_INVALID_INDEX)
15434
 
+                return NULL;
15435
 
+        sinks = gvc_mixer_control_get_sinks (control);
15436
 
+        stream = NULL;
15437
 
+        for (l = sinks; l != NULL; l = l->next) {
15438
 
+                GvcMixerStream *s = l->data;
15439
 
+                if (gvc_mixer_stream_get_card_index (s) == card_index) {
15440
 
+                        stream = g_object_ref (s);
15441
 
+                        break;
15442
 
+                }
15443
 
+        }
15444
 
+        g_slist_free (sinks);
15445
 
+
15446
 
+        if (stream == NULL)
15447
 
+               return NULL;
15448
 
+
15449
 
+        g_debug ("Found stream '%s' for card '%s'",
15450
 
+                 gvc_mixer_stream_get_name (stream),
15451
 
+                 gvc_mixer_card_get_name (card));
15452
 
+
15453
 
+        *output_name = g_strdup (gvc_mixer_stream_get_name (stream));
15454
 
+        map = gvc_mixer_stream_get_channel_map (stream);
15455
 
+
15456
 
+        g_debug ("Got channel map '%s' for port '%s'",
15457
 
+                 gvc_channel_map_get_mapping (map), *output_name);
15458
 
+
15459
 
+        return map;
15460
 
+}
15461
 
+#endif
15462
 
+
15463
 
+static void
15464
 
+update_channel_map (GvcSpeakerTest *speaker_test)
15465
 
+{
15466
 
+        guint i;
15467
 
+        const GvcChannelMap *map;
15468
 
+        char *output_name;
15469
 
+
15470
 
+        g_return_if_fail (speaker_test->priv->control != NULL);
15471
 
+        g_return_if_fail (speaker_test->priv->stream != NULL);
15472
 
+
15473
 
+        g_debug ("XXX update_channel_map called XXX");
15474
 
+
15475
 
+        map = gvc_mixer_stream_get_channel_map (speaker_test->priv->stream);
15476
 
+/*
15477
 
+        map = get_channel_map_for_stream (speaker_test->priv->control,
15478
 
+                                        speaker_test->priv->stream,
15479
 
+                                        &output_name);
15480
 
+*/
15481
 
+        g_return_if_fail (map != NULL);
15482
 
+
15483
 
+        ca_context_change_device (speaker_test->priv->canberra, 
15484
 
+                                  gvc_mixer_stream_get_name (speaker_test->priv->stream));
15485
 
+        g_free (output_name);
15486
 
+
15487
 
+        for (i = 0; i < G_N_ELEMENTS (position_table); i += 3) {
15488
 
+                gtk_widget_set_visible (speaker_test->priv->channel_controls[position_table[i]],
15489
 
+                                        gvc_channel_map_has_position(map, position_table[i]));
15490
 
+        }
15491
 
+}
15492
 
+
15493
 
+static void
15494
 
+gvc_speaker_test_set_theme (ca_context *ca)
15495
 
+{
15496
 
+        GtkSettings *settings;
15497
 
+        char *theme_name;
15498
 
+
15499
 
+        settings = gtk_settings_get_for_screen (gdk_screen_get_default ());
15500
 
+
15501
 
+        g_object_get (G_OBJECT (settings),
15502
 
+                      "gtk-sound-theme-name", &theme_name,
15503
 
+                      NULL);
15504
 
+
15505
 
+        if (theme_name)
15506
 
+                ca_context_change_props (ca, CA_PROP_CANBERRA_XDG_THEME_NAME, theme_name, NULL);
15507
 
+
15508
 
+        g_free (theme_name);
15509
 
+}
15510
 
+
15511
 
+static void
15512
 
+gvc_speaker_test_init (GvcSpeakerTest *speaker_test)
15513
 
+{
15514
 
+        GtkWidget *face;
15515
 
+
15516
 
+        speaker_test->priv = GVC_SPEAKER_TEST_GET_PRIVATE (speaker_test);
15517
 
+
15518
 
+        ca_context_create (&speaker_test->priv->canberra);
15519
 
+        ca_context_set_driver (speaker_test->priv->canberra, "pulse");
15520
 
+        ca_context_change_props (speaker_test->priv->canberra,
15521
 
+                                 CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl",
15522
 
+                                 NULL);
15523
 
+        gvc_speaker_test_set_theme (speaker_test->priv->canberra);
15524
 
+
15525
 
+        gtk_widget_set_direction (GTK_WIDGET (speaker_test), GTK_TEXT_DIR_LTR);
15526
 
+        gtk_table_resize (GTK_TABLE (speaker_test), 3, 5);
15527
 
+        gtk_container_set_border_width (GTK_CONTAINER (speaker_test), 12);
15528
 
+        gtk_table_set_homogeneous (GTK_TABLE (speaker_test), TRUE);
15529
 
+        gtk_table_set_row_spacings (GTK_TABLE (speaker_test), 12);
15530
 
+        gtk_table_set_col_spacings (GTK_TABLE (speaker_test), 12);
15531
 
+
15532
 
+        create_channel_controls (speaker_test);
15533
 
+
15534
 
+        face = gtk_image_new_from_icon_name ("face-smile", GTK_ICON_SIZE_DIALOG);
15535
 
+        gtk_table_attach (GTK_TABLE (speaker_test), face,
15536
 
+                          2, 3, 1, 2, GTK_EXPAND, GTK_EXPAND, 0, 0);
15537
 
+        gtk_widget_show (face);
15538
 
+}
15539
 
+
15540
 
+static void
15541
 
+gvc_speaker_test_finalize (GObject *object)
15542
 
+{
15543
 
+        GvcSpeakerTest *speaker_test;
15544
 
+
15545
 
+        g_return_if_fail (object != NULL);
15546
 
+        g_return_if_fail (GVC_IS_SPEAKER_TEST (object));
15547
 
+
15548
 
+        speaker_test = GVC_SPEAKER_TEST (object);
15549
 
+
15550
 
+        g_return_if_fail (speaker_test->priv != NULL);
15551
 
+
15552
 
+        g_object_unref (speaker_test->priv->stream);
15553
 
+        speaker_test->priv->stream = NULL;
15554
 
+
15555
 
+        g_object_unref (speaker_test->priv->control);
15556
 
+        speaker_test->priv->control = NULL;
15557
 
+
15558
 
+        ca_context_destroy (speaker_test->priv->canberra);
15559
 
+        speaker_test->priv->canberra = NULL;
15560
 
+
15561
 
+        G_OBJECT_CLASS (gvc_speaker_test_parent_class)->finalize (object);
15562
 
+}
15563
 
+
15564
 
+GtkWidget *
15565
 
+gvc_speaker_test_new (GvcMixerControl *control,
15566
 
+                      GvcMixerStream *stream)
15567
 
+{
15568
 
+        GObject *speaker_test;
15569
 
+
15570
 
+        g_return_val_if_fail (stream != NULL, NULL);
15571
 
+        g_return_val_if_fail (control != NULL, NULL);
15572
 
+
15573
 
+        speaker_test = g_object_new (GVC_TYPE_SPEAKER_TEST,
15574
 
+                                  "stream", stream,
15575
 
+                                  "control", control,
15576
 
+                                  NULL);
15577
 
+
15578
 
+        return GTK_WIDGET (speaker_test);
15579
 
+}
15580
 
+
15581
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-speaker-test.h
15582
 
===================================================================
15583
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
15584
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-speaker-test.h      2012-08-28 17:08:49.464516900 +0200
15585
 
@@ -0,0 +1,57 @@
15586
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
15587
 
+ *
15588
 
+ * Copyright (C) 2009 Red Hat, Inc.
15589
 
+ *
15590
 
+ * This program is free software; you can redistribute it and/or modify
15591
 
+ * it under the terms of the GNU General Public License as published by
15592
 
+ * the Free Software Foundation; either version 2 of the License, or
15593
 
+ * (at your option) any later version.
15594
 
+ *
15595
 
+ * This program is distributed in the hope that it will be useful,
15596
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15597
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15598
 
+ * GNU General Public License for more details.
15599
 
+ *
15600
 
+ * You should have received a copy of the GNU General Public License
15601
 
+ * along with this program; if not, write to the Free Software
15602
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15603
 
+ *
15604
 
+ */
15605
 
+
15606
 
+#ifndef __GVC_SPEAKER_TEST_H
15607
 
+#define __GVC_SPEAKER_TEST_H
15608
 
+
15609
 
+#include <glib-object.h>
15610
 
+#include <gvc-mixer-card.h>
15611
 
+#include <gvc-mixer-control.h>
15612
 
+
15613
 
+G_BEGIN_DECLS
15614
 
+
15615
 
+#define GVC_TYPE_SPEAKER_TEST         (gvc_speaker_test_get_type ())
15616
 
+#define GVC_SPEAKER_TEST(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_SPEAKER_TEST, GvcSpeakerTest))
15617
 
+#define GVC_SPEAKER_TEST_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_SPEAKER_TEST, GvcSpeakerTestClass))
15618
 
+#define GVC_IS_SPEAKER_TEST(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_SPEAKER_TEST))
15619
 
+#define GVC_IS_SPEAKER_TEST_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_SPEAKER_TEST))
15620
 
+#define GVC_SPEAKER_TEST_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_SPEAKER_TEST, GvcSpeakerTestClass))
15621
 
+
15622
 
+typedef struct GvcSpeakerTestPrivate GvcSpeakerTestPrivate;
15623
 
+
15624
 
+typedef struct
15625
 
+{
15626
 
+        GtkNotebook               parent;
15627
 
+        GvcSpeakerTestPrivate *priv;
15628
 
+} GvcSpeakerTest;
15629
 
+
15630
 
+typedef struct
15631
 
+{
15632
 
+        GtkNotebookClass        parent_class;
15633
 
+} GvcSpeakerTestClass;
15634
 
+
15635
 
+GType               gvc_speaker_test_get_type            (void);
15636
 
+
15637
 
+GtkWidget *         gvc_speaker_test_new                 (GvcMixerControl *control,
15638
 
+                                                          GvcMixerStream *stream);
15639
 
+
15640
 
+G_END_DECLS
15641
 
+
15642
 
+#endif /* __GVC_SPEAKER_TEST_H */
15643
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-stream-status-icon.c
15644
 
===================================================================
15645
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
15646
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-stream-status-icon.c        2012-08-28 17:08:49.468516900 +0200
15647
 
@@ -0,0 +1,780 @@
15648
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
15649
 
+ *
15650
 
+ * Copyright (C) 2008 William Jon McCann
15651
 
+ *
15652
 
+ * This program is free software; you can redistribute it and/or modify
15653
 
+ * it under the terms of the GNU General Public License as published by
15654
 
+ * the Free Software Foundation; either version 2 of the License, or
15655
 
+ * (at your option) any later version.
15656
 
+ *
15657
 
+ * This program is distributed in the hope that it will be useful,
15658
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15659
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15660
 
+ * GNU General Public License for more details.
15661
 
+ *
15662
 
+ * You should have received a copy of the GNU General Public License
15663
 
+ * along with this program; if not, write to the Free Software
15664
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15665
 
+ *
15666
 
+ */
15667
 
+
15668
 
+#include "config.h"
15669
 
+
15670
 
+#include <stdlib.h>
15671
 
+#include <stdio.h>
15672
 
+#include <unistd.h>
15673
 
+
15674
 
+#include <glib.h>
15675
 
+#include <glib/gi18n.h>
15676
 
+#include <gdk/gdkkeysyms.h>
15677
 
+#include <gtk/gtk.h>
15678
 
+#include <pulse/pulseaudio.h>
15679
 
+
15680
 
+#include "gvc-mixer-stream.h"
15681
 
+#include "gvc-channel-bar.h"
15682
 
+#include "gvc-stream-status-icon.h"
15683
 
+
15684
 
+#define GVC_STREAM_STATUS_ICON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_STREAM_STATUS_ICON, GvcStreamStatusIconPrivate))
15685
 
+
15686
 
+struct GvcStreamStatusIconPrivate
15687
 
+{
15688
 
+        char          **icon_names;
15689
 
+        GvcMixerStream *mixer_stream;
15690
 
+        GtkWidget      *dock;
15691
 
+        GtkWidget      *bar;
15692
 
+        guint           current_icon;
15693
 
+        char           *display_name;
15694
 
+        gboolean        thaw;
15695
 
+};
15696
 
+
15697
 
+enum
15698
 
+{
15699
 
+        PROP_0,
15700
 
+        PROP_DISPLAY_NAME,
15701
 
+        PROP_MIXER_STREAM,
15702
 
+        PROP_ICON_NAMES,
15703
 
+};
15704
 
+
15705
 
+static void     gvc_stream_status_icon_class_init (GvcStreamStatusIconClass *klass);
15706
 
+static void     gvc_stream_status_icon_init       (GvcStreamStatusIcon      *stream_status_icon);
15707
 
+static void     gvc_stream_status_icon_finalize   (GObject                  *object);
15708
 
+
15709
 
+G_DEFINE_TYPE (GvcStreamStatusIcon, gvc_stream_status_icon, GTK_TYPE_STATUS_ICON)
15710
 
+
15711
 
+static void
15712
 
+on_adjustment_value_changed (GtkAdjustment *adjustment,
15713
 
+                             GvcStreamStatusIcon     *icon)
15714
 
+{
15715
 
+        gdouble volume;
15716
 
+
15717
 
+        if (icon->priv->thaw)
15718
 
+                return;
15719
 
+
15720
 
+        volume = gtk_adjustment_get_value (adjustment);
15721
 
+
15722
 
+        /* Only push the volume if it's actually changed */
15723
 
+        if (gvc_mixer_stream_set_volume(icon->priv->mixer_stream,
15724
 
+                                    (pa_volume_t) round (volume)) != FALSE) {
15725
 
+                gvc_mixer_stream_push_volume(icon->priv->mixer_stream);
15726
 
+        }
15727
 
+}
15728
 
+
15729
 
+static void
15730
 
+update_dock (GvcStreamStatusIcon *icon)
15731
 
+{
15732
 
+        GtkAdjustment *adj;
15733
 
+        gboolean       is_muted;
15734
 
+
15735
 
+        g_return_if_fail (icon);
15736
 
+
15737
 
+        adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (icon->priv->bar)));
15738
 
+
15739
 
+        icon->priv->thaw = TRUE;
15740
 
+        gtk_adjustment_set_value (adj,
15741
 
+                                  gvc_mixer_stream_get_volume (icon->priv->mixer_stream));
15742
 
+        is_muted = gvc_mixer_stream_get_is_muted (icon->priv->mixer_stream);
15743
 
+        gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (icon->priv->bar), is_muted);
15744
 
+        icon->priv->thaw = FALSE;
15745
 
+}
15746
 
+
15747
 
+static gboolean
15748
 
+popup_dock (GvcStreamStatusIcon *icon,
15749
 
+            guint                time)
15750
 
+{
15751
 
+        GdkRectangle   area;
15752
 
+        GtkOrientation orientation;
15753
 
+        GdkDisplay    *display;
15754
 
+        GdkScreen     *screen;
15755
 
+        gboolean       res;
15756
 
+        int            x;
15757
 
+        int            y;
15758
 
+        int            monitor_num;
15759
 
+        GdkRectangle   monitor;
15760
 
+        GtkRequisition dock_req;
15761
 
+
15762
 
+        update_dock (icon);
15763
 
+
15764
 
+        screen = gtk_status_icon_get_screen (GTK_STATUS_ICON (icon));
15765
 
+        res = gtk_status_icon_get_geometry (GTK_STATUS_ICON (icon),
15766
 
+                                            &screen,
15767
 
+                                            &area,
15768
 
+                                            &orientation);
15769
 
+        if (! res) {
15770
 
+                g_warning ("Unable to determine geometry of status icon");
15771
 
+                return FALSE;
15772
 
+        }
15773
 
+
15774
 
+        /* position roughly */
15775
 
+        gtk_window_set_screen (GTK_WINDOW (icon->priv->dock), screen);
15776
 
+        gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (icon->priv->bar),
15777
 
+                                         1 - orientation);
15778
 
+
15779
 
+        monitor_num = gdk_screen_get_monitor_at_point (screen, area.x, area.y);
15780
 
+        gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
15781
 
+
15782
 
+        gtk_container_foreach (GTK_CONTAINER (icon->priv->dock),
15783
 
+                               (GtkCallback) gtk_widget_show_all, NULL);
15784
 
+        gtk_widget_get_preferred_size (icon->priv->dock, &dock_req, NULL);
15785
 
+
15786
 
+        if (orientation == GTK_ORIENTATION_VERTICAL) {
15787
 
+                if (area.x + area.width + dock_req.width <= monitor.x + monitor.width) {
15788
 
+                        x = area.x + area.width;
15789
 
+                } else {
15790
 
+                        x = area.x - dock_req.width;
15791
 
+                }
15792
 
+                if (area.y + dock_req.height <= monitor.y + monitor.height) {
15793
 
+                        y = area.y;
15794
 
+                } else {
15795
 
+                        y = monitor.y + monitor.height - dock_req.height;
15796
 
+                }
15797
 
+        } else {
15798
 
+                if (area.y + area.height + dock_req.height <= monitor.y + monitor.height) {
15799
 
+                        y = area.y + area.height;
15800
 
+                } else {
15801
 
+                        y = area.y - dock_req.height;
15802
 
+                }
15803
 
+                if (area.x + dock_req.width <= monitor.x + monitor.width) {
15804
 
+                        x = area.x;
15805
 
+                } else {
15806
 
+                        x = monitor.x + monitor.width - dock_req.width;
15807
 
+                }
15808
 
+        }
15809
 
+
15810
 
+        gtk_window_move (GTK_WINDOW (icon->priv->dock), x, y);
15811
 
+
15812
 
+        /* FIXME: without this, the popup window appears as a square
15813
 
+         * after changing the orientation
15814
 
+         */
15815
 
+        gtk_window_resize (GTK_WINDOW (icon->priv->dock), 1, 1);
15816
 
+
15817
 
+        gtk_widget_show_all (icon->priv->dock);
15818
 
+
15819
 
+        /* grab focus */
15820
 
+        gtk_grab_add (icon->priv->dock);
15821
 
+
15822
 
+        if (gdk_pointer_grab (gtk_widget_get_window (icon->priv->dock), TRUE,
15823
 
+                              GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
15824
 
+                              GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK, NULL, NULL,
15825
 
+                              time)
15826
 
+            != GDK_GRAB_SUCCESS) {
15827
 
+                gtk_grab_remove (icon->priv->dock);
15828
 
+                gtk_widget_hide (icon->priv->dock);
15829
 
+                return FALSE;
15830
 
+        }
15831
 
+
15832
 
+        if (gdk_keyboard_grab (gtk_widget_get_window (icon->priv->dock), TRUE, time) != GDK_GRAB_SUCCESS) {
15833
 
+                display = gtk_widget_get_display (icon->priv->dock);
15834
 
+                gdk_display_pointer_ungrab (display, time);
15835
 
+                gtk_grab_remove (icon->priv->dock);
15836
 
+                gtk_widget_hide (icon->priv->dock);
15837
 
+                return FALSE;
15838
 
+        }
15839
 
+
15840
 
+        gtk_widget_grab_focus (icon->priv->dock);
15841
 
+
15842
 
+        return TRUE;
15843
 
+}
15844
 
+
15845
 
+static void
15846
 
+on_status_icon_activate (GtkStatusIcon       *status_icon,
15847
 
+                         GvcStreamStatusIcon *icon)
15848
 
+{
15849
 
+        popup_dock (icon, GDK_CURRENT_TIME);
15850
 
+}
15851
 
+
15852
 
+static void
15853
 
+on_menu_mute_toggled (GtkMenuItem         *item,
15854
 
+                      GvcStreamStatusIcon *icon)
15855
 
+{
15856
 
+        gboolean is_muted;
15857
 
+        is_muted = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item));
15858
 
+        gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (icon->priv->bar), is_muted);
15859
 
+}
15860
 
+
15861
 
+static void
15862
 
+on_menu_activate_open_volume_control (GtkMenuItem *item,
15863
 
+                                      GvcStreamStatusIcon   *icon)
15864
 
+{
15865
 
+        GAppInfo *app;
15866
 
+        GdkAppLaunchContext *context;
15867
 
+        GError *error;
15868
 
+
15869
 
+        error = NULL;
15870
 
+        context = gdk_app_launch_context_new ();
15871
 
+        app = g_app_info_create_from_commandline ("gnome-control-center sound", "Sound preferences", 0, &error);
15872
 
+        if (app)
15873
 
+                g_app_info_launch (app, NULL, G_APP_LAUNCH_CONTEXT (context), &error);
15874
 
+
15875
 
+        if (error != NULL) {
15876
 
+                GtkWidget *dialog;
15877
 
+
15878
 
+                dialog = gtk_message_dialog_new (NULL,
15879
 
+                                                 0,
15880
 
+                                                 GTK_MESSAGE_ERROR,
15881
 
+                                                 GTK_BUTTONS_CLOSE,
15882
 
+                                                 _("Failed to start Sound Preferences: %s"),
15883
 
+                                                 error->message);
15884
 
+                g_signal_connect (dialog,
15885
 
+                                  "response",
15886
 
+                                  G_CALLBACK (gtk_widget_destroy),
15887
 
+                                  NULL);
15888
 
+                gtk_widget_show (dialog);
15889
 
+                g_error_free (error);
15890
 
+        }
15891
 
+
15892
 
+        g_object_unref (context);
15893
 
+        g_object_unref (app);
15894
 
+}
15895
 
+
15896
 
+static void
15897
 
+on_status_icon_popup_menu (GtkStatusIcon       *status_icon,
15898
 
+                           guint                button,
15899
 
+                           guint                activate_time,
15900
 
+                           GvcStreamStatusIcon *icon)
15901
 
+{
15902
 
+        GtkWidget *menu;
15903
 
+        GtkWidget *item;
15904
 
+        GtkWidget *image;
15905
 
+
15906
 
+        menu = gtk_menu_new ();
15907
 
+
15908
 
+        item = gtk_check_menu_item_new_with_mnemonic (_("_Mute"));
15909
 
+        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
15910
 
+                                        gvc_mixer_stream_get_is_muted (icon->priv->mixer_stream));
15911
 
+        g_signal_connect (item,
15912
 
+                          "toggled",
15913
 
+                          G_CALLBACK (on_menu_mute_toggled),
15914
 
+                          icon);
15915
 
+        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
15916
 
+
15917
 
+        item = gtk_image_menu_item_new_with_mnemonic (_("_Sound Preferences"));
15918
 
+        image = gtk_image_new_from_icon_name ("multimedia-volume-control",
15919
 
+                                              GTK_ICON_SIZE_MENU);
15920
 
+        gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
15921
 
+        g_signal_connect (item,
15922
 
+                          "activate",
15923
 
+                          G_CALLBACK (on_menu_activate_open_volume_control),
15924
 
+                          icon);
15925
 
+        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
15926
 
+
15927
 
+        gtk_widget_show_all (menu);
15928
 
+        gtk_menu_popup (GTK_MENU (menu),
15929
 
+                        NULL,
15930
 
+                        NULL,
15931
 
+                        gtk_status_icon_position_menu,
15932
 
+                        status_icon,
15933
 
+                        button,
15934
 
+                        activate_time);
15935
 
+}
15936
 
+
15937
 
+static gboolean
15938
 
+on_status_icon_scroll_event (GtkStatusIcon       *status_icon,
15939
 
+                             GdkEventScroll      *event,
15940
 
+                             GvcStreamStatusIcon *icon)
15941
 
+{
15942
 
+        return gvc_channel_bar_scroll (GVC_CHANNEL_BAR (icon->priv->bar), event);
15943
 
+}
15944
 
+
15945
 
+static void
15946
 
+gvc_icon_release_grab (GvcStreamStatusIcon *icon,
15947
 
+                         GdkEventButton    *event)
15948
 
+{
15949
 
+        GdkDisplay     *display;
15950
 
+
15951
 
+        /* ungrab focus */
15952
 
+        display = gtk_widget_get_display (GTK_WIDGET (icon->priv->dock));
15953
 
+        gdk_display_keyboard_ungrab (display, event->time);
15954
 
+        gdk_display_pointer_ungrab (display, event->time);
15955
 
+        gtk_grab_remove (icon->priv->dock);
15956
 
+
15957
 
+        /* hide again */
15958
 
+        gtk_widget_hide (icon->priv->dock);
15959
 
+}
15960
 
+
15961
 
+static gboolean
15962
 
+on_dock_button_press (GtkWidget      *widget,
15963
 
+                      GdkEventButton *event,
15964
 
+                      GvcStreamStatusIcon      *icon)
15965
 
+{
15966
 
+        if (event->type == GDK_BUTTON_PRESS) {
15967
 
+                gvc_icon_release_grab (icon, event);
15968
 
+                return TRUE;
15969
 
+        }
15970
 
+
15971
 
+        return FALSE;
15972
 
+}
15973
 
+
15974
 
+static void
15975
 
+popdown_dock (GvcStreamStatusIcon *icon)
15976
 
+{
15977
 
+        GdkDisplay *display;
15978
 
+
15979
 
+        /* ungrab focus */
15980
 
+        display = gtk_widget_get_display (icon->priv->dock);
15981
 
+        gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
15982
 
+        gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
15983
 
+        gtk_grab_remove (icon->priv->dock);
15984
 
+
15985
 
+        /* hide again */
15986
 
+        gtk_widget_hide (icon->priv->dock);
15987
 
+}
15988
 
+
15989
 
+static gboolean
15990
 
+on_dock_key_release (GtkWidget           *widget,
15991
 
+                     GdkEventKey         *event,
15992
 
+                     GvcStreamStatusIcon *icon)
15993
 
+{
15994
 
+        if (event->keyval == GDK_KEY_Escape) {
15995
 
+                popdown_dock (icon);
15996
 
+                return TRUE;
15997
 
+        }
15998
 
+
15999
 
+#if 0
16000
 
+        if (!gtk_bindings_activate_event (GTK_OBJECT (widget), event)) {
16001
 
+                /* The popup hasn't managed the event, pass onto the button */
16002
 
+                gtk_bindings_activate_event (GTK_OBJECT (user_data), event);
16003
 
+        }
16004
 
+#endif
16005
 
+        return TRUE;
16006
 
+}
16007
 
+
16008
 
+static gboolean
16009
 
+on_dock_scroll_event (GtkWidget           *widget,
16010
 
+                      GdkEventScroll      *event,
16011
 
+                      GvcStreamStatusIcon *icon)
16012
 
+{
16013
 
+        /* Forward event to the status icon */
16014
 
+        on_status_icon_scroll_event (NULL, event, icon);
16015
 
+        return TRUE;
16016
 
+}
16017
 
+
16018
 
+static void
16019
 
+update_icon (GvcStreamStatusIcon *icon)
16020
 
+{
16021
 
+        guint    volume;
16022
 
+        gboolean is_muted;
16023
 
+        guint    n;
16024
 
+        char    *markup;
16025
 
+        gboolean can_decibel;
16026
 
+        gdouble  db;
16027
 
+
16028
 
+        if (icon->priv->mixer_stream == NULL) {
16029
 
+                return;
16030
 
+        }
16031
 
+
16032
 
+        volume = gvc_mixer_stream_get_volume (icon->priv->mixer_stream);
16033
 
+        is_muted = gvc_mixer_stream_get_is_muted (icon->priv->mixer_stream);
16034
 
+        db = gvc_mixer_stream_get_decibel (icon->priv->mixer_stream);
16035
 
+        can_decibel = gvc_mixer_stream_get_can_decibel (icon->priv->mixer_stream);
16036
 
+
16037
 
+        /* select image */
16038
 
+        if (volume <= 0 || is_muted) {
16039
 
+                n = 0;
16040
 
+        } else {
16041
 
+                n = 3 * volume / PA_VOLUME_NORM + 1;
16042
 
+                if (n < 1) {
16043
 
+                        n = 1;
16044
 
+                } else if (n > 3) {
16045
 
+                        n = 3;
16046
 
+                }
16047
 
+        }
16048
 
+
16049
 
+        /* apparently status icon will reset icon even if
16050
 
+         * if doesn't change */
16051
 
+        if (icon->priv->current_icon != n) {
16052
 
+                gtk_status_icon_set_from_icon_name (GTK_STATUS_ICON (icon),
16053
 
+                                                    icon->priv->icon_names [n]);
16054
 
+                icon->priv->current_icon = n;
16055
 
+        }
16056
 
+
16057
 
+
16058
 
+        if (is_muted) {
16059
 
+                markup = g_strdup_printf (
16060
 
+                                          "<b>%s: %s</b>\n<small>%s</small>",
16061
 
+                                          icon->priv->display_name,
16062
 
+                                          _("Muted"),
16063
 
+                                          gvc_mixer_stream_get_description (icon->priv->mixer_stream));
16064
 
+        } else if (can_decibel && (db > PA_DECIBEL_MININFTY)) {
16065
 
+                markup = g_strdup_printf (
16066
 
+                                          "<b>%s: %.0f%%</b>\n<small>%0.2f dB\n%s</small>",
16067
 
+                                          icon->priv->display_name,
16068
 
+                                          100 * (float)volume / PA_VOLUME_NORM,
16069
 
+                                          db,
16070
 
+                                          gvc_mixer_stream_get_description (icon->priv->mixer_stream));
16071
 
+        } else if (can_decibel) {
16072
 
+                markup = g_strdup_printf (
16073
 
+                                          "<b>%s: %.0f%%</b>\n<small>-&#8734; dB\n%s</small>",
16074
 
+                                          icon->priv->display_name,
16075
 
+                                          100 * (float)volume / PA_VOLUME_NORM,
16076
 
+                                          gvc_mixer_stream_get_description (icon->priv->mixer_stream));
16077
 
+        } else {
16078
 
+                markup = g_strdup_printf (
16079
 
+                                          "<b>%s: %.0f%%</b>\n<small>%s</small>",
16080
 
+                                          icon->priv->display_name,
16081
 
+                                          100 * (float)volume / PA_VOLUME_NORM,
16082
 
+                                          gvc_mixer_stream_get_description (icon->priv->mixer_stream));
16083
 
+        }
16084
 
+        gtk_status_icon_set_tooltip_markup (GTK_STATUS_ICON (icon), markup);
16085
 
+        g_free (markup);
16086
 
+}
16087
 
+
16088
 
+void
16089
 
+gvc_stream_status_icon_set_icon_names (GvcStreamStatusIcon  *icon,
16090
 
+                                       const char          **names)
16091
 
+{
16092
 
+        g_return_if_fail (GVC_IS_STREAM_STATUS_ICON (icon));
16093
 
+
16094
 
+        g_strfreev (icon->priv->icon_names);
16095
 
+        icon->priv->icon_names = g_strdupv ((char **)names);
16096
 
+        update_icon (icon);
16097
 
+        g_object_notify (G_OBJECT (icon), "icon-names");
16098
 
+}
16099
 
+
16100
 
+static void
16101
 
+on_stream_volume_notify (GObject             *object,
16102
 
+                         GParamSpec          *pspec,
16103
 
+                         GvcStreamStatusIcon *icon)
16104
 
+{
16105
 
+        update_icon (icon);
16106
 
+        update_dock (icon);
16107
 
+}
16108
 
+
16109
 
+static void
16110
 
+on_stream_is_muted_notify (GObject             *object,
16111
 
+                           GParamSpec          *pspec,
16112
 
+                           GvcStreamStatusIcon *icon)
16113
 
+{
16114
 
+        update_icon (icon);
16115
 
+        update_dock (icon);
16116
 
+}
16117
 
+
16118
 
+void
16119
 
+gvc_stream_status_icon_set_display_name (GvcStreamStatusIcon *icon,
16120
 
+                                         const char          *name)
16121
 
+{
16122
 
+        g_return_if_fail (GVC_STREAM_STATUS_ICON (icon));
16123
 
+
16124
 
+        g_free (icon->priv->display_name);
16125
 
+        icon->priv->display_name = g_strdup (name);
16126
 
+        update_icon (icon);
16127
 
+        g_object_notify (G_OBJECT (icon), "display-name");
16128
 
+}
16129
 
+
16130
 
+void
16131
 
+gvc_stream_status_icon_set_mixer_stream (GvcStreamStatusIcon *icon,
16132
 
+                                         GvcMixerStream      *stream)
16133
 
+{
16134
 
+        g_return_if_fail (GVC_STREAM_STATUS_ICON (icon));
16135
 
+
16136
 
+        if (stream != NULL) {
16137
 
+                g_object_ref (stream);
16138
 
+        }
16139
 
+
16140
 
+        if (icon->priv->mixer_stream != NULL) {
16141
 
+                g_signal_handlers_disconnect_by_func (icon->priv->mixer_stream,
16142
 
+                                                      G_CALLBACK (on_stream_volume_notify),
16143
 
+                                                      icon);
16144
 
+                g_signal_handlers_disconnect_by_func (icon->priv->mixer_stream,
16145
 
+                                                      G_CALLBACK (on_stream_is_muted_notify),
16146
 
+                                                      icon);
16147
 
+                g_object_unref (icon->priv->mixer_stream);
16148
 
+                icon->priv->mixer_stream = NULL;
16149
 
+        }
16150
 
+
16151
 
+        icon->priv->mixer_stream = stream;
16152
 
+
16153
 
+        if (icon->priv->mixer_stream != NULL) {
16154
 
+                GtkAdjustment *adj;
16155
 
+
16156
 
+                g_object_ref (icon->priv->mixer_stream);
16157
 
+
16158
 
+                icon->priv->thaw = TRUE;
16159
 
+                adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (icon->priv->bar)));
16160
 
+                gtk_adjustment_set_value (adj,
16161
 
+                                          gvc_mixer_stream_get_volume (icon->priv->mixer_stream));
16162
 
+                icon->priv->thaw = FALSE;
16163
 
+
16164
 
+                g_signal_connect (icon->priv->mixer_stream,
16165
 
+                                  "notify::volume",
16166
 
+                                  G_CALLBACK (on_stream_volume_notify),
16167
 
+                                  icon);
16168
 
+                g_signal_connect (icon->priv->mixer_stream,
16169
 
+                                  "notify::is-muted",
16170
 
+                                  G_CALLBACK (on_stream_is_muted_notify),
16171
 
+                                  icon);
16172
 
+        }
16173
 
+
16174
 
+        update_icon (icon);
16175
 
+
16176
 
+        g_object_notify (G_OBJECT (icon), "mixer-stream");
16177
 
+}
16178
 
+
16179
 
+static void
16180
 
+gvc_stream_status_icon_set_property (GObject       *object,
16181
 
+                                     guint          prop_id,
16182
 
+                                     const GValue  *value,
16183
 
+                                     GParamSpec    *pspec)
16184
 
+{
16185
 
+        GvcStreamStatusIcon *self = GVC_STREAM_STATUS_ICON (object);
16186
 
+
16187
 
+        switch (prop_id) {
16188
 
+        case PROP_MIXER_STREAM:
16189
 
+                gvc_stream_status_icon_set_mixer_stream (self, g_value_get_object (value));
16190
 
+                break;
16191
 
+        case PROP_DISPLAY_NAME:
16192
 
+                gvc_stream_status_icon_set_display_name (self, g_value_get_string (value));
16193
 
+                break;
16194
 
+        case PROP_ICON_NAMES:
16195
 
+                gvc_stream_status_icon_set_icon_names (self, g_value_get_boxed (value));
16196
 
+                break;
16197
 
+        default:
16198
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
16199
 
+                break;
16200
 
+        }
16201
 
+}
16202
 
+
16203
 
+static void
16204
 
+gvc_stream_status_icon_get_property (GObject     *object,
16205
 
+                                     guint        prop_id,
16206
 
+                                     GValue      *value,
16207
 
+                                     GParamSpec  *pspec)
16208
 
+{
16209
 
+        GvcStreamStatusIcon *self = GVC_STREAM_STATUS_ICON (object);
16210
 
+        GvcStreamStatusIconPrivate *priv = self->priv;
16211
 
+
16212
 
+        switch (prop_id) {
16213
 
+        case PROP_MIXER_STREAM:
16214
 
+                g_value_set_object (value, priv->mixer_stream);
16215
 
+                break;
16216
 
+        case PROP_DISPLAY_NAME:
16217
 
+                g_value_set_string (value, priv->display_name);
16218
 
+                break;
16219
 
+        case PROP_ICON_NAMES:
16220
 
+                g_value_set_boxed (value, priv->icon_names);
16221
 
+                break;
16222
 
+        default:
16223
 
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
16224
 
+                break;
16225
 
+        }
16226
 
+}
16227
 
+
16228
 
+static void
16229
 
+on_bar_is_muted_notify (GObject             *object,
16230
 
+                        GParamSpec          *pspec,
16231
 
+                        GvcStreamStatusIcon *icon)
16232
 
+{
16233
 
+        gboolean is_muted;
16234
 
+
16235
 
+        is_muted = gvc_channel_bar_get_is_muted (GVC_CHANNEL_BAR (object));
16236
 
+
16237
 
+        if (gvc_mixer_stream_get_is_muted (icon->priv->mixer_stream) != is_muted) {
16238
 
+                /* Update the stream before pushing the change */
16239
 
+                gvc_mixer_stream_set_is_muted (icon->priv->mixer_stream, is_muted);
16240
 
+                gvc_mixer_stream_change_is_muted (icon->priv->mixer_stream,
16241
 
+                                                  is_muted);
16242
 
+        }
16243
 
+}
16244
 
+
16245
 
+static GObject *
16246
 
+gvc_stream_status_icon_constructor (GType                  type,
16247
 
+                                    guint                  n_construct_properties,
16248
 
+                                    GObjectConstructParam *construct_params)
16249
 
+{
16250
 
+        GObject             *object;
16251
 
+        GvcStreamStatusIcon *icon;
16252
 
+        GtkWidget           *frame;
16253
 
+        GtkWidget           *box;
16254
 
+        GtkAdjustment       *adj;
16255
 
+
16256
 
+        object = G_OBJECT_CLASS (gvc_stream_status_icon_parent_class)->constructor (type, n_construct_properties, construct_params);
16257
 
+
16258
 
+        icon = GVC_STREAM_STATUS_ICON (object);
16259
 
+
16260
 
+        gtk_status_icon_set_from_icon_name (GTK_STATUS_ICON (icon),
16261
 
+                                            icon->priv->icon_names[0]);
16262
 
+
16263
 
+        /* window */
16264
 
+        icon->priv->dock = gtk_window_new (GTK_WINDOW_POPUP);
16265
 
+        gtk_widget_set_name (icon->priv->dock, "gvc-stream-status-icon-popup-window");
16266
 
+        g_signal_connect (icon->priv->dock,
16267
 
+                          "button-press-event",
16268
 
+                          G_CALLBACK (on_dock_button_press),
16269
 
+                          icon);
16270
 
+        g_signal_connect (icon->priv->dock,
16271
 
+                          "key-release-event",
16272
 
+                          G_CALLBACK (on_dock_key_release),
16273
 
+                          icon);
16274
 
+        g_signal_connect (icon->priv->dock,
16275
 
+                          "scroll-event",
16276
 
+                          G_CALLBACK (on_dock_scroll_event),
16277
 
+                          icon);
16278
 
+
16279
 
+        gtk_window_set_decorated (GTK_WINDOW (icon->priv->dock), FALSE);
16280
 
+
16281
 
+        frame = gtk_frame_new (NULL);
16282
 
+        gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
16283
 
+        gtk_container_add (GTK_CONTAINER (icon->priv->dock), frame);
16284
 
+
16285
 
+        box = gtk_vbox_new (FALSE, 6);
16286
 
+        gtk_container_set_border_width (GTK_CONTAINER (box), 2);
16287
 
+        gtk_container_add (GTK_CONTAINER (frame), box);
16288
 
+
16289
 
+        icon->priv->bar = gvc_channel_bar_new ();
16290
 
+        gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (icon->priv->bar),
16291
 
+                                         GTK_ORIENTATION_VERTICAL);
16292
 
+
16293
 
+        gtk_box_pack_start (GTK_BOX (box), icon->priv->bar, TRUE, FALSE, 0);
16294
 
+        g_signal_connect (icon->priv->bar,
16295
 
+                          "notify::is-muted",
16296
 
+                          G_CALLBACK (on_bar_is_muted_notify),
16297
 
+                          icon);
16298
 
+
16299
 
+        adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (icon->priv->bar)));
16300
 
+        g_signal_connect (adj,
16301
 
+                          "value-changed",
16302
 
+                          G_CALLBACK (on_adjustment_value_changed),
16303
 
+                          icon);
16304
 
+
16305
 
+        return object;
16306
 
+}
16307
 
+
16308
 
+static void
16309
 
+gvc_stream_status_icon_dispose (GObject *object)
16310
 
+{
16311
 
+        GvcStreamStatusIcon *icon = GVC_STREAM_STATUS_ICON (object);
16312
 
+
16313
 
+        if (icon->priv->dock != NULL) {
16314
 
+                gtk_widget_destroy (icon->priv->dock);
16315
 
+                icon->priv->dock = NULL;
16316
 
+        }
16317
 
+
16318
 
+        if (icon->priv->mixer_stream != NULL) {
16319
 
+                g_object_unref (icon->priv->mixer_stream);
16320
 
+                icon->priv->mixer_stream = NULL;
16321
 
+        }
16322
 
+
16323
 
+        G_OBJECT_CLASS (gvc_stream_status_icon_parent_class)->dispose (object);
16324
 
+}
16325
 
+
16326
 
+static void
16327
 
+gvc_stream_status_icon_class_init (GvcStreamStatusIconClass *klass)
16328
 
+{
16329
 
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
16330
 
+
16331
 
+        object_class->constructor = gvc_stream_status_icon_constructor;
16332
 
+        object_class->finalize = gvc_stream_status_icon_finalize;
16333
 
+        object_class->dispose = gvc_stream_status_icon_dispose;
16334
 
+        object_class->set_property = gvc_stream_status_icon_set_property;
16335
 
+        object_class->get_property = gvc_stream_status_icon_get_property;
16336
 
+
16337
 
+        g_object_class_install_property (object_class,
16338
 
+                                         PROP_MIXER_STREAM,
16339
 
+                                         g_param_spec_object ("mixer-stream",
16340
 
+                                                              "mixer stream",
16341
 
+                                                              "mixer stream",
16342
 
+                                                              GVC_TYPE_MIXER_STREAM,
16343
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
16344
 
+        g_object_class_install_property (object_class,
16345
 
+                                         PROP_DISPLAY_NAME,
16346
 
+                                         g_param_spec_string ("display-name",
16347
 
+                                                              "Display Name",
16348
 
+                                                              "Name to display for this stream",
16349
 
+                                                              NULL,
16350
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
16351
 
+        g_object_class_install_property (object_class,
16352
 
+                                         PROP_ICON_NAMES,
16353
 
+                                         g_param_spec_boxed ("icon-names",
16354
 
+                                                             "Icon Names",
16355
 
+                                                             "Name of icon to display for this stream",
16356
 
+                                                              G_TYPE_STRV,
16357
 
+                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
16358
 
+
16359
 
+        g_type_class_add_private (klass, sizeof (GvcStreamStatusIconPrivate));
16360
 
+}
16361
 
+
16362
 
+static void
16363
 
+on_status_icon_visible_notify (GvcStreamStatusIcon *icon)
16364
 
+{
16365
 
+        gboolean visible;
16366
 
+
16367
 
+        g_object_get (icon, "visible", &visible, NULL);
16368
 
+        if (! visible) {
16369
 
+                if (icon->priv->dock != NULL) {
16370
 
+                        gtk_widget_hide (icon->priv->dock);
16371
 
+                }
16372
 
+        }
16373
 
+}
16374
 
+
16375
 
+static void
16376
 
+gvc_stream_status_icon_init (GvcStreamStatusIcon *icon)
16377
 
+{
16378
 
+        icon->priv = GVC_STREAM_STATUS_ICON_GET_PRIVATE (icon);
16379
 
+
16380
 
+        g_signal_connect (icon,
16381
 
+                          "activate",
16382
 
+                          G_CALLBACK (on_status_icon_activate),
16383
 
+                          icon);
16384
 
+        g_signal_connect (icon,
16385
 
+                          "popup-menu",
16386
 
+                          G_CALLBACK (on_status_icon_popup_menu),
16387
 
+                          icon);
16388
 
+        g_signal_connect (icon,
16389
 
+                          "scroll-event",
16390
 
+                          G_CALLBACK (on_status_icon_scroll_event),
16391
 
+                          icon);
16392
 
+        g_signal_connect (icon,
16393
 
+                          "notify::visible",
16394
 
+                          G_CALLBACK (on_status_icon_visible_notify),
16395
 
+                          NULL);
16396
 
+
16397
 
+        icon->priv->thaw = FALSE;
16398
 
+}
16399
 
+
16400
 
+static void
16401
 
+gvc_stream_status_icon_finalize (GObject *object)
16402
 
+{
16403
 
+        GvcStreamStatusIcon *stream_status_icon;
16404
 
+
16405
 
+        g_return_if_fail (object != NULL);
16406
 
+        g_return_if_fail (GVC_IS_STREAM_STATUS_ICON (object));
16407
 
+
16408
 
+        stream_status_icon = GVC_STREAM_STATUS_ICON (object);
16409
 
+
16410
 
+        g_return_if_fail (stream_status_icon->priv != NULL);
16411
 
+
16412
 
+        g_strfreev (stream_status_icon->priv->icon_names);
16413
 
+
16414
 
+        G_OBJECT_CLASS (gvc_stream_status_icon_parent_class)->finalize (object);
16415
 
+}
16416
 
+
16417
 
+GvcStreamStatusIcon *
16418
 
+gvc_stream_status_icon_new (GvcMixerStream *stream,
16419
 
+                            const char    **icon_names)
16420
 
+{
16421
 
+        GObject *icon;
16422
 
+        icon = g_object_new (GVC_TYPE_STREAM_STATUS_ICON,
16423
 
+                             "mixer-stream", stream,
16424
 
+                             "icon-names", icon_names,
16425
 
+                             NULL);
16426
 
+        return GVC_STREAM_STATUS_ICON (icon);
16427
 
+}
16428
 
Index: gnome-control-center-3.4.2/panels/sound-nua/gvc-stream-status-icon.h
16429
 
===================================================================
16430
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
16431
 
+++ gnome-control-center-3.4.2/panels/sound-nua/gvc-stream-status-icon.h        2012-08-28 17:08:49.468516900 +0200
16432
 
@@ -0,0 +1,63 @@
16433
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
16434
 
+ *
16435
 
+ * Copyright (C) 2008 Red Hat, Inc.
16436
 
+ *
16437
 
+ * This program is free software; you can redistribute it and/or modify
16438
 
+ * it under the terms of the GNU General Public License as published by
16439
 
+ * the Free Software Foundation; either version 2 of the License, or
16440
 
+ * (at your option) any later version.
16441
 
+ *
16442
 
+ * This program is distributed in the hope that it will be useful,
16443
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16444
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16445
 
+ * GNU General Public License for more details.
16446
 
+ *
16447
 
+ * You should have received a copy of the GNU General Public License
16448
 
+ * along with this program; if not, write to the Free Software
16449
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16450
 
+ *
16451
 
+ */
16452
 
+
16453
 
+#ifndef __GVC_STREAM_STATUS_ICON_H
16454
 
+#define __GVC_STREAM_STATUS_ICON_H
16455
 
+
16456
 
+#include <glib-object.h>
16457
 
+#include "gvc-mixer-stream.h"
16458
 
+
16459
 
+G_BEGIN_DECLS
16460
 
+
16461
 
+#define GVC_TYPE_STREAM_STATUS_ICON         (gvc_stream_status_icon_get_type ())
16462
 
+#define GVC_STREAM_STATUS_ICON(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_STREAM_STATUS_ICON, GvcStreamStatusIcon))
16463
 
+#define GVC_STREAM_STATUS_ICON_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_STREAM_STATUS_ICON, GvcStreamStatusIconClass))
16464
 
+#define GVC_IS_STREAM_STATUS_ICON(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_STREAM_STATUS_ICON))
16465
 
+#define GVC_IS_STREAM_STATUS_ICON_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_STREAM_STATUS_ICON))
16466
 
+#define GVC_STREAM_STATUS_ICON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_STREAM_STATUS_ICON, GvcStreamStatusIconClass))
16467
 
+
16468
 
+typedef struct GvcStreamStatusIconPrivate GvcStreamStatusIconPrivate;
16469
 
+
16470
 
+typedef struct
16471
 
+{
16472
 
+        GtkStatusIcon               parent;
16473
 
+        GvcStreamStatusIconPrivate *priv;
16474
 
+} GvcStreamStatusIcon;
16475
 
+
16476
 
+typedef struct
16477
 
+{
16478
 
+        GtkStatusIconClass          parent_class;
16479
 
+} GvcStreamStatusIconClass;
16480
 
+
16481
 
+GType                 gvc_stream_status_icon_get_type            (void);
16482
 
+
16483
 
+GvcStreamStatusIcon * gvc_stream_status_icon_new                 (GvcMixerStream      *stream,
16484
 
+                                                                  const char         **icon_names);
16485
 
+
16486
 
+void                  gvc_stream_status_icon_set_icon_names      (GvcStreamStatusIcon *icon,
16487
 
+                                                                  const char         **icon_names);
16488
 
+void                  gvc_stream_status_icon_set_display_name    (GvcStreamStatusIcon *icon,
16489
 
+                                                                  const char          *display_name);
16490
 
+void                  gvc_stream_status_icon_set_mixer_stream    (GvcStreamStatusIcon *icon,
16491
 
+                                                                  GvcMixerStream      *stream);
16492
 
+
16493
 
+G_END_DECLS
16494
 
+
16495
 
+#endif /* __GVC_STREAM_STATUS_ICON_H */
16496
 
Index: gnome-control-center-3.4.2/panels/sound-nua/sound-theme-file-utils.c
16497
 
===================================================================
16498
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
16499
 
+++ gnome-control-center-3.4.2/panels/sound-nua/sound-theme-file-utils.c        2012-08-28 17:08:49.468516900 +0200
16500
 
@@ -0,0 +1,305 @@
16501
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
16502
 
+ * Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
16503
 
+ *
16504
 
+ * This program is free software; you can redistribute it and/or modify
16505
 
+ * it under the terms of the GNU General Public License as published by
16506
 
+ * the Free Software Foundation; either version 2, or (at your option)
16507
 
+ * any later version.
16508
 
+ *
16509
 
+ * This program is distributed in the hope that it will be useful,
16510
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16511
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16512
 
+ * GNU General Public License for more details.
16513
 
+ *
16514
 
+ * You should have received a copy of the GNU General Public License
16515
 
+ * along with this program; if not, write to the Free Software
16516
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
16517
 
+ * 02111-1307, USA.
16518
 
+ */
16519
 
+
16520
 
+#include <config.h>
16521
 
+#include <glib/gstdio.h>
16522
 
+#include <glib/gi18n-lib.h>
16523
 
+#include <gio/gio.h>
16524
 
+#include <utime.h>
16525
 
+#include <strings.h>
16526
 
+
16527
 
+#include "sound-theme-file-utils.h"
16528
 
+
16529
 
+#define CUSTOM_THEME_NAME       "__custom"
16530
 
+
16531
 
+/* This function needs to be called after each individual
16532
 
+ * changeset to the theme */
16533
 
+void
16534
 
+custom_theme_update_time (void)
16535
 
+{
16536
 
+        char *path;
16537
 
+
16538
 
+        path = custom_theme_dir_path (NULL);
16539
 
+        utime (path, NULL);
16540
 
+        g_free (path);
16541
 
+}
16542
 
+
16543
 
+char *
16544
 
+custom_theme_dir_path (const char *child)
16545
 
+{
16546
 
+        static char *dir = NULL;
16547
 
+        const char *data_dir;
16548
 
+
16549
 
+        if (dir == NULL) {
16550
 
+                data_dir = g_get_user_data_dir ();
16551
 
+                dir = g_build_filename (data_dir, "sounds", CUSTOM_THEME_NAME, NULL);
16552
 
+        }
16553
 
+        if (child == NULL)
16554
 
+                return g_strdup (dir);
16555
 
+
16556
 
+        return g_build_filename (dir, child, NULL);
16557
 
+}
16558
 
+
16559
 
+static gboolean
16560
 
+directory_delete_recursive (GFile *directory, GError **error)
16561
 
+{
16562
 
+        GFileEnumerator *enumerator;
16563
 
+        GFileInfo *info;
16564
 
+        gboolean success = TRUE;
16565
 
+
16566
 
+        enumerator = g_file_enumerate_children (directory,
16567
 
+                                                G_FILE_ATTRIBUTE_STANDARD_NAME ","
16568
 
+                                                G_FILE_ATTRIBUTE_STANDARD_TYPE,
16569
 
+                                                G_FILE_QUERY_INFO_NONE,
16570
 
+                                                NULL, error);
16571
 
+        if (enumerator == NULL)
16572
 
+                return FALSE;
16573
 
+
16574
 
+        while (success &&
16575
 
+               (info = g_file_enumerator_next_file (enumerator, NULL, NULL))) {
16576
 
+                GFile *child;
16577
 
+
16578
 
+                child = g_file_get_child (directory, g_file_info_get_name (info));
16579
 
+
16580
 
+                if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
16581
 
+                        success = directory_delete_recursive (child, error);
16582
 
+                }
16583
 
+                g_object_unref (info);
16584
 
+
16585
 
+                if (success)
16586
 
+                        success = g_file_delete (child, NULL, error);
16587
 
+        }
16588
 
+        g_file_enumerator_close (enumerator, NULL, NULL);
16589
 
+
16590
 
+        if (success)
16591
 
+                success = g_file_delete (directory, NULL, error);
16592
 
+
16593
 
+        return success;
16594
 
+}
16595
 
+
16596
 
+/**
16597
 
+ * capplet_file_delete_recursive :
16598
 
+ * @file :
16599
 
+ * @error  :
16600
 
+ *
16601
 
+ * A utility routine to delete files and/or directories,
16602
 
+ * including non-empty directories.
16603
 
+ **/
16604
 
+static gboolean
16605
 
+capplet_file_delete_recursive (GFile *file, GError **error)
16606
 
+{
16607
 
+        GFileInfo *info;
16608
 
+        GFileType type;
16609
 
+
16610
 
+        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
16611
 
+
16612
 
+        info = g_file_query_info (file,
16613
 
+                                  G_FILE_ATTRIBUTE_STANDARD_TYPE,
16614
 
+                                  G_FILE_QUERY_INFO_NONE,
16615
 
+                                  NULL, error);
16616
 
+        if (info == NULL)
16617
 
+                return FALSE;
16618
 
+
16619
 
+        type = g_file_info_get_file_type (info);
16620
 
+        g_object_unref (info);
16621
 
+
16622
 
+        if (type == G_FILE_TYPE_DIRECTORY)
16623
 
+                return directory_delete_recursive (file, error);
16624
 
+        else
16625
 
+                return g_file_delete (file, NULL, error);
16626
 
+}
16627
 
+
16628
 
+void
16629
 
+delete_custom_theme_dir (void)
16630
 
+{
16631
 
+        char *dir;
16632
 
+        GFile *file;
16633
 
+
16634
 
+        dir = custom_theme_dir_path (NULL);
16635
 
+        file = g_file_new_for_path (dir);
16636
 
+        g_free (dir);
16637
 
+        capplet_file_delete_recursive (file, NULL);
16638
 
+        g_object_unref (file);
16639
 
+
16640
 
+        g_debug ("deleted the custom theme dir");
16641
 
+}
16642
 
+
16643
 
+gboolean
16644
 
+custom_theme_dir_is_empty (void)
16645
 
+{
16646
 
+        char            *dir;
16647
 
+        GFile           *file;
16648
 
+        gboolean         is_empty;
16649
 
+        GFileEnumerator *enumerator;
16650
 
+        GFileInfo       *info;
16651
 
+        GError          *error = NULL;
16652
 
+
16653
 
+        dir = custom_theme_dir_path (NULL);
16654
 
+        file = g_file_new_for_path (dir);
16655
 
+        g_free (dir);
16656
 
+
16657
 
+        is_empty = TRUE;
16658
 
+
16659
 
+        enumerator = g_file_enumerate_children (file,
16660
 
+                                                G_FILE_ATTRIBUTE_STANDARD_NAME ","
16661
 
+                                                G_FILE_ATTRIBUTE_STANDARD_TYPE,
16662
 
+                                                G_FILE_QUERY_INFO_NONE,
16663
 
+                                                NULL, &error);
16664
 
+        if (enumerator == NULL) {
16665
 
+                g_warning ("Unable to enumerate files: %s", error->message);
16666
 
+                g_error_free (error);
16667
 
+                goto out;
16668
 
+        }
16669
 
+
16670
 
+        while (is_empty &&
16671
 
+               (info = g_file_enumerator_next_file (enumerator, NULL, NULL))) {
16672
 
+
16673
 
+                if (strcmp ("index.theme", g_file_info_get_name (info)) != 0) {
16674
 
+                        is_empty = FALSE;
16675
 
+                }
16676
 
+
16677
 
+                g_object_unref (info);
16678
 
+        }
16679
 
+        g_file_enumerator_close (enumerator, NULL, NULL);
16680
 
+
16681
 
+ out:
16682
 
+        g_object_unref (file);
16683
 
+
16684
 
+        return is_empty;
16685
 
+}
16686
 
+
16687
 
+static void
16688
 
+delete_one_file (const char *sound_name, const char *pattern)
16689
 
+{
16690
 
+        GFile *file;
16691
 
+        char *name, *filename;
16692
 
+
16693
 
+        name = g_strdup_printf (pattern, sound_name);
16694
 
+        filename = custom_theme_dir_path (name);
16695
 
+        g_free (name);
16696
 
+        file = g_file_new_for_path (filename);
16697
 
+        g_free (filename);
16698
 
+        capplet_file_delete_recursive (file, NULL);
16699
 
+        g_object_unref (file);
16700
 
+}
16701
 
+
16702
 
+void
16703
 
+delete_old_files (const char **sounds)
16704
 
+{
16705
 
+        guint i;
16706
 
+
16707
 
+        for (i = 0; sounds[i] != NULL; i++) {
16708
 
+                delete_one_file (sounds[i], "%s.ogg");
16709
 
+        }
16710
 
+}
16711
 
+
16712
 
+void
16713
 
+delete_disabled_files (const char **sounds)
16714
 
+{
16715
 
+        guint i;
16716
 
+
16717
 
+        for (i = 0; sounds[i] != NULL; i++)
16718
 
+                delete_one_file (sounds[i], "%s.disabled");
16719
 
+}
16720
 
+
16721
 
+static void
16722
 
+create_one_file (GFile *file)
16723
 
+{
16724
 
+        GFileOutputStream* stream;
16725
 
+
16726
 
+        stream = g_file_create (file, G_FILE_CREATE_NONE, NULL, NULL);
16727
 
+        if (stream != NULL) {
16728
 
+                g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, NULL);
16729
 
+                g_object_unref (stream);
16730
 
+        }
16731
 
+}
16732
 
+
16733
 
+void
16734
 
+add_disabled_file (const char **sounds)
16735
 
+{
16736
 
+        guint i;
16737
 
+
16738
 
+        for (i = 0; sounds[i] != NULL; i++) {
16739
 
+                GFile *file;
16740
 
+                char *name, *filename;
16741
 
+
16742
 
+                name = g_strdup_printf ("%s.disabled", sounds[i]);
16743
 
+                filename = custom_theme_dir_path (name);
16744
 
+                g_free (name);
16745
 
+                file = g_file_new_for_path (filename);
16746
 
+                g_free (filename);
16747
 
+
16748
 
+                create_one_file (file);
16749
 
+                g_object_unref (file);
16750
 
+        }
16751
 
+}
16752
 
+
16753
 
+void
16754
 
+add_custom_file (const char **sounds, const char *filename)
16755
 
+{
16756
 
+        guint i;
16757
 
+
16758
 
+        for (i = 0; sounds[i] != NULL; i++) {
16759
 
+                GFile *file;
16760
 
+                char *name, *path;
16761
 
+
16762
 
+                /* We use *.ogg because it's the first type of file that
16763
 
+                 * libcanberra looks at */
16764
 
+                name = g_strdup_printf ("%s.ogg", sounds[i]);
16765
 
+                path = custom_theme_dir_path (name);
16766
 
+                g_free (name);
16767
 
+                /* In case there's already a link there, delete it */
16768
 
+                g_unlink (path);
16769
 
+                file = g_file_new_for_path (path);
16770
 
+                g_free (path);
16771
 
+
16772
 
+                /* Create the link */
16773
 
+                g_file_make_symbolic_link (file, filename, NULL, NULL);
16774
 
+                g_object_unref (file);
16775
 
+        }
16776
 
+}
16777
 
+
16778
 
+void
16779
 
+create_custom_theme (const char *parent)
16780
 
+{
16781
 
+        GKeyFile *keyfile;
16782
 
+        char     *data;
16783
 
+        char     *path;
16784
 
+
16785
 
+        /* Create the custom directory */
16786
 
+        path = custom_theme_dir_path (NULL);
16787
 
+        g_mkdir_with_parents (path, 0755);
16788
 
+        g_free (path);
16789
 
+
16790
 
+        /* Set the data for index.theme */
16791
 
+        keyfile = g_key_file_new ();
16792
 
+        g_key_file_set_string (keyfile, "Sound Theme", "Name", _("Custom"));
16793
 
+        g_key_file_set_string (keyfile, "Sound Theme", "Inherits", parent);
16794
 
+        g_key_file_set_string (keyfile, "Sound Theme", "Directories", ".");
16795
 
+        data = g_key_file_to_data (keyfile, NULL, NULL);
16796
 
+        g_key_file_free (keyfile);
16797
 
+
16798
 
+        /* Save the index.theme */
16799
 
+        path = custom_theme_dir_path ("index.theme");
16800
 
+        g_file_set_contents (path, data, -1, NULL);
16801
 
+        g_free (path);
16802
 
+        g_free (data);
16803
 
+
16804
 
+        custom_theme_update_time ();
16805
 
+}
16806
 
Index: gnome-control-center-3.4.2/panels/sound-nua/sound-theme-file-utils.h
16807
 
===================================================================
16808
 
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
16809
 
+++ gnome-control-center-3.4.2/panels/sound-nua/sound-theme-file-utils.h        2012-08-28 17:08:49.468516900 +0200
16810
 
@@ -0,0 +1,37 @@
16811
 
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
16812
 
+ * Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
16813
 
+ *
16814
 
+ * This program is free software; you can redistribute it and/or modify
16815
 
+ * it under the terms of the GNU General Public License as published by
16816
 
+ * the Free Software Foundation; either version 2, or (at your option)
16817
 
+ * any later version.
16818
 
+ *
16819
 
+ * This program is distributed in the hope that it will be useful,
16820
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16821
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16822
 
+ * GNU General Public License for more details.
16823
 
+ *
16824
 
+ * You should have received a copy of the GNU General Public License
16825
 
+ * along with this program; if not, write to the Free Software
16826
 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
16827
 
+ * 02111-1307, USA.
16828
 
+ */
16829
 
+#ifndef __SOUND_THEME_FILE_UTILS_HH__
16830
 
+#define __SOUND_THEME_FILE_UTILS_HH__
16831
 
+
16832
 
+#include <gio/gio.h>
16833
 
+
16834
 
+char *custom_theme_dir_path (const char *child);
16835
 
+gboolean custom_theme_dir_is_empty (void);
16836
 
+void create_custom_theme (const char *parent);
16837
 
+
16838
 
+void delete_custom_theme_dir (void);
16839
 
+void delete_old_files (const char **sounds);
16840
 
+void delete_disabled_files (const char **sounds);
16841
 
+
16842
 
+void add_disabled_file (const char **sounds);
16843
 
+void add_custom_file (const char **sounds, const char *filename);
16844
 
+
16845
 
+void custom_theme_update_time (void);
16846
 
+
16847
 
+#endif /* __SOUND_THEME_FILE_UTILS_HH__ */
16848
 
Index: gnome-control-center-3.4.2/panels/sound/data/gnome-sound-panel.desktop.in.in
16849
 
===================================================================
16850
 
--- gnome-control-center-3.4.2.orig/panels/sound/data/gnome-sound-panel.desktop.in.in   2012-03-05 15:04:55.000000000 +0100
16851
 
+++ gnome-control-center-3.4.2/panels/sound/data/gnome-sound-panel.desktop.in.in        2012-08-28 17:08:49.468516900 +0200
16852
 
@@ -7,7 +7,7 @@
16853
 
 Type=Application
16854
 
 StartupNotify=true
16855
 
 Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel;
16856
 
-OnlyShowIn=GNOME;Unity;
16857
 
+OnlyShowIn=GNOME;
16858
 
 X-GNOME-Bugzilla-Bugzilla=GNOME
16859
 
 X-GNOME-Bugzilla-Product=gnome-control-center
16860
 
 X-GNOME-Bugzilla-Component=sound
16861
 
Index: gnome-control-center-3.4.2/panels/universal-access/cc-ua-panel.c
16862
 
===================================================================
16863
 
--- gnome-control-center-3.4.2.orig/panels/universal-access/cc-ua-panel.c       2012-08-28 17:08:49.364516895 +0200
16864
 
+++ gnome-control-center-3.4.2/panels/universal-access/cc-ua-panel.c    2012-08-28 17:08:49.468516900 +0200
16865
 
@@ -589,7 +589,10 @@
16866
 
   CcShell *shell;
16867
 
 
16868
 
   shell = cc_panel_get_shell (CC_PANEL (panel));
16869
 
-  cc_shell_set_active_panel_from_id (shell, "sound", NULL, NULL);
16870
 
+  if (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity") == 0)
16871
 
+    cc_shell_set_active_panel_from_id (shell, "sound-nua", NULL, NULL);
16872
 
+  else
16873
 
+    cc_shell_set_active_panel_from_id (shell, "sound", NULL, NULL);
16874
 
 
16875
 
   return TRUE;
16876
 
 }
16877
 
Index: gnome-control-center-3.4.2/shell/gnome-control-center.c
16878
 
===================================================================
16879
 
--- gnome-control-center-3.4.2.orig/shell/gnome-control-center.c        2012-08-28 17:08:49.324516894 +0200
16880
 
+++ gnome-control-center-3.4.2/shell/gnome-control-center.c     2012-08-28 17:08:53.316517087 +0200
16881
 
@@ -887,6 +887,10 @@
16882
 
   GIcon *gicon;
16883
 
   GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (shell)->priv;
16884
 
 
16885
 
+  if (!g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity") && 
16886
 
+      !g_strcmp0(start_id, "sound"))
16887
 
+      start_id = "sound-nua";
16888
 
+
16889
 
   /* clear any custom widgets */
16890
 
   _shell_remove_all_custom_widgets (priv);
16891