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
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
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
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
39
+# This is used in PANEL_CFLAGS
43
+ccpanelsdir = $(PANELS_DIR)
44
+ccpanels_LTLIBRARIES = libsoundnua.la
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\"" \
57
+noinst_LTLIBRARIES = libgnomevolumecontrol.la
58
+libgnomevolumecontrol_la_SOURCES = \
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 \
69
+ gvc-channel-map-private.h \
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 \
85
+ gvc-pulseaudio-fake.h \
88
+libsoundnua_la_LIBADD = \
90
+ libgnomevolumecontrol.la \
92
+ $(SOUND_PANEL_LIBS) \
95
+libsoundnua_la_LDFLAGS = \
99
+libsoundnua_la_SOURCES = \
100
+ gvc-balance-bar.h \
101
+ gvc-balance-bar.c \
102
+ gvc-mixer-dialog.h \
103
+ gvc-mixer-dialog.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 \
125
+MAINTAINERCLEANFILES = \
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
135
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
137
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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
157
+#include <libintl.h>
163
+#include <glib/gi18n.h>
165
+#include <gtk/gtk.h>
166
+#include <gio/gio.h>
168
+#include "gvc-applet.h"
169
+#include "gvc-log.h"
171
+#define GVCA_DBUS_NAME "org.gnome.VolumeControlApplet"
173
+static gboolean show_version = FALSE;
174
+static gboolean debug = FALSE;
177
+main (int argc, char **argv)
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 }
188
+ bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
189
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
190
+ textdomain (GETTEXT_PACKAGE);
195
+ gtk_init_with_args (&argc, &argv,
196
+ (char *) _(" — GNOME Volume Control Applet"),
197
+ entries, GETTEXT_PACKAGE,
200
+ if (error != NULL) {
201
+ g_warning ("%s", error->message);
205
+ if (show_version) {
206
+ g_print ("%s %s\n", argv [0], VERSION);
210
+ gvc_log_set_debug (debug);
212
+ if (debug == FALSE) {
213
+ GError *error = NULL;
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);
222
+ if (g_application_get_is_remote (app)) {
223
+ g_warning ("Applet is already running, exiting");
228
+ gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
231
+ applet = gvc_applet_new ();
232
+ gvc_applet_start (applet);
236
+ if (applet != NULL) {
237
+ g_object_unref (applet);
240
+ g_object_unref (app);
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
250
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
252
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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
272
+#include <libintl.h>
278
+#include <glib/gi18n-lib.h>
280
+#include <gtk/gtk.h>
281
+#include <pulse/pulseaudio.h>
283
+#include "cc-sound-panel.h"
284
+#include "gvc-mixer-dialog.h"
286
+G_DEFINE_DYNAMIC_TYPE (CcSoundNuaPanel, cc_sound_panel, CC_TYPE_PANEL)
293
+static void cc_sound_panel_finalize (GObject *object);
296
+cc_sound_panel_set_property (GObject *object,
298
+ const GValue *value,
301
+ CcSoundNuaPanel *self = CC_SOUND_PANEL (object);
303
+ switch (property_id) {
307
+ args = g_value_get_boxed (value);
309
+ if (args && args[0]) {
310
+ gvc_mixer_dialog_set_page (self->dialog, args[0]);
315
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
320
+cc_sound_panel_class_init (CcSoundNuaPanelClass *klass)
322
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
324
+ object_class->finalize = cc_sound_panel_finalize;
325
+ object_class->set_property = cc_sound_panel_set_property;
327
+ g_object_class_override_property (object_class, PROP_ARGV, "argv");
331
+cc_sound_panel_class_finalize (CcSoundNuaPanelClass *klass)
336
+cc_sound_panel_finalize (GObject *object)
338
+ CcSoundNuaPanel *panel = CC_SOUND_PANEL (object);
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;
349
+ G_OBJECT_CLASS (cc_sound_panel_parent_class)->finalize (object);
353
+cc_sound_panel_init (CcSoundNuaPanel *self)
355
+ gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
357
+ gtk_window_set_default_icon_name ("multimedia-volume-control");
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));
367
+cc_sound_panel_register (GIOModule *module)
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,
375
+/* GIO extension stuff */
377
+g_io_module_load (GIOModule *module)
379
+ bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
380
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
382
+ /* register the panel */
383
+ cc_sound_panel_register (module);
387
+g_io_module_unload (GIOModule *module)
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
396
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
398
+ * Copyright (C) 2010 Red Hat, Inc.
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.
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.
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
416
+#ifndef _CC_SOUND_PANEL_H
417
+#define _CC_SOUND_PANEL_H
419
+#include <shell/cc-panel.h>
420
+#include "gvc-mixer-control.h"
421
+#include "gvc-mixer-dialog.h"
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))
432
+typedef struct _CcSoundNuaPanel CcSoundNuaPanel;
433
+typedef struct _CcSoundNuaPanelClass CcSoundNuaPanelClass;
434
+typedef struct _CcSoundNuaPanelPrivate CcSoundNuaPanelPrivate;
436
+struct _CcSoundNuaPanel {
439
+ GvcMixerControl *control;
440
+ GvcMixerDialog *dialog;
441
+ GtkWidget *connecting_label;
444
+struct _CcSoundNuaPanelClass {
445
+ CcPanelClass parent_class;
448
+GType cc_sound_panel_get_type (void) G_GNUC_CONST;
450
+void cc_sound_panel_register (GIOModule *module);
454
+#endif /* _CC_SOUND_PANEL_H */
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
463
+@INTLTOOL_DESKTOP_RULE@
465
+appsdir = $(datadir)/applications
466
+apps_in_files = gnome-sound-nua-panel.desktop.in
467
+apps_DATA = $(apps_in_files:.desktop.in=.desktop)
470
+ gnome-sound-nua-panel.desktop.in.in \
474
+ gnome-sound-nua-panel.desktop \
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
485
+_Comment=Change sound volume and sound events
486
+Exec=gnome-control-center sound-nua
487
+Icon=multimedia-volume-control
491
+Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel;
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
505
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
507
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
535
+#include <glib/gi18n.h>
536
+#include <gtk/gtk.h>
537
+#include <pulse/pulseaudio.h>
539
+#include "gvc-applet.h"
540
+#include "gvc-mixer-control.h"
541
+#include "gvc-stream-status-icon.h"
543
+#define GVC_APPLET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_APPLET, GvcAppletPrivate))
545
+#define SCALE_SIZE 128
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",
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",
563
+struct GvcAppletPrivate
565
+ GvcStreamStatusIcon *input_status_icon;
566
+ GvcStreamStatusIcon *output_status_icon;
567
+ GvcMixerControl *control;
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);
574
+G_DEFINE_TYPE (GvcApplet, gvc_applet, G_TYPE_OBJECT)
577
+maybe_show_status_icons (GvcApplet *applet)
580
+ GvcMixerStream *stream;
581
+ GSList *source_outputs, *l;
584
+ stream = gvc_mixer_control_get_default_sink (applet->priv->control);
585
+ if (stream == NULL) {
588
+ gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->output_status_icon), show);
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;
601
+ id = gvc_mixer_stream_get_application_id (s);
607
+ if (!g_str_equal (id, "org.gnome.VolumeControl") &&
608
+ !g_str_equal (id, "org.PulseAudio.pavucontrol")) {
614
+ gtk_status_icon_set_visible (GTK_STATUS_ICON (applet->priv->input_status_icon), show);
616
+ g_slist_free (source_outputs);
620
+gvc_applet_start (GvcApplet *applet)
622
+ g_return_if_fail (GVC_IS_APPLET (applet));
624
+ maybe_show_status_icons (applet);
628
+gvc_applet_dispose (GObject *object)
630
+ GvcApplet *applet = GVC_APPLET (object);
632
+ if (applet->priv->control != NULL) {
633
+ g_object_unref (applet->priv->control);
634
+ applet->priv->control = NULL;
637
+ G_OBJECT_CLASS (gvc_applet_parent_class)->dispose (object);
641
+update_default_source (GvcApplet *applet)
643
+ GvcMixerStream *stream;
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,
649
+ maybe_show_status_icons(applet);
651
+ g_debug ("Unable to get default source, or no source available");
656
+update_default_sink (GvcApplet *applet)
658
+ GvcMixerStream *stream;
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,
664
+ maybe_show_status_icons(applet);
666
+ g_warning ("Unable to get default sink");
671
+on_control_state_changed (GvcMixerControl *control,
672
+ GvcMixerControlState new_state,
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...");
684
+on_control_default_sink_changed (GvcMixerControl *control,
688
+ update_default_sink (applet);
692
+on_control_default_source_changed (GvcMixerControl *control,
696
+ update_default_source (applet);
700
+on_control_stream_removed (GvcMixerControl *control,
704
+ maybe_show_status_icons (applet);
708
+on_control_stream_added (GvcMixerControl *control,
712
+ maybe_show_status_icons (applet);
716
+gvc_applet_constructor (GType type,
717
+ guint n_construct_properties,
718
+ GObjectConstructParam *construct_params)
723
+ object = G_OBJECT_CLASS (gvc_applet_parent_class)->constructor (type, n_construct_properties, construct_params);
725
+ self = GVC_APPLET (object);
727
+ self->priv->control = gvc_mixer_control_new ("GNOME Volume Control Applet");
728
+ g_signal_connect (self->priv->control,
730
+ G_CALLBACK (on_control_state_changed),
732
+ g_signal_connect (self->priv->control,
733
+ "default-sink-changed",
734
+ G_CALLBACK (on_control_default_sink_changed),
736
+ g_signal_connect (self->priv->control,
737
+ "default-source-changed",
738
+ G_CALLBACK (on_control_default_source_changed),
740
+ g_signal_connect (self->priv->control,
742
+ G_CALLBACK (on_control_stream_added),
744
+ g_signal_connect (self->priv->control,
746
+ G_CALLBACK (on_control_stream_removed),
749
+ gvc_mixer_control_open (self->priv->control);
755
+gvc_applet_class_init (GvcAppletClass *klass)
757
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
759
+ object_class->finalize = gvc_applet_finalize;
760
+ object_class->dispose = gvc_applet_dispose;
761
+ object_class->constructor = gvc_applet_constructor;
763
+ g_type_class_add_private (klass, sizeof (GvcAppletPrivate));
767
+gvc_applet_init (GvcApplet *applet)
769
+ applet->priv = GVC_APPLET_GET_PRIVATE (applet);
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,
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,
779
+ gvc_stream_status_icon_set_display_name (applet->priv->input_status_icon,
781
+ gtk_status_icon_set_title (GTK_STATUS_ICON (applet->priv->input_status_icon),
782
+ _("Microphone Volume"));
786
+gvc_applet_finalize (GObject *object)
790
+ g_return_if_fail (object != NULL);
791
+ g_return_if_fail (GVC_IS_APPLET (object));
793
+ applet = GVC_APPLET (object);
795
+ g_return_if_fail (applet->priv != NULL);
798
+ G_OBJECT_CLASS (gvc_applet_parent_class)->finalize (object);
802
+gvc_applet_new (void)
806
+ applet = g_object_new (GVC_TYPE_APPLET, NULL);
808
+ return GVC_APPLET (applet);
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
815
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
817
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
835
+#ifndef __GVC_APPLET_H
836
+#define __GVC_APPLET_H
838
+#include <glib-object.h>
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))
849
+typedef struct GvcAppletPrivate GvcAppletPrivate;
854
+ GvcAppletPrivate *priv;
859
+ GObjectClass parent_class;
862
+GType gvc_applet_get_type (void);
864
+GvcApplet * gvc_applet_new (void);
865
+void gvc_applet_start (GvcApplet *applet);
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
875
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
877
+ * Copyright (C) 2008 William Jon McCann
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.
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.
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.
902
+#include <glib/gi18n-lib.h>
903
+#include <gtk/gtk.h>
904
+#include <canberra-gtk.h>
905
+#include <pulse/pulseaudio.h>
907
+#include "gvc-balance-bar.h"
908
+#include "gvc-channel-map-private.h"
910
+#define SCALE_SIZE 220
911
+#define ADJUSTMENT_MAX_NORMAL 65536.0 /* PA_VOLUME_NORM */
913
+#define GVC_BALANCE_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_BALANCE_BAR, GvcBalanceBarPrivate))
915
+struct GvcBalanceBarPrivate
917
+ GvcChannelMap *channel_map;
918
+ GvcBalanceType btype;
919
+ GtkWidget *scale_box;
920
+ GtkWidget *start_box;
921
+ GtkWidget *end_box;
924
+ GtkAdjustment *adjustment;
925
+ GtkSizeGroup *size_group;
926
+ gboolean symmetric;
927
+ gboolean click_lock;
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);
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);
953
+G_DEFINE_TYPE (GvcBalanceBar, gvc_balance_bar, GTK_TYPE_HBOX)
956
+_scale_box_new (GvcBalanceBar *bar)
958
+ GvcBalanceBarPrivate *priv = bar->priv;
962
+ GtkAdjustment *adjustment = bar->priv->adjustment;
963
+ char *str_lower, *str_upper;
964
+ gdouble lower, upper;
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"
974
+ "widget \"*.balance-bar-scale\" style : rc \"balance-bar-scale-style\"\n");
976
+ bar->priv->start_box = sbox = gtk_box_new (FALSE, 6);
977
+ gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0);
979
+ gtk_box_pack_start (GTK_BOX (sbox), priv->label, FALSE, FALSE, 0);
981
+ gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, TRUE, 0);
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"));
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"));
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"));
997
+ g_assert_not_reached ();
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);
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);
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);
1018
+ ca_gtk_widget_disable_sounds (bar->priv->scale, FALSE);
1019
+ gtk_widget_add_events (bar->priv->scale, GDK_SCROLL_MASK);
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);
1028
+ if (bar->priv->size_group != NULL) {
1029
+ gtk_size_group_add_widget (bar->priv->size_group, sbox);
1031
+ if (bar->priv->symmetric) {
1032
+ gtk_size_group_add_widget (bar->priv->size_group, ebox);
1036
+ gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE);
1042
+gvc_balance_bar_set_size_group (GvcBalanceBar *bar,
1043
+ GtkSizeGroup *group,
1044
+ gboolean symmetric)
1046
+ g_return_if_fail (GVC_IS_BALANCE_BAR (bar));
1048
+ bar->priv->size_group = group;
1049
+ bar->priv->symmetric = symmetric;
1051
+ if (bar->priv->size_group != NULL) {
1052
+ gtk_size_group_add_widget (bar->priv->size_group,
1053
+ bar->priv->start_box);
1055
+ if (bar->priv->symmetric) {
1056
+ gtk_size_group_add_widget (bar->priv->size_group,
1057
+ bar->priv->end_box);
1060
+ gtk_widget_queue_draw (GTK_WIDGET (bar));
1063
+static const char *
1064
+btype_to_string (guint btype)
1067
+ case BALANCE_TYPE_RL:
1069
+ case BALANCE_TYPE_FR:
1072
+ case BALANCE_TYPE_LFE:
1075
+ g_assert_not_reached ();
1081
+update_level_from_map (GvcBalanceBar *bar,
1082
+ GvcChannelMap *map)
1084
+ const gdouble *volumes;
1087
+ g_debug ("Volume changed (for %s bar)", btype_to_string (bar->priv->btype));
1089
+ volumes = gvc_channel_map_get_volume (map);
1090
+ switch (bar->priv->btype) {
1091
+ case BALANCE_TYPE_RL:
1092
+ val = volumes[BALANCE];
1094
+ case BALANCE_TYPE_FR:
1095
+ val = volumes[FADE];
1097
+ case BALANCE_TYPE_LFE:
1098
+ val = volumes[LFE];
1101
+ g_assert_not_reached ();
1104
+ gtk_adjustment_set_value (bar->priv->adjustment, val);
1108
+on_channel_map_volume_changed (GvcChannelMap *map,
1110
+ GvcBalanceBar *bar)
1112
+ update_level_from_map (bar, map);
1116
+gvc_balance_bar_set_channel_map (GvcBalanceBar *bar,
1117
+ GvcChannelMap *map)
1119
+ g_return_if_fail (GVC_BALANCE_BAR (bar));
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);
1126
+ bar->priv->channel_map = g_object_ref (map);
1128
+ update_level_from_map (bar, map);
1130
+ g_signal_connect (G_OBJECT (map), "volume-changed",
1131
+ G_CALLBACK (on_channel_map_volume_changed), bar);
1133
+ g_object_notify (G_OBJECT (bar), "channel-map");
1137
+gvc_balance_bar_set_balance_type (GvcBalanceBar *bar,
1138
+ GvcBalanceType btype)
1142
+ g_return_if_fail (GVC_BALANCE_BAR (bar));
1144
+ bar->priv->btype = btype;
1145
+ if (bar->priv->btype != BALANCE_TYPE_LFE) {
1146
+ bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
1153
+ bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
1155
+ ADJUSTMENT_MAX_NORMAL,
1156
+ ADJUSTMENT_MAX_NORMAL/100.0,
1157
+ ADJUSTMENT_MAX_NORMAL/10.0,
1161
+ g_object_ref_sink (bar->priv->adjustment);
1162
+ g_signal_connect (bar->priv->adjustment,
1164
+ G_CALLBACK (on_adjustment_value_changed),
1168
+ case BALANCE_TYPE_RL:
1169
+ bar->priv->label = gtk_label_new_with_mnemonic (_("_Balance:"));
1171
+ case BALANCE_TYPE_FR:
1172
+ bar->priv->label = gtk_label_new_with_mnemonic (_("_Fade:"));
1174
+ case BALANCE_TYPE_LFE:
1175
+ bar->priv->label = gtk_label_new_with_mnemonic (_("_Subwoofer:"));
1178
+ g_assert_not_reached ();
1180
+ gtk_misc_set_alignment (GTK_MISC (bar->priv->label),
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);
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);
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);
1197
+ g_object_notify (G_OBJECT (bar), "balance-type");
1201
+gvc_balance_bar_set_property (GObject *object,
1203
+ const GValue *value,
1204
+ GParamSpec *pspec)
1206
+ GvcBalanceBar *self = GVC_BALANCE_BAR (object);
1208
+ switch (prop_id) {
1209
+ case PROP_CHANNEL_MAP:
1210
+ gvc_balance_bar_set_channel_map (self, g_value_get_object (value));
1212
+ case PROP_BALANCE_TYPE:
1213
+ gvc_balance_bar_set_balance_type (self, g_value_get_int (value));
1216
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1222
+gvc_balance_bar_get_property (GObject *object,
1225
+ GParamSpec *pspec)
1227
+ GvcBalanceBar *self = GVC_BALANCE_BAR (object);
1229
+ switch (prop_id) {
1230
+ case PROP_CHANNEL_MAP:
1231
+ g_value_set_object (value, self->priv->channel_map);
1234
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1240
+gvc_balance_bar_constructor (GType type,
1241
+ guint n_construct_properties,
1242
+ GObjectConstructParam *construct_params)
1244
+ return G_OBJECT_CLASS (gvc_balance_bar_parent_class)->constructor (type, n_construct_properties, construct_params);
1248
+gvc_balance_bar_class_init (GvcBalanceBarClass *klass)
1250
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
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;
1257
+ g_object_class_install_property (object_class,
1259
+ g_param_spec_object ("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",
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));
1272
+ g_type_class_add_private (klass, sizeof (GvcBalanceBarPrivate));
1277
+on_scale_button_press_event (GtkWidget *widget,
1278
+ GdkEventButton *event,
1279
+ GvcBalanceBar *bar)
1281
+ bar->priv->click_lock = TRUE;
1287
+on_scale_button_release_event (GtkWidget *widget,
1288
+ GdkEventButton *event,
1289
+ GvcBalanceBar *bar)
1291
+ bar->priv->click_lock = FALSE;
1297
+on_scale_scroll_event (GtkWidget *widget,
1298
+ GdkEventScroll *event,
1299
+ GvcBalanceBar *bar)
1304
+ value = gtk_adjustment_get_value (bar->priv->adjustment);
1306
+ if (!gdk_event_get_scroll_deltas ((GdkEvent*)event, &dx, &dy)) {
1310
+ switch (event->direction) {
1311
+ case GDK_SCROLL_UP:
1312
+ case GDK_SCROLL_RIGHT:
1315
+ case GDK_SCROLL_DOWN:
1316
+ case GDK_SCROLL_LEFT:
1324
+ if (bar->priv->btype == BALANCE_TYPE_LFE) {
1326
+ if (value + dy * ADJUSTMENT_MAX_NORMAL/100.0 > ADJUSTMENT_MAX_NORMAL)
1327
+ value = ADJUSTMENT_MAX_NORMAL;
1329
+ value = value + dy * ADJUSTMENT_MAX_NORMAL/100.0;
1330
+ } else if (dy < 0) {
1331
+ if (value + dy * ADJUSTMENT_MAX_NORMAL/100.0 < 0)
1334
+ value = value + dy * ADJUSTMENT_MAX_NORMAL/100.0;
1338
+ if (value + dy * 0.01 > 1.0)
1341
+ value = value + dy * 0.01;
1342
+ } else if (dy < 0) {
1343
+ if (value + dy * 0.01 < -1.0)
1346
+ value = value + dy * 0.01;
1349
+ gtk_adjustment_set_value (bar->priv->adjustment, value);
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) {
1358
+ gboolean good = FALSE;
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);
1366
+ for (c = 0; c < map->channels; c++)
1367
+ if (map->map[c] == t) {
1368
+ cv->values[c] = v;
1372
+ return good ? cv : NULL;
1376
+on_adjustment_value_changed (GtkAdjustment *adjustment,
1377
+ GvcBalanceBar *bar)
1381
+ const pa_channel_map *pa_map;
1383
+ if (bar->priv->channel_map == NULL)
1386
+ cv = *gvc_channel_map_get_cvolume (bar->priv->channel_map);
1387
+ val = gtk_adjustment_get_value (adjustment);
1389
+ pa_map = gvc_channel_map_get_pa_channel_map (bar->priv->channel_map);
1391
+ switch (bar->priv->btype) {
1392
+ case BALANCE_TYPE_RL:
1393
+ pa_cvolume_set_balance (&cv, pa_map, val);
1395
+ case BALANCE_TYPE_FR:
1396
+ pa_cvolume_set_fade (&cv, pa_map, val);
1398
+ case BALANCE_TYPE_LFE:
1399
+ gvc_pa_cvolume_set_position (&cv, pa_map, PA_CHANNEL_POSITION_LFE, val);
1403
+ gvc_channel_map_volume_changed (bar->priv->channel_map, &cv, TRUE);
1407
+gvc_balance_bar_init (GvcBalanceBar *bar)
1409
+ bar->priv = GVC_BALANCE_BAR_GET_PRIVATE (bar);
1413
+gvc_balance_bar_finalize (GObject *object)
1415
+ GvcBalanceBar *bar;
1417
+ g_return_if_fail (object != NULL);
1418
+ g_return_if_fail (GVC_IS_BALANCE_BAR (object));
1420
+ bar = GVC_BALANCE_BAR (object);
1422
+ g_return_if_fail (bar->priv != NULL);
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);
1430
+ G_OBJECT_CLASS (gvc_balance_bar_parent_class)->finalize (object);
1434
+gvc_balance_bar_set_map (GvcBalanceBar* self,
1435
+ const GvcChannelMap *channel_map)
1437
+ g_object_set (G_OBJECT (self),
1438
+ "channel-map", channel_map, NULL);
1442
+gvc_balance_bar_new (GvcBalanceType btype)
1445
+ bar = g_object_new (GVC_TYPE_BALANCE_BAR,
1446
+ "balance-type", btype, NULL);
1448
+ return GTK_WIDGET (bar);
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
1455
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
1457
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
1475
+#ifndef __GVC_BALANCE_BAR_H
1476
+#define __GVC_BALANCE_BAR_H
1478
+#include <glib-object.h>
1480
+#include "gvc-channel-map.h"
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))
1497
+#define NUM_BALANCE_TYPES BALANCE_TYPE_LFE + 1
1499
+typedef struct GvcBalanceBarPrivate GvcBalanceBarPrivate;
1504
+ GvcBalanceBarPrivate *priv;
1509
+ GtkHBoxClass parent_class;
1510
+} GvcBalanceBarClass;
1512
+GType gvc_balance_bar_get_type (void);
1513
+GtkWidget * gvc_balance_bar_new (GvcBalanceType btype);
1515
+void gvc_balance_bar_set_size_group (GvcBalanceBar *bar,
1516
+ GtkSizeGroup *group,
1517
+ gboolean symmetric);
1519
+void gvc_balance_bar_set_map (GvcBalanceBar *self,
1520
+ const GvcChannelMap *channel_map);
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
1530
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
1532
+ * Copyright (C) 2008 William Jon McCann
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.
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.
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.
1550
+#include "config.h"
1552
+#include <stdlib.h>
1554
+#include <unistd.h>
1556
+#include <pulse/pulseaudio.h>
1559
+#include <glib/gi18n-lib.h>
1560
+#include <gtk/gtk.h>
1561
+#include <canberra-gtk.h>
1563
+#include "gvc-channel-bar.h"
1564
+#include "gvc-mixer-control.h"
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)
1572
+#define GVC_CHANNEL_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_CHANNEL_BAR, GvcChannelBarPrivate))
1574
+struct GvcChannelBarPrivate
1576
+ GtkOrientation orientation;
1577
+ GtkWidget *scale_box;
1578
+ GtkWidget *start_box;
1579
+ GtkWidget *end_box;
1582
+ GtkWidget *low_image;
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;
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;
1611
+ PROP_LOW_ICON_NAME,
1612
+ PROP_HIGH_ICON_NAME,
1613
+ PROP_IS_AMPLIFIED,
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);
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);
1631
+G_DEFINE_TYPE (GvcChannelBar, gvc_channel_bar, GTK_TYPE_HBOX)
1634
+_scale_box_new (GvcChannelBar *bar)
1636
+ GvcChannelBarPrivate *priv = bar->priv;
1641
+ if (priv->orientation == GTK_ORIENTATION_VERTICAL) {
1642
+ bar->priv->scale_box = box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1644
+ priv->scale = gtk_vscale_new (priv->adjustment);
1646
+ gtk_widget_set_size_request (priv->scale, -1, SCALE_SIZE);
1647
+ gtk_range_set_inverted (GTK_RANGE (priv->scale), TRUE);
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);
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);
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);
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);
1662
+ gtk_box_pack_start (GTK_BOX (ebox), priv->low_image, FALSE, FALSE, 0);
1663
+ gtk_widget_hide (priv->low_image);
1665
+ gtk_box_pack_start (GTK_BOX (ebox), priv->mute_box, FALSE, FALSE, 0);
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);
1670
+ priv->scale = gtk_hscale_new (priv->adjustment);
1672
+ gtk_widget_set_size_request (priv->scale, SCALE_SIZE, -1);
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);
1677
+ gtk_box_pack_end (GTK_BOX (sbox), priv->low_image, FALSE, FALSE, 0);
1678
+ gtk_widget_show (priv->low_image);
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);
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);
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);
1691
+ ca_gtk_widget_disable_sounds (bar->priv->scale, FALSE);
1692
+ gtk_widget_add_events (bar->priv->scale, GDK_SCROLL_MASK);
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);
1701
+ if (bar->priv->size_group != NULL) {
1702
+ gtk_size_group_add_widget (bar->priv->size_group, sbox);
1704
+ if (bar->priv->symmetric) {
1705
+ gtk_size_group_add_widget (bar->priv->size_group, ebox);
1709
+ gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE);
1715
+update_image (GvcChannelBar *bar)
1717
+ gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->image),
1718
+ bar->priv->icon_name,
1719
+ GTK_ICON_SIZE_DIALOG);
1721
+ if (bar->priv->icon_name != NULL) {
1722
+ gtk_widget_show (bar->priv->image);
1724
+ gtk_widget_hide (bar->priv->image);
1729
+update_label (GvcChannelBar *bar)
1731
+ if (bar->priv->name != NULL) {
1732
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (bar->priv->label),
1734
+ gtk_label_set_mnemonic_widget (GTK_LABEL (bar->priv->label),
1735
+ bar->priv->scale);
1736
+ gtk_widget_show (bar->priv->label);
1738
+ gtk_label_set_text (GTK_LABEL (bar->priv->label), NULL);
1739
+ gtk_widget_hide (bar->priv->label);
1744
+update_layout (GvcChannelBar *bar)
1749
+ if (bar->priv->scale == NULL) {
1753
+ box = bar->priv->scale_box;
1754
+ frame = gtk_widget_get_parent (box);
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);
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);
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);
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);
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);
1779
+ bar->priv->scale_box = _scale_box_new (bar);
1780
+ gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box);
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);
1788
+ gtk_widget_show_all (frame);
1792
+gvc_channel_bar_set_size_group (GvcChannelBar *bar,
1793
+ GtkSizeGroup *group,
1794
+ gboolean symmetric)
1796
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
1798
+ bar->priv->size_group = group;
1799
+ bar->priv->symmetric = symmetric;
1801
+ if (bar->priv->size_group != NULL) {
1802
+ gtk_size_group_add_widget (bar->priv->size_group,
1803
+ bar->priv->start_box);
1805
+ if (bar->priv->symmetric) {
1806
+ gtk_size_group_add_widget (bar->priv->size_group,
1807
+ bar->priv->end_box);
1810
+ gtk_widget_queue_draw (GTK_WIDGET (bar));
1814
+gvc_channel_bar_set_name (GvcChannelBar *bar,
1817
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
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");
1826
+gvc_channel_bar_set_icon_name (GvcChannelBar *bar,
1829
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
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");
1838
+gvc_channel_bar_set_low_icon_name (GvcChannelBar *bar,
1841
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
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");
1854
+gvc_channel_bar_set_high_icon_name (GvcChannelBar *bar,
1857
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
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");
1870
+gvc_channel_bar_set_orientation (GvcChannelBar *bar,
1871
+ GtkOrientation orientation)
1873
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
1875
+ if (orientation != bar->priv->orientation) {
1876
+ bar->priv->orientation = orientation;
1877
+ update_layout (bar);
1878
+ g_object_notify (G_OBJECT (bar), "orientation");
1883
+gvc_channel_bar_set_adjustment (GvcChannelBar *bar,
1884
+ GtkAdjustment *adjustment)
1886
+ g_return_if_fail (GVC_CHANNEL_BAR (bar));
1887
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
1889
+ if (bar->priv->adjustment != NULL) {
1890
+ g_object_unref (bar->priv->adjustment);
1892
+ bar->priv->adjustment = g_object_ref_sink (adjustment);
1894
+ if (bar->priv->scale != NULL) {
1895
+ gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale), adjustment);
1898
+ g_object_notify (G_OBJECT (bar), "adjustment");
1902
+gvc_channel_bar_get_adjustment (GvcChannelBar *bar)
1904
+ g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), NULL);
1906
+ return bar->priv->adjustment;
1910
+on_scale_button_press_event (GtkWidget *widget,
1911
+ GdkEventButton *event,
1912
+ GvcChannelBar *bar)
1914
+ bar->priv->click_lock = TRUE;
1920
+on_scale_button_release_event (GtkWidget *widget,
1921
+ GdkEventButton *event,
1922
+ GvcChannelBar *bar)
1924
+ GtkAdjustment *adj;
1927
+ bar->priv->click_lock = FALSE;
1929
+ adj = gtk_range_get_adjustment (GTK_RANGE (widget));
1931
+ value = gtk_adjustment_get_value (adj);
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));
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",
1948
+gvc_channel_bar_scroll (GvcChannelBar *bar, GdkEventScroll *event)
1950
+ GtkAdjustment *adj;
1952
+ GdkScrollDirection direction;
1955
+ g_return_val_if_fail (bar != NULL, FALSE);
1956
+ g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
1958
+ direction = event->direction;
1960
+ if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
1961
+ if (direction == GDK_SCROLL_LEFT || direction == GDK_SCROLL_RIGHT)
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;
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;
1978
+ if (!gdk_event_get_scroll_deltas ((GdkEvent*)event, &dx, &dy)) {
1982
+ switch (direction) {
1983
+ case GDK_SCROLL_UP:
1984
+ case GDK_SCROLL_LEFT:
1987
+ case GDK_SCROLL_DOWN:
1988
+ case GDK_SCROLL_RIGHT:
1996
+ adj = gtk_range_get_adjustment (GTK_RANGE (bar->priv->scale));
1997
+ if (adj == bar->priv->zero_adjustment) {
1999
+ gvc_channel_bar_set_is_muted (bar, FALSE);
2003
+ value = gtk_adjustment_get_value (adj);
2006
+ if (value + dy * SCROLLSTEP > ADJUSTMENT_MAX)
2007
+ value = ADJUSTMENT_MAX;
2009
+ value = value + dy * SCROLLSTEP;
2010
+ } else if (dy < 0) {
2011
+ if (value + dy * SCROLLSTEP < 0)
2014
+ value = value + dy * SCROLLSTEP;
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);
2025
+on_scale_scroll_event (GtkWidget *widget,
2026
+ GdkEventScroll *event,
2027
+ GvcChannelBar *bar)
2029
+ return gvc_channel_bar_scroll (bar, event);
2033
+on_zero_adjustment_value_changed (GtkAdjustment *adjustment,
2034
+ GvcChannelBar *bar)
2038
+ if (bar->priv->click_lock != FALSE) {
2042
+ value = gtk_adjustment_get_value (bar->priv->zero_adjustment);
2043
+ gtk_adjustment_set_value (bar->priv->adjustment, value);
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);
2054
+update_mute_button (GvcChannelBar *bar)
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);
2061
+ gtk_widget_hide (bar->priv->mute_button);
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,
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,
2075
+ gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale),
2076
+ bar->priv->zero_adjustment);
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);
2087
+gvc_channel_bar_set_is_muted (GvcChannelBar *bar,
2088
+ gboolean is_muted)
2090
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
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");
2102
+gvc_channel_bar_get_is_muted (GvcChannelBar *bar)
2104
+ g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
2105
+ return bar->priv->is_muted;
2109
+gvc_channel_bar_set_show_mute (GvcChannelBar *bar,
2110
+ gboolean show_mute)
2112
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
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);
2122
+gvc_channel_bar_get_show_mute (GvcChannelBar *bar)
2124
+ g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
2125
+ return bar->priv->show_mute;
2129
+gvc_channel_bar_set_is_amplified (GvcChannelBar *bar, gboolean amplified)
2131
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
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));
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);
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);
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);
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);
2171
+gvc_channel_bar_get_ellipsize (GvcChannelBar *bar)
2173
+ g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
2175
+ return gtk_label_get_ellipsize (GTK_LABEL (bar->priv->label)) != PANGO_ELLIPSIZE_NONE;
2179
+gvc_channel_bar_set_ellipsize (GvcChannelBar *bar,
2180
+ gboolean ellipsized)
2182
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
2185
+ gtk_label_set_ellipsize (GTK_LABEL (bar->priv->label), PANGO_ELLIPSIZE_END);
2187
+ gtk_label_set_ellipsize (GTK_LABEL (bar->priv->label), PANGO_ELLIPSIZE_NONE);
2191
+gvc_channel_bar_set_base_volume (GvcChannelBar *bar,
2192
+ pa_volume_t base_volume)
2194
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
2196
+ if (base_volume == 0) {
2197
+ bar->priv->base_volume = ADJUSTMENT_MAX_NORMAL;
2201
+ /* Note that you need to call _is_amplified() afterwards to update the marks */
2202
+ bar->priv->base_volume = base_volume;
2206
+gvc_channel_bar_set_property (GObject *object,
2208
+ const GValue *value,
2209
+ GParamSpec *pspec)
2211
+ GvcChannelBar *self = GVC_CHANNEL_BAR (object);
2213
+ switch (prop_id) {
2214
+ case PROP_ORIENTATION:
2215
+ gvc_channel_bar_set_orientation (self, g_value_get_enum (value));
2217
+ case PROP_IS_MUTED:
2218
+ gvc_channel_bar_set_is_muted (self, g_value_get_boolean (value));
2220
+ case PROP_SHOW_MUTE:
2221
+ gvc_channel_bar_set_show_mute (self, g_value_get_boolean (value));
2224
+ gvc_channel_bar_set_name (self, g_value_get_string (value));
2226
+ case PROP_ICON_NAME:
2227
+ gvc_channel_bar_set_icon_name (self, g_value_get_string (value));
2229
+ case PROP_LOW_ICON_NAME:
2230
+ gvc_channel_bar_set_low_icon_name (self, g_value_get_string (value));
2232
+ case PROP_HIGH_ICON_NAME:
2233
+ gvc_channel_bar_set_high_icon_name (self, g_value_get_string (value));
2235
+ case PROP_ADJUSTMENT:
2236
+ gvc_channel_bar_set_adjustment (self, g_value_get_object (value));
2238
+ case PROP_IS_AMPLIFIED:
2239
+ gvc_channel_bar_set_is_amplified (self, g_value_get_boolean (value));
2241
+ case PROP_ELLIPSIZE:
2242
+ gvc_channel_bar_set_ellipsize (self, g_value_get_boolean (value));
2245
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2251
+gvc_channel_bar_get_property (GObject *object,
2254
+ GParamSpec *pspec)
2256
+ GvcChannelBar *self = GVC_CHANNEL_BAR (object);
2257
+ GvcChannelBarPrivate *priv = self->priv;
2259
+ switch (prop_id) {
2260
+ case PROP_ORIENTATION:
2261
+ g_value_set_enum (value, priv->orientation);
2263
+ case PROP_IS_MUTED:
2264
+ g_value_set_boolean (value, priv->is_muted);
2266
+ case PROP_SHOW_MUTE:
2267
+ g_value_set_boolean (value, priv->show_mute);
2270
+ g_value_set_string (value, priv->name);
2272
+ case PROP_ICON_NAME:
2273
+ g_value_set_string (value, priv->icon_name);
2275
+ case PROP_LOW_ICON_NAME:
2276
+ g_value_set_string (value, priv->low_icon_name);
2278
+ case PROP_HIGH_ICON_NAME:
2279
+ g_value_set_string (value, priv->high_icon_name);
2281
+ case PROP_ADJUSTMENT:
2282
+ g_value_set_object (value, gvc_channel_bar_get_adjustment (self));
2284
+ case PROP_IS_AMPLIFIED:
2285
+ g_value_set_boolean (value, priv->is_amplified);
2287
+ case PROP_ELLIPSIZE:
2288
+ g_value_set_boolean (value, gvc_channel_bar_get_ellipsize (self));
2291
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2297
+gvc_channel_bar_constructor (GType type,
2298
+ guint n_construct_properties,
2299
+ GObjectConstructParam *construct_params)
2302
+ GvcChannelBar *self;
2304
+ object = G_OBJECT_CLASS (gvc_channel_bar_parent_class)->constructor (type, n_construct_properties, construct_params);
2306
+ self = GVC_CHANNEL_BAR (object);
2308
+ update_mute_button (self);
2314
+gvc_channel_bar_class_init (GvcChannelBarClass *klass)
2316
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
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;
2323
+ g_object_class_install_property (object_class,
2325
+ g_param_spec_enum ("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,
2333
+ g_param_spec_boolean ("is-muted",
2335
+ "Whether stream is muted",
2337
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2338
+ g_object_class_install_property (object_class,
2340
+ g_param_spec_boolean ("show-mute",
2342
+ "Whether stream is muted",
2344
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2346
+ g_object_class_install_property (object_class,
2348
+ g_param_spec_object ("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,
2355
+ g_param_spec_string ("name",
2357
+ "Name to display for this stream",
2359
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2360
+ g_object_class_install_property (object_class,
2362
+ g_param_spec_string ("icon-name",
2364
+ "Name of icon to display for this stream",
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",
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",
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",
2385
+ "Whether the stream is digitally amplified",
2387
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2388
+ g_object_class_install_property (object_class,
2390
+ g_param_spec_boolean ("ellipsize",
2391
+ "Label is ellipsized",
2392
+ "Whether the label is ellipsized",
2394
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2395
+ g_type_class_add_private (klass, sizeof (GvcChannelBarPrivate));
2399
+on_mute_button_toggled (GtkToggleButton *button,
2400
+ GvcChannelBar *bar)
2402
+ gboolean is_muted;
2403
+ is_muted = gtk_toggle_button_get_active (button);
2404
+ gvc_channel_bar_set_is_muted (bar, is_muted);
2408
+gvc_channel_bar_init (GvcChannelBar *bar)
2412
+ bar->priv = GVC_CHANNEL_BAR_GET_PRIVATE (bar);
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");
2418
+ bar->priv->orientation = GTK_ORIENTATION_VERTICAL;
2419
+ bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
2421
+ ADJUSTMENT_MAX_NORMAL,
2422
+ ADJUSTMENT_MAX_NORMAL/100.0,
2423
+ ADJUSTMENT_MAX_NORMAL/10.0,
2425
+ g_object_ref_sink (bar->priv->adjustment);
2427
+ bar->priv->zero_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
2429
+ ADJUSTMENT_MAX_NORMAL,
2430
+ ADJUSTMENT_MAX_NORMAL/100.0,
2431
+ ADJUSTMENT_MAX_NORMAL/10.0,
2433
+ g_object_ref_sink (bar->priv->zero_adjustment);
2435
+ g_signal_connect (bar->priv->zero_adjustment,
2437
+ G_CALLBACK (on_zero_adjustment_value_changed),
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,
2444
+ G_CALLBACK (on_mute_button_toggled),
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);
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);
2456
+ bar->priv->image = gtk_image_new ();
2457
+ gtk_widget_set_no_show_all (bar->priv->image, TRUE);
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);
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);
2469
+ /* box with scale */
2470
+ bar->priv->scale_box = _scale_box_new (bar);
2472
+ gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box);
2476
+gvc_channel_bar_finalize (GObject *object)
2478
+ GvcChannelBar *channel_bar;
2480
+ g_return_if_fail (object != NULL);
2481
+ g_return_if_fail (GVC_IS_CHANNEL_BAR (object));
2483
+ channel_bar = GVC_CHANNEL_BAR (object);
2485
+ g_return_if_fail (channel_bar->priv != NULL);
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);
2492
+ G_OBJECT_CLASS (gvc_channel_bar_parent_class)->finalize (object);
2496
+gvc_channel_bar_new (void)
2499
+ bar = g_object_new (GVC_TYPE_CHANNEL_BAR,
2501
+ return GTK_WIDGET (bar);
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
2508
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2510
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
2528
+#ifndef __GVC_CHANNEL_BAR_H
2529
+#define __GVC_CHANNEL_BAR_H
2531
+#include <glib-object.h>
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))
2542
+typedef struct GvcChannelBarPrivate GvcChannelBarPrivate;
2547
+ GvcChannelBarPrivate *priv;
2552
+ GtkHBoxClass parent_class;
2553
+} GvcChannelBarClass;
2555
+GType gvc_channel_bar_get_type (void);
2557
+GtkWidget * gvc_channel_bar_new (void);
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);
2568
+void gvc_channel_bar_set_orientation (GvcChannelBar *bar,
2569
+ GtkOrientation orientation);
2570
+GtkOrientation gvc_channel_bar_get_orientation (GvcChannelBar *bar);
2572
+GtkAdjustment * gvc_channel_bar_get_adjustment (GvcChannelBar *bar);
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);
2591
+gboolean gvc_channel_bar_scroll (GvcChannelBar *bar,
2592
+ GdkEventScroll *event);
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
2602
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2604
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
2622
+#ifndef __GVC_CHANNEL_MAP_PRIVATE_H
2623
+#define __GVC_CHANNEL_MAP_PRIVATE_H
2625
+#include <glib-object.h>
2626
+#include <pulse/pulseaudio.h>
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);
2633
+void gvc_channel_map_volume_changed (GvcChannelMap *map,
2634
+ const pa_cvolume *cv,
2636
+const pa_cvolume * gvc_channel_map_get_cvolume (const GvcChannelMap *map);
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
2646
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2648
+ * Copyright (C) 2008 William Jon McCann
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.
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.
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.
2666
+#include "config.h"
2668
+#include <stdlib.h>
2670
+#include <unistd.h>
2673
+#include <glib/gi18n-lib.h>
2675
+#include <pulse/pulseaudio.h>
2677
+#include "gvc-channel-map.h"
2678
+#include "gvc-channel-map-private.h"
2680
+#define GVC_CHANNEL_MAP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMapPrivate))
2682
+struct GvcChannelMapPrivate
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;
2697
+static guint signals [LAST_SIGNAL] = { 0, };
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);
2703
+G_DEFINE_TYPE (GvcChannelMap, gvc_channel_map, G_TYPE_OBJECT)
2706
+gvc_channel_map_get_num_channels (const GvcChannelMap *map)
2708
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), 0);
2710
+ if (!pa_channel_map_valid(&map->priv->pa_map))
2713
+ return map->priv->pa_map.channels;
2717
+gvc_channel_map_get_volume (GvcChannelMap *map)
2719
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
2721
+ if (!pa_channel_map_valid(&map->priv->pa_map))
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);
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);
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);
2736
+ map->priv->extern_volume[LFE] = 0;
2738
+ return map->priv->extern_volume;
2742
+gvc_channel_map_can_balance (const GvcChannelMap *map)
2744
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
2746
+ return map->priv->can_balance;
2750
+gvc_channel_map_can_fade (const GvcChannelMap *map)
2752
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
2754
+ return map->priv->can_fade;
2758
+gvc_channel_map_get_mapping (const GvcChannelMap *map)
2760
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
2762
+ if (!pa_channel_map_valid(&map->priv->pa_map))
2765
+ return pa_channel_map_to_pretty_name (&map->priv->pa_map);
2769
+ * gvc_channel_map_has_position: (skip)
2777
+gvc_channel_map_has_position (const GvcChannelMap *map,
2778
+ pa_channel_position_t position)
2780
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
2782
+ return pa_channel_map_has_position (&(map->priv->pa_map), position);
2785
+const pa_channel_map *
2786
+gvc_channel_map_get_pa_channel_map (const GvcChannelMap *map)
2788
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
2790
+ if (!pa_channel_map_valid(&map->priv->pa_map))
2793
+ return &map->priv->pa_map;
2797
+gvc_channel_map_get_cvolume (const GvcChannelMap *map)
2799
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
2801
+ if (!pa_channel_map_valid(&map->priv->pa_map))
2804
+ return &map->priv->pa_volume;
2808
+gvc_channel_map_class_init (GvcChannelMapClass *klass)
2810
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2812
+ gobject_class->finalize = gvc_channel_map_finalize;
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),
2820
+ g_cclosure_marshal_VOID__BOOLEAN,
2821
+ G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
2823
+ g_type_class_add_private (klass, sizeof (GvcChannelMapPrivate));
2827
+gvc_channel_map_volume_changed (GvcChannelMap *map,
2828
+ const pa_cvolume *cv,
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));
2835
+ if (pa_cvolume_equal(cv, &map->priv->pa_volume))
2838
+ map->priv->pa_volume = *cv;
2840
+ if (map->priv->pa_volume_is_set == FALSE) {
2841
+ map->priv->pa_volume_is_set = TRUE;
2844
+ g_signal_emit (map, signals[VOLUME_CHANGED], 0, set);
2848
+gvc_channel_map_init (GvcChannelMap *map)
2850
+ map->priv = GVC_CHANNEL_MAP_GET_PRIVATE (map);
2851
+ map->priv->pa_volume_is_set = FALSE;
2855
+gvc_channel_map_finalize (GObject *object)
2857
+ GvcChannelMap *channel_map;
2859
+ g_return_if_fail (object != NULL);
2860
+ g_return_if_fail (GVC_IS_CHANNEL_MAP (object));
2862
+ channel_map = GVC_CHANNEL_MAP (object);
2864
+ g_return_if_fail (channel_map->priv != NULL);
2866
+ G_OBJECT_CLASS (gvc_channel_map_parent_class)->finalize (object);
2870
+gvc_channel_map_new (void)
2873
+ map = g_object_new (GVC_TYPE_CHANNEL_MAP, NULL);
2874
+ return GVC_CHANNEL_MAP (map);
2878
+set_from_pa_map (GvcChannelMap *map,
2879
+ const pa_channel_map *pa_map)
2881
+ g_assert (pa_channel_map_valid(pa_map));
2883
+ map->priv->can_balance = pa_channel_map_can_balance (pa_map);
2884
+ map->priv->can_fade = pa_channel_map_can_fade (pa_map);
2886
+ map->priv->pa_map = *pa_map;
2887
+ pa_cvolume_set(&map->priv->pa_volume, pa_map->channels, PA_VOLUME_NORM);
2891
+gvc_channel_map_new_from_pa_channel_map (const pa_channel_map *pa_map)
2894
+ map = g_object_new (GVC_TYPE_CHANNEL_MAP, NULL);
2896
+ set_from_pa_map (GVC_CHANNEL_MAP (map), pa_map);
2898
+ return GVC_CHANNEL_MAP (map);
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
2905
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2907
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
2925
+#ifndef __GVC_CHANNEL_MAP_H
2926
+#define __GVC_CHANNEL_MAP_H
2928
+#include <glib-object.h>
2929
+#include <gvc-pulseaudio-fake.h>
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))
2940
+typedef struct GvcChannelMapPrivate GvcChannelMapPrivate;
2945
+ GvcChannelMapPrivate *priv;
2950
+ GObjectClass parent_class;
2951
+ void (*volume_changed) (GvcChannelMap *channel_map, gboolean set);
2952
+} GvcChannelMapClass;
2962
+GType gvc_channel_map_get_type (void);
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)
2973
+const char * gvc_channel_map_get_mapping (const GvcChannelMap *map);
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
2983
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2985
+ * Copyright (C) 2009 Bastien Nocera
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.
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.
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.
3003
+#include "config.h"
3005
+#include <stdlib.h>
3007
+#include <unistd.h>
3010
+#include <glib/gi18n-lib.h>
3011
+#include <gtk/gtk.h>
3012
+#include <canberra-gtk.h>
3013
+#include <pulse/pulseaudio.h>
3015
+#include "gvc-combo-box.h"
3016
+#include "gvc-mixer-stream.h"
3017
+#include "gvc-mixer-card.h"
3019
+#define GVC_COMBO_BOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_COMBO_BOX, GvcComboBoxPrivate))
3021
+struct GvcComboBoxPrivate
3023
+ GtkWidget *drop_box;
3024
+ GtkWidget *start_box;
3025
+ GtkWidget *end_box;
3027
+ GtkWidget *button;
3028
+ GtkTreeModel *model;
3029
+ GtkWidget *combobox;
3030
+ gboolean set_called;
3031
+ GtkSizeGroup *size_group;
3032
+ gboolean symmetric;
3054
+static guint signals [LAST_SIGNAL] = { 0, };
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);
3060
+G_DEFINE_TYPE (GvcComboBox, gvc_combo_box, GTK_TYPE_HBOX)
3063
+gvc_combo_box_set_size_group (GvcComboBox *combo_box,
3064
+ GtkSizeGroup *group,
3065
+ gboolean symmetric)
3067
+ g_return_if_fail (GVC_IS_COMBO_BOX (combo_box));
3069
+ combo_box->priv->size_group = group;
3070
+ combo_box->priv->symmetric = symmetric;
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);
3076
+ if (combo_box->priv->symmetric) {
3077
+ gtk_size_group_add_widget (combo_box->priv->size_group,
3078
+ combo_box->priv->end_box);
3081
+ gtk_widget_queue_draw (GTK_WIDGET (combo_box));
3085
+gvc_combo_box_set_property (GObject *object,
3087
+ const GValue *value,
3088
+ GParamSpec *pspec)
3090
+ GvcComboBox *self = GVC_COMBO_BOX (object);
3092
+ switch (prop_id) {
3094
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (self->priv->label), g_value_get_string (value));
3096
+ case PROP_BUTTON_LABEL:
3097
+ gtk_button_set_label (GTK_BUTTON (self->priv->button), g_value_get_string (value));
3099
+ case PROP_SHOW_BUTTON:
3100
+ gtk_widget_set_visible (self->priv->button, g_value_get_boolean (value));
3103
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3109
+gvc_combo_box_get_property (GObject *object,
3112
+ GParamSpec *pspec)
3114
+ GvcComboBox *self = GVC_COMBO_BOX (object);
3116
+ switch (prop_id) {
3118
+ g_value_set_string (value,
3119
+ gtk_label_get_text (GTK_LABEL (self->priv->label)));
3121
+ case PROP_BUTTON_LABEL:
3122
+ g_value_set_string (value,
3123
+ gtk_button_get_label (GTK_BUTTON (self->priv->button)));
3125
+ case PROP_SHOW_BUTTON:
3126
+ g_value_set_boolean (value,
3127
+ gtk_widget_get_visible (self->priv->button));
3130
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3136
+gvc_combo_box_class_init (GvcComboBoxClass *klass)
3138
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
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;
3144
+ g_object_class_install_property (object_class,
3146
+ g_param_spec_string ("label",
3148
+ "The combo box label",
3150
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
3151
+ g_object_class_install_property (object_class,
3153
+ g_param_spec_boolean ("show-button",
3155
+ "Whether to show the button",
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",
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),
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),
3179
+ g_cclosure_marshal_VOID__VOID,
3180
+ G_TYPE_NONE, 0, G_TYPE_NONE);
3182
+ g_type_class_add_private (klass, sizeof (GvcComboBoxPrivate));
3186
+gvc_combo_box_set_profiles (GvcComboBox *combo_box,
3187
+ const GHashTable* profiles)
3189
+ g_return_if_fail (GVC_IS_COMBO_BOX (combo_box));
3190
+ g_return_if_fail (combo_box->priv->set_called == FALSE);
3193
+ const GList *keys;
3195
+ keys = g_hash_table_get_keys (profiles);
3197
+ for (l = keys; l != NULL; l = l->next) {
3199
+ GvcMixerCardProfile *p;
3202
+ p = g_hash_table_lookup (profiles, k);
3203
+ g_debug ("set profiles - key %s \n profile %s \n human profile %s",
3206
+ p->human_profile);
3208
+ gtk_list_store_insert_with_values (GTK_LIST_STORE (combo_box->priv->model),
3211
+ COL_NAME, p->profile,
3212
+ COL_HUMAN_NAME, p->human_profile,
3215
+ combo_box->priv->set_called = TRUE;
3219
+gvc_combo_box_set_ports (GvcComboBox *combo_box,
3220
+ const GList *ports)
3224
+ g_return_if_fail (GVC_IS_COMBO_BOX (combo_box));
3225
+ g_return_if_fail (combo_box->priv->set_called == FALSE);
3227
+ for (l = ports; l != NULL; l = l->next) {
3228
+ GvcMixerStreamPort *p = l->data;
3230
+ gtk_list_store_insert_with_values (GTK_LIST_STORE (combo_box->priv->model),
3233
+ COL_NAME, p->port,
3234
+ COL_HUMAN_NAME, p->human_port,
3237
+ combo_box->priv->set_called = TRUE;
3241
+gvc_combo_box_set_active (GvcComboBox *combo_box,
3247
+ cont = gtk_tree_model_get_iter_first (combo_box->priv->model, &iter);
3248
+ while (cont != FALSE) {
3251
+ gtk_tree_model_get (combo_box->priv->model, &iter,
3254
+ if (g_strcmp0 (name, id) == 0) {
3255
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box->priv->combobox), &iter);
3258
+ cont = gtk_tree_model_iter_next (combo_box->priv->model, &iter);
3260
+ g_warning ("Could not find id '%s' in combo box", id);
3264
+on_combo_box_changed (GtkComboBox *widget,
3265
+ GvcComboBox *combo_box)
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");
3275
+ gtk_tree_model_get (combo_box->priv->model, &iter,
3276
+ COL_NAME, &profile,
3278
+ g_signal_emit (combo_box, signals[CHANGED], 0, profile);
3283
+on_combo_box_button_clicked (GtkButton *button,
3284
+ GvcComboBox *combo_box)
3286
+ g_signal_emit (combo_box, signals[BUTTON_CLICKED], 0);
3290
+gvc_combo_box_init (GvcComboBox *combo_box)
3296
+ GtkCellRenderer *renderer;
3298
+ combo_box->priv = GVC_COMBO_BOX_GET_PRIVATE (combo_box);
3300
+ combo_box->priv->model = GTK_TREE_MODEL (gtk_list_store_new (NUM_COLS,
3304
+ combo_box->priv->label = gtk_label_new (NULL);
3305
+ gtk_misc_set_alignment (GTK_MISC (combo_box->priv->label),
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);
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);
3317
+ renderer = gtk_cell_renderer_text_new ();
3318
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box->priv->combobox),
3320
+ gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->combobox),
3322
+ "text", COL_HUMAN_NAME);
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);
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);
3333
+ gtk_box_pack_start (GTK_BOX (sbox), combo_box->priv->label, FALSE, FALSE, 0);
3335
+ gtk_box_pack_start (GTK_BOX (box), combo_box->priv->combobox, TRUE, TRUE, 0);
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);
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);
3345
+ if (combo_box->priv->size_group != NULL) {
3346
+ gtk_size_group_add_widget (combo_box->priv->size_group, sbox);
3348
+ if (combo_box->priv->symmetric) {
3349
+ gtk_size_group_add_widget (combo_box->priv->size_group, ebox);
3353
+ gtk_container_add (GTK_CONTAINER (frame), combo_box->priv->drop_box);
3354
+ gtk_widget_show_all (frame);
3356
+ gtk_label_set_mnemonic_widget (GTK_LABEL (combo_box->priv->label),
3357
+ combo_box->priv->combobox);
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);
3366
+gvc_combo_box_finalize (GObject *object)
3368
+ GvcComboBox *combo_box;
3370
+ g_return_if_fail (object != NULL);
3371
+ g_return_if_fail (GVC_IS_COMBO_BOX (object));
3373
+ combo_box = GVC_COMBO_BOX (object);
3375
+ g_return_if_fail (combo_box->priv != NULL);
3377
+ g_object_unref (combo_box->priv->model);
3378
+ combo_box->priv->model = NULL;
3380
+ G_OBJECT_CLASS (gvc_combo_box_parent_class)->finalize (object);
3384
+gvc_combo_box_new (const char *label)
3386
+ GObject *combo_box;
3387
+ combo_box = g_object_new (GVC_TYPE_COMBO_BOX,
3390
+ return GTK_WIDGET (combo_box);
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
3398
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3400
+ * Copyright (C) 2009 Red Hat, Inc.
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.
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.
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.
3418
+#ifndef __GVC_COMBO_BOX_H
3419
+#define __GVC_COMBO_BOX_H
3421
+#include <glib-object.h>
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))
3432
+typedef struct GvcComboBoxPrivate GvcComboBoxPrivate;
3437
+ GvcComboBoxPrivate *priv;
3442
+ GtkHBoxClass parent_class;
3443
+ void (* changed) (GvcComboBox *combobox, const char *name);
3444
+ void (* button_clicked) (GvcComboBox *combobox);
3445
+} GvcComboBoxClass;
3447
+GType gvc_combo_box_get_type (void);
3449
+GtkWidget * gvc_combo_box_new (const char *label);
3451
+void gvc_combo_box_set_size_group (GvcComboBox *combo_box,
3452
+ GtkSizeGroup *group,
3453
+ gboolean symmetric);
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,
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
3469
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3471
+ * Copyright (C) 2008 William Jon McCann <william.jon.mccann@gmail.com>
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.
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.
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.
3489
+#include "config.h"
3491
+#include <stdlib.h>
3493
+#include <unistd.h>
3497
+#include <glib/gi18n-lib.h>
3498
+#include <gtk/gtk.h>
3500
+#include "gvc-level-bar.h"
3502
+#define NUM_BOXES 30
3504
+#define GVC_LEVEL_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_LEVEL_BAR, GvcLevelBarPrivate))
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
3515
+ GdkRectangle area;
3531
+struct GvcLevelBarPrivate
3533
+ GtkOrientation orientation;
3534
+ GtkAdjustment *peak_adjustment;
3535
+ GtkAdjustment *rms_adjustment;
3537
+ gdouble peak_fraction;
3538
+ gdouble rms_fraction;
3540
+ guint max_peak_id;
3541
+ LevelBarLayout layout;
3547
+ PROP_PEAK_ADJUSTMENT,
3548
+ PROP_RMS_ADJUSTMENT,
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);
3557
+G_DEFINE_TYPE (GvcLevelBar, gvc_level_bar, GTK_TYPE_WIDGET)
3559
+#define check_rectangle(rectangle1, rectangle2) \
3561
+ /* .x and .y are always 0 */ \
3562
+ if (rectangle1.width != rectangle2.width) return TRUE; \
3563
+ if (rectangle1.height != rectangle2.height) return TRUE; \
3567
+layout_changed (LevelBarLayout *layout1,
3568
+ LevelBarLayout *layout2)
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)
3578
+ if (layout1->bdr_r != layout2->bdr_r
3579
+ || layout1->bdr_g != layout2->bdr_g
3580
+ || layout1->bdr_b != layout2->bdr_b)
3582
+ if (layout1->fl_r != layout2->fl_r
3583
+ || layout1->fl_g != layout2->fl_g
3584
+ || layout1->fl_b != layout2->fl_b)
3591
+fraction_from_adjustment (GvcLevelBar *bar,
3592
+ GtkAdjustment *adjustment)
3599
+ level = gtk_adjustment_get_value (adjustment);
3601
+ min = gtk_adjustment_get_lower (adjustment);
3602
+ max = gtk_adjustment_get_upper (adjustment);
3604
+ switch (bar->priv->scale) {
3605
+ case GVC_LEVEL_SCALE_LINEAR:
3606
+ fraction = (level - min) / (max - min);
3608
+ case GVC_LEVEL_SCALE_LOG:
3609
+ fraction = log10 ((level - min + 1) / (max - min + 1));
3612
+ g_assert_not_reached ();
3619
+reset_max_peak (GvcLevelBar *bar)
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;
3632
+bar_calc_layout (GvcLevelBar *bar)
3636
+ int max_peak_level;
3637
+ GtkAllocation allocation;
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;
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;
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;
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;
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;
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;
3680
+ /* This can happen if the level bar isn't realized */
3681
+ if (bar->priv->layout.delta == 0)
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;
3689
+update_peak_value (GvcLevelBar *bar)
3692
+ LevelBarLayout layout;
3694
+ layout = bar->priv->layout;
3696
+ val = fraction_from_adjustment (bar, bar->priv->peak_adjustment);
3697
+ bar->priv->peak_fraction = val;
3699
+ if (val > bar->priv->max_peak) {
3700
+ if (bar->priv->max_peak_id > 0) {
3701
+ g_source_remove (bar->priv->max_peak_id);
3703
+ bar->priv->max_peak_id = g_timeout_add_seconds (1, (GSourceFunc)reset_max_peak, bar);
3704
+ bar->priv->max_peak = val;
3707
+ bar_calc_layout (bar);
3709
+ if (layout_changed (&bar->priv->layout, &layout)) {
3710
+ gtk_widget_queue_draw (GTK_WIDGET (bar));
3715
+update_rms_value (GvcLevelBar *bar)
3719
+ val = fraction_from_adjustment (bar, bar->priv->rms_adjustment);
3720
+ bar->priv->rms_fraction = val;
3724
+gvc_level_bar_get_orientation (GvcLevelBar *bar)
3726
+ g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), 0);
3727
+ return bar->priv->orientation;
3731
+gvc_level_bar_set_orientation (GvcLevelBar *bar,
3732
+ GtkOrientation orientation)
3734
+ g_return_if_fail (GVC_IS_LEVEL_BAR (bar));
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");
3744
+on_peak_adjustment_value_changed (GtkAdjustment *adjustment,
3747
+ update_peak_value (bar);
3751
+on_rms_adjustment_value_changed (GtkAdjustment *adjustment,
3754
+ update_rms_value (bar);
3758
+gvc_level_bar_set_peak_adjustment (GvcLevelBar *bar,
3759
+ GtkAdjustment *adjustment)
3761
+ g_return_if_fail (GVC_LEVEL_BAR (bar));
3762
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
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),
3768
+ g_object_unref (bar->priv->peak_adjustment);
3771
+ bar->priv->peak_adjustment = g_object_ref_sink (adjustment);
3773
+ g_signal_connect (bar->priv->peak_adjustment,
3775
+ G_CALLBACK (on_peak_adjustment_value_changed),
3778
+ update_peak_value (bar);
3780
+ g_object_notify (G_OBJECT (bar), "peak-adjustment");
3784
+gvc_level_bar_set_rms_adjustment (GvcLevelBar *bar,
3785
+ GtkAdjustment *adjustment)
3787
+ g_return_if_fail (GVC_LEVEL_BAR (bar));
3788
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
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),
3794
+ g_object_unref (bar->priv->rms_adjustment);
3797
+ bar->priv->rms_adjustment = g_object_ref_sink (adjustment);
3800
+ g_signal_connect (bar->priv->peak_adjustment,
3802
+ G_CALLBACK (on_peak_adjustment_value_changed),
3805
+ update_rms_value (bar);
3807
+ g_object_notify (G_OBJECT (bar), "rms-adjustment");
3811
+gvc_level_bar_get_peak_adjustment (GvcLevelBar *bar)
3813
+ g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), NULL);
3815
+ return bar->priv->peak_adjustment;
3819
+gvc_level_bar_get_rms_adjustment (GvcLevelBar *bar)
3821
+ g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), NULL);
3823
+ return bar->priv->rms_adjustment;
3827
+gvc_level_bar_set_scale (GvcLevelBar *bar,
3828
+ GvcLevelScale scale)
3830
+ g_return_if_fail (GVC_IS_LEVEL_BAR (bar));
3832
+ if (scale != bar->priv->scale) {
3833
+ bar->priv->scale = scale;
3835
+ update_peak_value (bar);
3836
+ update_rms_value (bar);
3838
+ g_object_notify (G_OBJECT (bar), "scale");
3843
+gvc_level_bar_set_property (GObject *object,
3845
+ const GValue *value,
3846
+ GParamSpec *pspec)
3848
+ GvcLevelBar *self = GVC_LEVEL_BAR (object);
3850
+ switch (prop_id) {
3852
+ gvc_level_bar_set_scale (self, g_value_get_int (value));
3854
+ case PROP_ORIENTATION:
3855
+ gvc_level_bar_set_orientation (self, g_value_get_enum (value));
3857
+ case PROP_PEAK_ADJUSTMENT:
3858
+ gvc_level_bar_set_peak_adjustment (self, g_value_get_object (value));
3860
+ case PROP_RMS_ADJUSTMENT:
3861
+ gvc_level_bar_set_rms_adjustment (self, g_value_get_object (value));
3864
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3870
+gvc_level_bar_get_property (GObject *object,
3873
+ GParamSpec *pspec)
3875
+ GvcLevelBar *self = GVC_LEVEL_BAR (object);
3877
+ switch (prop_id) {
3879
+ g_value_set_int (value, self->priv->scale);
3881
+ case PROP_ORIENTATION:
3882
+ g_value_set_enum (value, self->priv->orientation);
3884
+ case PROP_PEAK_ADJUSTMENT:
3885
+ g_value_set_object (value, self->priv->peak_adjustment);
3887
+ case PROP_RMS_ADJUSTMENT:
3888
+ g_value_set_object (value, self->priv->rms_adjustment);
3891
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3897
+gvc_level_bar_constructor (GType type,
3898
+ guint n_construct_properties,
3899
+ GObjectConstructParam *construct_params)
3901
+ return G_OBJECT_CLASS (gvc_level_bar_parent_class)->constructor (type, n_construct_properties, construct_params);
3905
+gvc_level_bar_size_request (GtkWidget *widget,
3906
+ GtkRequisition *requisition)
3908
+ GvcLevelBar *bar = GVC_LEVEL_BAR (widget);
3910
+ switch (bar->priv->orientation) {
3911
+ case GTK_ORIENTATION_VERTICAL:
3912
+ requisition->width = VERTICAL_BAR_WIDTH;
3913
+ requisition->height = MIN_VERTICAL_BAR_HEIGHT;
3915
+ case GTK_ORIENTATION_HORIZONTAL:
3916
+ requisition->width = MIN_HORIZONTAL_BAR_WIDTH;
3917
+ requisition->height = HORIZONTAL_BAR_HEIGHT;
3920
+ g_assert_not_reached ();
3926
+gvc_level_bar_get_preferred_width (GtkWidget *widget,
3930
+ GtkRequisition requisition;
3932
+ gvc_level_bar_size_request (widget, &requisition);
3934
+ if (minimum != NULL) {
3935
+ *minimum = requisition.width;
3937
+ if (natural != NULL) {
3938
+ *natural = requisition.width;
3943
+gvc_level_bar_get_preferred_height (GtkWidget *widget,
3947
+ GtkRequisition requisition;
3949
+ gvc_level_bar_size_request (widget, &requisition);
3951
+ if (minimum != NULL) {
3952
+ *minimum = requisition.height;
3954
+ if (natural != NULL) {
3955
+ *natural = requisition.height;
3960
+gvc_level_bar_size_allocate (GtkWidget *widget,
3961
+ GtkAllocation *allocation)
3965
+ g_return_if_fail (GVC_IS_LEVEL_BAR (widget));
3966
+ g_return_if_fail (allocation != NULL);
3968
+ bar = GVC_LEVEL_BAR (widget);
3970
+ /* FIXME: add height property, labels, etc */
3971
+ GTK_WIDGET_CLASS (gvc_level_bar_parent_class)->size_allocate (widget, allocation);
3973
+ gtk_widget_set_allocation (widget, allocation);
3974
+ gtk_widget_get_allocation (widget, allocation);
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);
3980
+ allocation->width = MIN (allocation->width, MIN_HORIZONTAL_BAR_WIDTH);
3981
+ allocation->height = MAX (allocation->height, HORIZONTAL_BAR_HEIGHT);
3984
+ bar_calc_layout (bar);
3988
+curved_rectangle (cairo_t *cr,
4001
+ if (!width || !height) {
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);
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);
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);
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);
4041
+ cairo_close_path (cr);
4045
+gvc_level_bar_draw (GtkWidget *widget,
4050
+ g_return_val_if_fail (GVC_IS_LEVEL_BAR (widget), FALSE);
4052
+ bar = GVC_LEVEL_BAR (widget);
4054
+ if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
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,
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);
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);
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);
4093
+ for (i = 0; i < NUM_BOXES; i++) {
4094
+ bx = i * bar->priv->layout.delta;
4095
+ curved_rectangle (cr,
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);
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);
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);
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);
4130
+gvc_level_bar_class_init (GvcLevelBarClass *klass)
4132
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
4133
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
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;
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;
4145
+ g_object_class_install_property (object_class,
4147
+ g_param_spec_enum ("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",
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,
4169
+ g_param_spec_int ("scale",
4174
+ GVC_LEVEL_SCALE_LINEAR,
4175
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
4177
+ g_type_class_add_private (klass, sizeof (GvcLevelBarPrivate));
4181
+gvc_level_bar_init (GvcLevelBar *bar)
4183
+ bar->priv = GVC_LEVEL_BAR_GET_PRIVATE (bar);
4185
+ bar->priv->peak_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
4191
+ g_object_ref_sink (bar->priv->peak_adjustment);
4192
+ g_signal_connect (bar->priv->peak_adjustment,
4194
+ G_CALLBACK (on_peak_adjustment_value_changed),
4197
+ bar->priv->rms_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
4203
+ g_object_ref_sink (bar->priv->rms_adjustment);
4204
+ g_signal_connect (bar->priv->rms_adjustment,
4206
+ G_CALLBACK (on_rms_adjustment_value_changed),
4209
+ gtk_widget_set_has_window (GTK_WIDGET (bar), FALSE);
4213
+gvc_level_bar_finalize (GObject *object)
4217
+ g_return_if_fail (object != NULL);
4218
+ g_return_if_fail (GVC_IS_LEVEL_BAR (object));
4220
+ bar = GVC_LEVEL_BAR (object);
4222
+ if (bar->priv->max_peak_id > 0) {
4223
+ g_source_remove (bar->priv->max_peak_id);
4226
+ g_return_if_fail (bar->priv != NULL);
4228
+ G_OBJECT_CLASS (gvc_level_bar_parent_class)->finalize (object);
4232
+gvc_level_bar_new (void)
4235
+ bar = g_object_new (GVC_TYPE_LEVEL_BAR,
4237
+ return GTK_WIDGET (bar);
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
4244
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
4246
+ * Copyright (C) 2008 William Jon McCann <william.jon.mccann@gmail.com>
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.
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.
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.
4264
+#ifndef __GVC_LEVEL_BAR_H
4265
+#define __GVC_LEVEL_BAR_H
4267
+#include <glib-object.h>
4268
+#include <gtk/gtk.h>
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))
4279
+typedef struct GvcLevelBarPrivate GvcLevelBarPrivate;
4284
+ GvcLevelBarPrivate *priv;
4289
+ GtkWidgetClass parent_class;
4290
+} GvcLevelBarClass;
4294
+ GVC_LEVEL_SCALE_LINEAR,
4295
+ GVC_LEVEL_SCALE_LOG,
4296
+ GVC_LEVEL_SCALE_LAST
4299
+GType gvc_level_bar_get_type (void);
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);
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);
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
4324
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
4326
+ * Copyright (C) 2009 Red Hat, Inc.
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.
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.
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.
4345
+#include "config.h"
4348
+#include <glib/gstdio.h>
4350
+#include "gvc-log.h"
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;
4361
+gvc_log_default_handler (const gchar *log_domain,
4362
+ GLogLevelFlags log_level,
4363
+ const gchar *message,
4364
+ gpointer unused_data)
4366
+ if ((log_level & log_levels) == 0)
4369
+ g_log_default_handler (log_domain, log_level, message, unused_data);
4373
+gvc_log_init (void)
4375
+ g_log_set_default_handler (gvc_log_default_handler, NULL);
4379
+gvc_log_set_debug (gboolean debug)
4382
+ log_levels |= (G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_INFO);
4383
+ g_debug ("Enabling debugging");
4385
+ log_levels &= ~ (G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_INFO);
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
4393
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
4395
+ * Copyright (C) 2009 Red Hat, Inc.
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.
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.
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.
4413
+#ifndef __GVC_LOG_H
4414
+#define __GVC_LOG_H
4421
+void gvc_log_init (void);
4422
+void gvc_log_set_debug (gboolean debug);
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
4433
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
4435
+ * Copyright (C) 2008-2009 Red Hat, Inc.
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.
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.
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.
4453
+#ifndef __GVC_MIXER_CARD_PRIVATE_H
4454
+#define __GVC_MIXER_CARD_PRIVATE_H
4456
+#include <pulse/pulseaudio.h>
4457
+#include "gvc-mixer-card.h"
4461
+GvcMixerCard * gvc_mixer_card_new (pa_context *context,
4463
+pa_context * gvc_mixer_card_get_pa_context (GvcMixerCard *card);
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
4473
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
4475
+ * Copyright (C) 2008 William Jon McCann
4476
+ * Copyright (C) 2009 Bastien Nocera
4477
+ * Copyright (C) Conor Curran 2011 <conor.curran@canonical.com>
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.
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.
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.
4495
+#include "config.h"
4497
+#include <stdlib.h>
4499
+#include <unistd.h>
4502
+#include <glib/gi18n-lib.h>
4504
+#include <pulse/pulseaudio.h>
4506
+#include "gvc-mixer-card.h"
4507
+#include "gvc-mixer-card-private.h"
4509
+#define GVC_MIXER_CARD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_CARD, GvcMixerCardPrivate))
4511
+static guint32 card_serial = 1;
4513
+struct GvcMixerCardPrivate
4515
+ pa_context *pa_context;
4521
+ char *target_profile;
4522
+ char *human_profile;
4524
+ pa_operation *profile_op;
4537
+ PROP_HUMAN_PROFILE,
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);
4544
+G_DEFINE_TYPE (GvcMixerCard, gvc_mixer_card, G_TYPE_OBJECT)
4547
+get_next_card_serial (void)
4551
+ serial = card_serial++;
4553
+ if ((gint32)card_serial < 0) {
4561
+gvc_mixer_card_get_pa_context (GvcMixerCard *card)
4563
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
4564
+ return card->priv->pa_context;
4568
+gvc_mixer_card_get_index (GvcMixerCard *card)
4570
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
4571
+ return card->priv->index;
4575
+gvc_mixer_card_get_id (GvcMixerCard *card)
4577
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
4578
+ return card->priv->id;
4582
+gvc_mixer_card_get_name (GvcMixerCard *card)
4584
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
4585
+ return card->priv->name;
4589
+gvc_mixer_card_set_name (GvcMixerCard *card,
4592
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
4594
+ g_free (card->priv->name);
4595
+ card->priv->name = g_strdup (name);
4596
+ g_object_notify (G_OBJECT (card), "name");
4602
+gvc_mixer_card_get_icon_name (GvcMixerCard *card)
4604
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
4605
+ return card->priv->icon_name;
4609
+gvc_mixer_card_set_icon_name (GvcMixerCard *card,
4610
+ const char *icon_name)
4612
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
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");
4622
+ * gvc_mixer_card_get_profile: (skip)
4628
+GvcMixerCardProfile *
4629
+gvc_mixer_card_get_profile (GvcMixerCard *card)
4633
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
4634
+ g_return_val_if_fail (card->priv->profiles != NULL, NULL);
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)) {
4643
+ g_assert_not_reached ();
4649
+gvc_mixer_card_set_profile (GvcMixerCard *card,
4650
+ const char *profile)
4654
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
4655
+ g_return_val_if_fail (card->priv->profiles != NULL, FALSE);
4657
+ g_free (card->priv->profile);
4658
+ card->priv->profile = g_strdup (profile);
4660
+ g_free (card->priv->human_profile);
4661
+ card->priv->human_profile = NULL;
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);
4671
+ g_object_notify (G_OBJECT (card), "profile");
4677
+_pa_context_set_card_profile_by_index_cb (pa_context *context,
4681
+ GvcMixerCard *card = GVC_MIXER_CARD (userdata);
4683
+ g_assert (card->priv->target_profile);
4685
+ if (success > 0) {
4686
+ gvc_mixer_card_set_profile (card, card->priv->target_profile);
4688
+ g_debug ("Failed to switch profile on '%s' from '%s' to '%s'",
4690
+ card->priv->profile,
4691
+ card->priv->target_profile);
4693
+ g_free (card->priv->target_profile);
4694
+ card->priv->target_profile = NULL;
4696
+ pa_operation_unref (card->priv->profile_op);
4697
+ card->priv->profile_op = NULL;
4701
+gvc_mixer_card_change_profile (GvcMixerCard *card,
4702
+ const char *profile)
4704
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
4705
+ g_return_val_if_fail (card->priv->profiles != NULL, FALSE);
4707
+ /* Same profile, or already requested? */
4708
+ if (g_strcmp0 (card->priv->profile, profile) == 0)
4710
+ if (g_strcmp0 (profile, card->priv->target_profile) == 0)
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;
4718
+ if (card->priv->profile != NULL) {
4719
+ g_free (card->priv->target_profile);
4720
+ card->priv->target_profile = g_strdup (profile);
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,
4728
+ if (card->priv->profile_op == NULL) {
4729
+ g_warning ("pa_context_set_card_profile_by_index() failed");
4733
+ g_assert (card->priv->human_profile == NULL);
4734
+ card->priv->profile = g_strdup (profile);
4741
+ * gvc_mixer_card_get_profiles:
4743
+ * Return value: (transfer none) (element-type GvcMixerCardProfile):
4746
+gvc_mixer_card_get_profiles (GvcMixerCard *card)
4748
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
4749
+ return card->priv->profiles;
4754
+ * gvc_mixer_card_get_ports:
4756
+ * Return value: (transfer none) (element-type GvcMixerCardPort):
4759
+gvc_mixer_card_get_ports (GvcMixerCard *card)
4761
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
4762
+ return card->priv->ports;
4766
+ * gvc_mixer_card_set_profiles:
4767
+ * @profiles: (transfer full) (element-type GvcMixerCardProfile):
4770
+gvc_mixer_card_set_profiles (GvcMixerCard *card,
4773
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
4774
+ g_return_val_if_fail (card->priv->profiles == NULL, FALSE);
4776
+ card->priv->profiles = g_list_sort (profiles, (GCompareFunc) sort_profiles);
4782
+ * gvc_mixer_card_get_gicon:
4784
+ * Return value: (transfer full) (element-type GIcon):
4787
+gvc_mixer_card_get_gicon (GvcMixerCard *card)
4789
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
4790
+ if (card->priv->icon_name == NULL)
4792
+ return g_themed_icon_new_with_default_fallbacks (card->priv->icon_name);
4796
+ * gvc_mixer_card_set_ports:
4797
+ * @profiles: (transfer full) (element-type GvcMixerCardPort):
4800
+gvc_mixer_card_set_ports (GvcMixerCard *card,
4803
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
4804
+ g_return_val_if_fail (card->priv->ports == NULL, FALSE);
4806
+ card->priv->ports = ports;
4812
+gvc_mixer_card_set_property (GObject *object,
4814
+ const GValue *value,
4815
+ GParamSpec *pspec)
4817
+ GvcMixerCard *self = GVC_MIXER_CARD (object);
4819
+ switch (prop_id) {
4820
+ case PROP_PA_CONTEXT:
4821
+ self->priv->pa_context = g_value_get_pointer (value);
4824
+ self->priv->index = g_value_get_ulong (value);
4827
+ self->priv->id = g_value_get_ulong (value);
4830
+ gvc_mixer_card_set_name (self, g_value_get_string (value));
4832
+ case PROP_ICON_NAME:
4833
+ gvc_mixer_card_set_icon_name (self, g_value_get_string (value));
4835
+ case PROP_PROFILE:
4836
+ gvc_mixer_card_set_profile (self, g_value_get_string (value));
4839
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4845
+gvc_mixer_card_get_property (GObject *object,
4848
+ GParamSpec *pspec)
4850
+ GvcMixerCard *self = GVC_MIXER_CARD (object);
4852
+ switch (prop_id) {
4853
+ case PROP_PA_CONTEXT:
4854
+ g_value_set_pointer (value, self->priv->pa_context);
4857
+ g_value_set_ulong (value, self->priv->index);
4860
+ g_value_set_ulong (value, self->priv->id);
4863
+ g_value_set_string (value, self->priv->name);
4865
+ case PROP_ICON_NAME:
4866
+ g_value_set_string (value, self->priv->icon_name);
4868
+ case PROP_PROFILE:
4869
+ g_value_set_string (value, self->priv->profile);
4871
+ case PROP_HUMAN_PROFILE:
4872
+ g_value_set_string (value, self->priv->human_profile);
4875
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4881
+gvc_mixer_card_constructor (GType type,
4882
+ guint n_construct_properties,
4883
+ GObjectConstructParam *construct_params)
4886
+ GvcMixerCard *self;
4888
+ object = G_OBJECT_CLASS (gvc_mixer_card_parent_class)->constructor (type, n_construct_properties, construct_params);
4890
+ self = GVC_MIXER_CARD (object);
4892
+ self->priv->id = get_next_card_serial ();
4898
+gvc_mixer_card_class_init (GvcMixerCardClass *klass)
4900
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
4902
+ gobject_class->constructor = gvc_mixer_card_constructor;
4903
+ gobject_class->finalize = gvc_mixer_card_finalize;
4905
+ gobject_class->set_property = gvc_mixer_card_set_property;
4906
+ gobject_class->get_property = gvc_mixer_card_get_property;
4908
+ g_object_class_install_property (gobject_class,
4910
+ g_param_spec_ulong ("index",
4912
+ "The index for this card",
4914
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
4915
+ g_object_class_install_property (gobject_class,
4917
+ g_param_spec_ulong ("id",
4919
+ "The id for this card",
4921
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
4922
+ g_object_class_install_property (gobject_class,
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,
4930
+ g_param_spec_string ("name",
4932
+ "Name to display for this card",
4934
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
4935
+ g_object_class_install_property (gobject_class,
4937
+ g_param_spec_string ("icon-name",
4939
+ "Name of icon to display for this card",
4941
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
4942
+ g_object_class_install_property (gobject_class,
4944
+ g_param_spec_string ("profile",
4946
+ "Name of current profile for this card",
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",
4955
+ G_PARAM_READABLE));
4957
+ g_type_class_add_private (klass, sizeof (GvcMixerCardPrivate));
4961
+gvc_mixer_card_init (GvcMixerCard *card)
4963
+ card->priv = GVC_MIXER_CARD_GET_PRIVATE (card);
4968
+gvc_mixer_card_new (pa_context *context,
4973
+ object = g_object_new (GVC_TYPE_MIXER_CARD,
4975
+ "pa-context", context,
4977
+ return GVC_MIXER_CARD (object);
4981
+free_profile (GvcMixerCardProfile *p)
4983
+ g_free (p->profile);
4984
+ g_free (p->human_profile);
4985
+ g_free (p->status);
4990
+gvc_mixer_card_finalize (GObject *object)
4992
+ GvcMixerCard *mixer_card;
4994
+ g_return_if_fail (object != NULL);
4995
+ g_return_if_fail (GVC_IS_MIXER_CARD (object));
4997
+ mixer_card = GVC_MIXER_CARD (object);
4999
+ g_return_if_fail (mixer_card->priv != NULL);
5001
+ g_free (mixer_card->priv->name);
5002
+ mixer_card->priv->name = NULL;
5004
+ g_free (mixer_card->priv->icon_name);
5005
+ mixer_card->priv->icon_name = NULL;
5007
+ g_free (mixer_card->priv->target_profile);
5008
+ mixer_card->priv->target_profile = NULL;
5010
+ g_free (mixer_card->priv->profile);
5011
+ mixer_card->priv->profile = NULL;
5013
+ g_free (mixer_card->priv->human_profile);
5014
+ mixer_card->priv->human_profile = NULL;
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;
5020
+ G_OBJECT_CLASS (gvc_mixer_card_parent_class)->finalize (object);
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
5028
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
5030
+ * Copyright (C) 2008-2009 Red Hat, Inc.
5031
+ * Copyright (C) Conor Curran 2011 <conor.curran@canonical.com>
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.
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.
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.
5049
+#ifndef __GVC_MIXER_CARD_H
5050
+#define __GVC_MIXER_CARD_H
5052
+#include <glib-object.h>
5053
+#include <gio/gio.h>
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))
5064
+typedef struct GvcMixerCardPrivate GvcMixerCardPrivate;
5069
+ GvcMixerCardPrivate *priv;
5074
+ GObjectClass parent_class;
5077
+} GvcMixerCardClass;
5082
+ char *human_profile;
5085
+ guint n_sinks, n_sources;
5086
+} GvcMixerCardProfile;
5096
+} GvcMixerCardPort;
5098
+GType gvc_mixer_card_get_type (void);
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);
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,
5120
+gboolean gvc_mixer_card_set_ports (GvcMixerCard *stream,
5124
+sort_profiles (GvcMixerCardProfile *a,
5125
+ GvcMixerCardProfile *b)
5127
+ if (a->priority == b->priority)
5129
+ if (a->priority > b->priority)
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
5142
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
5144
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
5162
+#ifndef __GVC_MIXER_CONTROL_PRIVATE_H
5163
+#define __GVC_MIXER_CONTROL_PRIVATE_H
5165
+#include <glib-object.h>
5166
+#include <pulse/pulseaudio.h>
5167
+#include "gvc-mixer-stream.h"
5168
+#include "gvc-mixer-card.h"
5172
+pa_context * gvc_mixer_control_get_pa_context (GvcMixerControl *control);
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
5182
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
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
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.
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.
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.
5204
+#include "config.h"
5206
+#include <stdlib.h>
5208
+#include <unistd.h>
5211
+#include <glib/gi18n-lib.h>
5213
+#include <pulse/pulseaudio.h>
5214
+#include <pulse/glib-mainloop.h>
5215
+#include <pulse/ext-stream-restore.h>
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"
5228
+#define GVC_MIXER_CONTROL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControlPrivate))
5230
+#define RECONNECT_DELAY 5
5237
+struct GvcMixerControlPrivate
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;
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;
5254
+ gboolean event_sink_input_is_set;
5255
+ guint event_sink_input_id;
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 */
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.
5275
+ guint profile_swapping_device_id;
5276
+ GvcMixerControlState state;
5285
+ DEFAULT_SINK_CHANGED,
5286
+ DEFAULT_SOURCE_CHANGED,
5288
+ ACTIVE_OUTPUT_UPDATE,
5289
+ ACTIVE_INPUT_UPDATE,
5296
+static guint signals [LAST_SIGNAL] = { 0, };
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);
5302
+G_DEFINE_TYPE (GvcMixerControl, gvc_mixer_control, G_TYPE_OBJECT)
5305
+gvc_mixer_control_get_pa_context (GvcMixerControl *control)
5307
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5308
+ return control->priv->pa_context;
5312
+ * gvc_mixer_control_get_event_sink_input:
5316
+ * Returns: (transfer none):
5319
+gvc_mixer_control_get_event_sink_input (GvcMixerControl *control)
5321
+ GvcMixerStream *stream;
5323
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5325
+ stream = g_hash_table_lookup (control->priv->all_streams,
5326
+ GUINT_TO_POINTER (control->priv->event_sink_input_id));
5332
+gvc_mixer_control_stream_restore_cb (pa_context *c,
5333
+ const pa_ext_stream_restore_info *info,
5339
+ GvcMixerControl *control = (GvcMixerControl *) userdata;
5340
+ pa_ext_stream_restore_info new_info;
5342
+ if (eol || control->priv->new_default_stream == NULL)
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))
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;
5355
+ new_info.device = gvc_mixer_stream_get_name (control->priv->new_default_stream);
5357
+ o = pa_ext_stream_restore_write (control->priv->pa_context,
5358
+ PA_UPDATE_REPLACE,
5360
+ TRUE, NULL, NULL);
5363
+ g_warning ("pa_ext_stream_restore_write() failed: %s",
5364
+ pa_strerror (pa_context_errno (control->priv->pa_context)));
5368
+ g_debug ("Changed default device for %s to %s", info->name, new_info.device);
5370
+ pa_operation_unref (o);
5374
+ * gvc_mixer_control_lookup_device_from_stream:
5377
+ * Returns: GvcUIDevice (transfer none) or NULL:
5379
+static GvcMixerUIDevice *
5380
+gvc_mixer_control_lookup_device_from_stream (GvcMixerControl *control,
5381
+ GvcMixerStream *stream)
5385
+ GvcMixerUIDevice *device;
5387
+ if (GVC_IS_MIXER_SOURCE (stream))
5388
+ devices = g_hash_table_get_values (control->priv->ui_inputs);
5390
+ devices = g_hash_table_get_values (control->priv->ui_outputs);
5393
+ gboolean is_network_stream;
5394
+ const GList *ports;
5395
+ ports = gvc_mixer_stream_get_ports (stream);
5397
+ // really this should be called 'is_network_or_bluetooth_stream'
5398
+ is_network_stream = ports == NULL;
5400
+ for (d = devices; d != NULL; d = d->next) {
5402
+ gint stream_id = -2;
5404
+ g_object_get (G_OBJECT (device),
5405
+ "stream-id", &stream_id,
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));
5416
+ const GvcMixerStreamPort *port;
5417
+ port = gvc_mixer_stream_get_port (stream);
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),
5427
+ gvc_mixer_stream_get_id (stream),
5428
+ gvc_mixer_stream_get_description (stream));
5433
+ g_debug ("\n gvc_mixer_control_lookup_device_from_stream - Could not find a device ? %s \n",gvc_mixer_stream_get_description (stream));
5438
+gvc_mixer_control_set_default_sink (GvcMixerControl *control,
5439
+ GvcMixerStream *stream)
5443
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE);
5444
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
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),
5452
+ g_warning ("pa_context_set_default_sink() failed: %s",
5453
+ pa_strerror (pa_context_errno (control->priv->pa_context)));
5457
+ pa_operation_unref (o);
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);
5463
+ o = pa_ext_stream_restore_read (control->priv->pa_context,
5464
+ gvc_mixer_control_stream_restore_cb,
5468
+ g_warning ("pa_ext_stream_restore_read() failed: %s",
5469
+ pa_strerror (pa_context_errno (control->priv->pa_context)));
5473
+ pa_operation_unref (o);
5479
+gvc_mixer_control_set_default_source (GvcMixerControl *control,
5480
+ GvcMixerStream *stream)
5484
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE);
5485
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
5487
+ o = pa_context_set_default_source (control->priv->pa_context,
5488
+ gvc_mixer_stream_get_name (stream),
5492
+ g_warning ("pa_context_set_default_source() failed");
5496
+ pa_operation_unref (o);
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);
5502
+ o = pa_ext_stream_restore_read (control->priv->pa_context,
5503
+ gvc_mixer_control_stream_restore_cb,
5507
+ g_warning ("pa_ext_stream_restore_read() failed: %s",
5508
+ pa_strerror (pa_context_errno (control->priv->pa_context)));
5512
+ pa_operation_unref (o);
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],
5520
+ gvc_mixer_ui_device_get_id (input));
5526
+ * gvc_mixer_control_get_default_sink:
5530
+ * Returns: (transfer none):
5533
+gvc_mixer_control_get_default_sink (GvcMixerControl *control)
5535
+ GvcMixerStream *stream;
5537
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
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));
5550
+ * gvc_mixer_control_get_default_source:
5554
+ * Returns: (transfer none):
5557
+gvc_mixer_control_get_default_source (GvcMixerControl *control)
5559
+ GvcMixerStream *stream;
5561
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
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));
5574
+gvc_mixer_control_lookup_id (GHashTable *hash_table,
5577
+ return g_hash_table_lookup (hash_table,
5578
+ GUINT_TO_POINTER (id));
5582
+ * gvc_mixer_control_lookup_stream_id:
5587
+ * Returns: (transfer none):
5590
+gvc_mixer_control_lookup_stream_id (GvcMixerControl *control,
5593
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5595
+ return gvc_mixer_control_lookup_id (control->priv->all_streams, id);
5599
+ * gvc_mixer_control_lookup_card_id:
5604
+ * Returns: (transfer none):
5607
+gvc_mixer_control_lookup_card_id (GvcMixerControl *control,
5610
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5611
+ return gvc_mixer_control_lookup_id (control->priv->cards, id);
5615
+ * gvc_mixer_control_lookup_output_id:
5618
+ * Returns: (transfer none):
5621
+gvc_mixer_control_lookup_output_id (GvcMixerControl *control,
5624
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5626
+ return gvc_mixer_control_lookup_id (control->priv->ui_outputs, id);
5630
+ * gvc_mixer_control_lookup_input_id:
5633
+ * Returns: (transfer none):
5636
+gvc_mixer_control_lookup_input_id (GvcMixerControl *control,
5639
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5641
+ return gvc_mixer_control_lookup_id (control->priv->ui_inputs, id);
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.
5653
+gvc_mixer_control_get_active_profile_from_ui_device (GvcMixerControl* control,
5654
+ GvcMixerUIDevice* device)
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");
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);
5670
+ * gvc_mixer_control_get_stream_from_device:
5673
+ * Returns: (transfer container) (element-type Gvc.MixerStream):
5676
+gvc_mixer_control_get_stream_from_device (GvcMixerControl *control,
5677
+ GvcMixerUIDevice *dev)
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);
5682
+ gint stream_id = gvc_mixer_ui_device_get_stream_id (dev);
5684
+ if (stream_id == GVC_MIXER_UI_DEVICE_INVALID) {
5685
+ g_debug ("gvc_mixer_control_get_stream_from_device - device has a null stream");
5688
+ return gvc_mixer_control_lookup_stream_id (control, stream_id);
5691
+ * gvc_mixer_control_change_profile_on_selected_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.
5701
+gvc_mixer_control_change_profile_on_selected_device (GvcMixerControl *control,
5702
+ GvcMixerUIDevice *device,
5703
+ const gchar* profile)
5706
+ const gchar *best_profile;
5707
+ GvcMixerCardProfile *current_profile;
5708
+ g_object_get ( G_OBJECT(device), "card-id", &card_id, NULL);
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 ?");
5714
+ GvcMixerCard *card;
5715
+ card = gvc_mixer_control_lookup_card_id (control, card_id);
5716
+ current_profile = gvc_mixer_card_get_profile (card);
5718
+ if (current_profile)
5719
+ best_profile = gvc_mixer_ui_device_get_best_profile (device, profile, current_profile->profile);
5721
+ best_profile = profile;
5723
+ g_assert(best_profile);
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));
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);
5734
+ control->priv->profile_swapping_device_id = gvc_mixer_ui_device_get_id (device);
5736
+ if (gvc_mixer_card_change_profile (card, best_profile)) {
5737
+ gvc_mixer_ui_device_set_user_preferred_profile (device, best_profile);
5744
+ * gvc_mixer_control_change_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.
5761
+gvc_mixer_control_change_output (GvcMixerControl *control,
5762
+ GvcMixerUIDevice* output)
5764
+ g_debug ("\n control change output \n");
5765
+ GvcMixerStream *stream;
5766
+ GvcMixerStream *default_stream;
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,
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],
5783
+ gvc_mixer_ui_device_get_id (output));
5786
+ g_warning ("Failed to set default sink with stream from output %s \n",
5787
+ gvc_mixer_ui_device_get_description (output));
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",
5798
+ if (gvc_mixer_stream_change_port (stream, output_port) == FALSE){
5799
+ g_warning ("\n Could not change port ! \n");
5804
+ default_stream = gvc_mixer_control_get_default_sink (control);
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],
5816
+ gvc_mixer_ui_device_get_id (output));
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],
5824
+ gvc_mixer_ui_device_get_id (output));
5832
+ * gvc_mixer_control_change_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.
5849
+gvc_mixer_control_change_input (GvcMixerControl *control,
5850
+ GvcMixerUIDevice* input)
5852
+ GvcMixerStream *stream;
5853
+ GvcMixerStream *default_stream;
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,
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));
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",
5878
+ if (gvc_mixer_stream_change_port (stream, input_port) == FALSE){
5879
+ g_warning ("\n Could not change port ! \n");
5884
+ default_stream = gvc_mixer_control_get_default_source (control);
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);
5896
+listify_hash_values_hfunc (gpointer key,
5898
+ gpointer user_data)
5900
+ GSList **list = user_data;
5902
+ *list = g_slist_prepend (*list, value);
5906
+gvc_name_collate (const char *namea,
5907
+ const char *nameb)
5909
+ if (nameb == NULL && namea == NULL)
5911
+ if (nameb == NULL)
5913
+ if (namea == NULL)
5916
+ return g_utf8_collate (namea, nameb);
5920
+gvc_card_collate (GvcMixerCard *a,
5923
+ const char *namea;
5924
+ const char *nameb;
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);
5929
+ namea = gvc_mixer_card_get_name (a);
5930
+ nameb = gvc_mixer_card_get_name (b);
5932
+ return gvc_name_collate (namea, nameb);
5936
+ * gvc_mixer_control_get_cards:
5940
+ * Returns: (transfer container) (element-type Gvc.MixerCard):
5943
+gvc_mixer_control_get_cards (GvcMixerControl *control)
5947
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5950
+ g_hash_table_foreach (control->priv->cards,
5951
+ listify_hash_values_hfunc,
5953
+ return g_slist_sort (retval, (GCompareFunc) gvc_card_collate);
5957
+gvc_stream_collate (GvcMixerStream *a,
5958
+ GvcMixerStream *b)
5960
+ const char *namea;
5961
+ const char *nameb;
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);
5966
+ namea = gvc_mixer_stream_get_name (a);
5967
+ nameb = gvc_mixer_stream_get_name (b);
5969
+ return gvc_name_collate (namea, nameb);
5973
+ * gvc_mixer_control_get_streams:
5977
+ * Returns: (transfer container) (element-type Gvc.MixerStream):
5980
+gvc_mixer_control_get_streams (GvcMixerControl *control)
5984
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
5987
+ g_hash_table_foreach (control->priv->all_streams,
5988
+ listify_hash_values_hfunc,
5990
+ return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate);
5995
+ * gvc_mixer_control_get_sinks:
5999
+ * Returns: (transfer container) (element-type Gvc.MixerSink):
6002
+gvc_mixer_control_get_sinks (GvcMixerControl *control)
6006
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
6009
+ g_hash_table_foreach (control->priv->sinks,
6010
+ listify_hash_values_hfunc,
6012
+ return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate);
6016
+ * gvc_mixer_control_get_sources:
6020
+ * Returns: (transfer container) (element-type Gvc.MixerSource):
6023
+gvc_mixer_control_get_sources (GvcMixerControl *control)
6027
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
6030
+ g_hash_table_foreach (control->priv->sources,
6031
+ listify_hash_values_hfunc,
6033
+ return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate);
6037
+ * gvc_mixer_control_get_sink_inputs:
6041
+ * Returns: (transfer container) (element-type Gvc.MixerSinkInput):
6044
+gvc_mixer_control_get_sink_inputs (GvcMixerControl *control)
6048
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
6051
+ g_hash_table_foreach (control->priv->sink_inputs,
6052
+ listify_hash_values_hfunc,
6054
+ return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate);
6058
+ * gvc_mixer_control_get_source_outputs:
6062
+ * Returns: (transfer container) (element-type Gvc.MixerSourceOutput):
6065
+gvc_mixer_control_get_source_outputs (GvcMixerControl *control)
6069
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
6072
+ g_hash_table_foreach (control->priv->source_outputs,
6073
+ listify_hash_values_hfunc,
6075
+ return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate);
6079
+dec_outstanding (GvcMixerControl *control)
6081
+ if (control->priv->n_outstanding <= 0) {
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);
6091
+GvcMixerControlState
6092
+gvc_mixer_control_get_state (GvcMixerControl *control)
6094
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE);
6096
+ return control->priv->state;
6100
+on_default_source_port_notify (GObject *object,
6101
+ GParamSpec *pspec,
6102
+ GvcMixerControl *control)
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));
6110
+ g_debug ("\n\n on_default_source_port_notify - moved to port %s \n which SHOULD ?? correspond to output \n %s \n",
6112
+ gvc_mixer_ui_device_get_description (input));
6114
+ g_signal_emit (G_OBJECT (control),
6115
+ signals[ACTIVE_INPUT_UPDATE],
6117
+ gvc_mixer_ui_device_get_id (input));
6124
+_set_default_source (GvcMixerControl *control,
6125
+ GvcMixerStream *stream)
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],
6135
+ PA_INVALID_INDEX);
6139
+ new_id = gvc_mixer_stream_get_id (stream);
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],
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,
6155
+ g_signal_connect (stream,
6157
+ G_CALLBACK (on_default_source_port_notify),
6160
+ GvcMixerUIDevice* input;
6161
+ input = gvc_mixer_control_lookup_device_from_stream (control, stream);
6163
+ g_signal_emit (G_OBJECT (control),
6164
+ signals[ACTIVE_INPUT_UPDATE],
6166
+ gvc_mixer_ui_device_get_id (input));
6172
+on_default_sink_port_notify (GObject *object,
6173
+ GParamSpec *pspec,
6174
+ GvcMixerControl *control)
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",
6184
+ gvc_mixer_ui_device_get_description (output));
6185
+ g_signal_emit (G_OBJECT (control),
6186
+ signals[ACTIVE_OUTPUT_UPDATE],
6188
+ gvc_mixer_ui_device_get_id (output));
6195
+_set_default_sink (GvcMixerControl *control,
6196
+ GvcMixerStream *stream)
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)
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],
6210
+ PA_INVALID_INDEX);
6214
+ new_id = gvc_mixer_stream_get_id (stream);
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,
6223
+ control->priv->default_sink_id = new_id;
6225
+ control->priv->default_sink_is_set = TRUE;
6226
+ g_signal_emit (control,
6227
+ signals[DEFAULT_SINK_CHANGED],
6231
+ g_signal_connect (stream,
6233
+ G_CALLBACK (on_default_sink_port_notify),
6236
+ GvcMixerUIDevice* output;
6237
+ output = gvc_mixer_control_lookup_device_from_stream (control, stream);
6239
+ g_debug ("active_sink change \n");
6241
+ g_signal_emit (G_OBJECT (control),
6242
+ signals[ACTIVE_OUTPUT_UPDATE],
6244
+ gvc_mixer_ui_device_get_id (output));
6249
+_stream_has_name (gpointer key,
6250
+ GvcMixerStream *stream,
6253
+ const char *t_name;
6255
+ t_name = gvc_mixer_stream_get_name (stream);
6257
+ if (t_name != NULL
6259
+ && strcmp (t_name, name) == 0) {
6266
+static GvcMixerStream *
6267
+find_stream_for_name (GvcMixerControl *control,
6270
+ GvcMixerStream *stream;
6272
+ stream = g_hash_table_find (control->priv->all_streams,
6273
+ (GHRFunc)_stream_has_name,
6279
+update_default_source_from_name (GvcMixerControl *control,
6282
+ gboolean changed = FALSE;
6284
+ if ((control->priv->default_source_name == NULL
6286
+ || (control->priv->default_source_name != NULL
6288
+ || (name != NULL && strcmp (control->priv->default_source_name, name) != 0)) {
6293
+ GvcMixerStream *stream;
6295
+ g_free (control->priv->default_source_name);
6296
+ control->priv->default_source_name = g_strdup (name);
6298
+ stream = find_stream_for_name (control, name);
6299
+ _set_default_source (control, stream);
6304
+update_default_sink_from_name (GvcMixerControl *control,
6307
+ gboolean changed = FALSE;
6309
+ if ((control->priv->default_sink_name == NULL
6311
+ || (control->priv->default_sink_name != NULL
6313
+ || (name != NULL && strcmp (control->priv->default_sink_name, name) != 0)) {
6318
+ GvcMixerStream *stream;
6319
+ g_free (control->priv->default_sink_name);
6320
+ control->priv->default_sink_name = g_strdup (name);
6322
+ stream = find_stream_for_name (control, name);
6323
+ _set_default_sink (control, stream);
6328
+update_server (GvcMixerControl *control,
6329
+ const pa_server_info *info)
6331
+ if (info->default_source_name != NULL) {
6332
+ update_default_source_from_name (control, info->default_source_name);
6334
+ if (info->default_sink_name != NULL) {
6335
+ g_debug ("\n update server");
6336
+ update_default_sink_from_name (control, info->default_sink_name);
6341
+remove_stream (GvcMixerControl *control,
6342
+ GvcMixerStream *stream)
6346
+ g_object_ref (stream);
6348
+ id = gvc_mixer_stream_get_id (stream);
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);
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],
6361
+ gvc_mixer_stream_get_id (stream));
6362
+ g_object_unref (stream);
6366
+add_stream (GvcMixerControl *control,
6367
+ GvcMixerStream *stream)
6369
+ g_hash_table_insert (control->priv->all_streams,
6370
+ GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)),
6372
+ g_signal_emit (G_OBJECT (control),
6373
+ signals[STREAM_ADDED],
6375
+ gvc_mixer_stream_get_id (stream));
6379
+This method will match individual stream ports against it's corresponding device
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.
6386
+match_stream_with_devices (GvcMixerControl *control,
6387
+ GvcMixerStreamPort* stream_port,
6388
+ GvcMixerStream* stream)
6392
+ GvcMixerUIDevice *device;
6393
+ guint stream_card_id;
6396
+ stream_id = gvc_mixer_stream_get_id (stream);
6397
+ stream_card_id = gvc_mixer_stream_get_card_index (stream);
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;
6402
+ for (d = devices; d != NULL; d = d->next) {
6405
+ gint device_stream_id;
6406
+ gchar *device_port_name;
6408
+ gchar *description;
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,
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 ",
6424
+ stream_port->port,
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 ",
6432
+ gvc_mixer_ui_device_get_id (device),
6435
+ g_object_set (G_OBJECT (device),
6436
+ "stream-id", (gint)stream_id,
6438
+ in_possession = TRUE;
6441
+ g_free (device_port_name);
6443
+ g_free (description);
6445
+ if (in_possession == TRUE)
6448
+ return in_possession;
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 !
6465
+sync_devices (GvcMixerControl *control,
6466
+ GvcMixerStream* stream)
6468
+ // Go through ports to see what outputs can be created.
6469
+ const GList *stream_ports = NULL;
6470
+ const GList *n = NULL;
6472
+ gboolean is_output = !GVC_IS_MIXER_SOURCE (stream);
6473
+ stream_ports = gvc_mixer_stream_get_ports (stream);
6474
+ gint stream_port_count = 0;
6476
+ if (g_list_length (stream_ports) == 0){
6477
+ GvcMixerUIDevice* device;
6479
+ // => no ports && a valid card
6480
+ if (gvc_mixer_stream_get_card_index (stream) != PA_INVALID_INDEX) {
6483
+ devices = g_hash_table_get_values ( is_output ? control->priv->ui_outputs : control->priv->ui_inputs);
6485
+ gboolean in_possession = FALSE;
6487
+ for (d = devices; d != NULL; d = d->next) {
6491
+ g_object_get (G_OBJECT (device),
6492
+ "card-id", &card_id,
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;
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));
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,
6516
+ // Network sink/source => no ports && no card.
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,
6527
+ device = GVC_MIXER_UI_DEVICE (object);
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));
6534
+ g_signal_emit (G_OBJECT (control),
6535
+ signals[is_output ? OUTPUT_ADDED : INPUT_ADDED],
6537
+ gvc_mixer_ui_device_get_id (device));
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) {
6545
+ GvcMixerStreamPort *stream_port;
6546
+ stream_port = n->data;
6547
+ stream_port_count ++;
6549
+ if ( TRUE == match_stream_with_devices (control,
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));
6562
+set_icon_name_from_proplist (GvcMixerStream *stream,
6564
+ const char *default_icon_name)
6568
+ if ((t = pa_proplist_gets (l, PA_PROP_DEVICE_ICON_NAME))) {
6572
+ if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ICON_NAME))) {
6576
+ if ((t = pa_proplist_gets (l, PA_PROP_WINDOW_ICON_NAME))) {
6580
+ if ((t = pa_proplist_gets (l, PA_PROP_APPLICATION_ICON_NAME))) {
6584
+ if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ROLE))) {
6586
+ if (strcmp (t, "video") == 0 ||
6587
+ strcmp (t, "phone") == 0) {
6591
+ if (strcmp (t, "music") == 0) {
6596
+ if (strcmp (t, "game") == 0) {
6597
+ t = "applications-games";
6601
+ if (strcmp (t, "event") == 0) {
6602
+ t = "dialog-information";
6607
+ t = default_icon_name;
6610
+ gvc_mixer_stream_set_icon_name (stream, t);
6614
+* Called when anything changes with a sink.
6617
+update_sink (GvcMixerControl *control,
6618
+ const pa_sink_info *info)
6620
+ GvcMixerStream *stream;
6622
+ pa_volume_t max_volume;
6623
+ GvcChannelMap *map;
6624
+ char map_buff[PA_CHANNEL_MAP_SNPRINT_MAX];
6626
+ pa_channel_map_snprint (map_buff, PA_CHANNEL_MAP_SNPRINT_MAX, &info->channel_map);
6628
+ g_debug ("Updating sink: index=%u name='%s' description='%s' map='%s'",
6631
+ info->description,
6637
+ stream = g_hash_table_lookup (control->priv->sinks,
6638
+ GUINT_TO_POINTER (info->index));
6640
+ if (stream == NULL) {
6641
+ GList *list = NULL;
6644
+ map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map);
6645
+ stream = gvc_mixer_sink_new (control->priv->pa_context,
6649
+ for (i = 0; i < info->n_ports; i++) {
6650
+ GvcMixerStreamPort *port;
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;
6659
+ list = g_list_prepend (list, port);
6661
+ gvc_mixer_stream_set_ports (stream, list);
6663
+ g_object_unref (map);
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");
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);
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){
6687
+ gvc_mixer_stream_set_port (stream, info->active_port->name);
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);
6701
+ g_debug ("\n update sink - is new \n");
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);
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.
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);
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);
6729
+ control->priv->profile_swapping_device_id = GVC_MIXER_UI_DEVICE_INVALID;
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);
6739
+ map = (GvcChannelMap *) gvc_mixer_stream_get_channel_map (stream);
6741
+ gvc_channel_map_volume_changed (map, &info->volume, FALSE);
6745
+update_source (GvcMixerControl *control,
6746
+ const pa_source_info *info)
6748
+ GvcMixerStream *stream;
6750
+ gboolean port_change;
6751
+ pa_volume_t max_volume;
6754
+ g_debug ("Updating source: index=%u name='%s' description='%s'",
6757
+ info->description);
6760
+ /* completely ignore monitors, they're not real sources */
6761
+ if (info->monitor_of_sink != PA_INVALID_INDEX) {
6766
+ stream = g_hash_table_lookup (control->priv->sources,
6767
+ GUINT_TO_POINTER (info->index));
6768
+ if (stream == NULL) {
6769
+ GList *list = NULL;
6771
+ GvcChannelMap *map;
6773
+ map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map);
6774
+ stream = gvc_mixer_source_new (control->priv->pa_context,
6778
+ for (i = 0; i < info->n_ports; i++) {
6779
+ GvcMixerStreamPort *port;
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);
6787
+ gvc_mixer_stream_set_ports (stream, list);
6789
+ g_object_unref (map);
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");
6797
+ max_volume = pa_cvolume_max (&info->volume);
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");
6809
+ if (info->active_port != NULL){
6811
+ gvc_mixer_stream_set_port (stream, info->active_port->name);
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);
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);
6832
+ if (control->priv->profile_swapping_device_id != GVC_MIXER_UI_DEVICE_INVALID){
6833
+ GvcMixerUIDevice *dev = NULL;
6835
+ dev = gvc_mixer_control_lookup_input_id (control, control->priv->profile_swapping_device_id);
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);
6844
+ control->priv->profile_swapping_device_id = GVC_MIXER_UI_DEVICE_INVALID;
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);
6854
+set_is_event_stream_from_proplist (GvcMixerStream *stream,
6858
+ gboolean is_event_stream;
6860
+ is_event_stream = FALSE;
6862
+ if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ROLE))) {
6863
+ if (g_str_equal (t, "event"))
6864
+ is_event_stream = TRUE;
6867
+ gvc_mixer_stream_set_is_event_stream (stream, is_event_stream);
6871
+set_application_id_from_proplist (GvcMixerStream *stream,
6876
+ if ((t = pa_proplist_gets (l, PA_PROP_APPLICATION_ID))) {
6877
+ gvc_mixer_stream_set_application_id (stream, t);
6882
+update_sink_input (GvcMixerControl *control,
6883
+ const pa_sink_input_info *info)
6885
+ GvcMixerStream *stream;
6887
+ pa_volume_t max_volume;
6891
+ g_debug ("Updating sink input: index=%u name='%s' client=%u sink=%u",
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,
6908
+ g_object_unref (map);
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");
6916
+ max_volume = pa_cvolume_max (&info->volume);
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);
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);
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);
6939
+update_source_output (GvcMixerControl *control,
6940
+ const pa_source_output_info *info)
6942
+ GvcMixerStream *stream;
6947
+ g_debug ("Updating source output: index=%u name='%s' client=%u source=%u",
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,
6963
+ g_object_unref (map);
6967
+ name = (const char *)g_hash_table_lookup (control->priv->clients,
6968
+ GUINT_TO_POINTER (info->client));
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");
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);
6985
+update_client (GvcMixerControl *control,
6986
+ const pa_client_info *info)
6989
+ g_debug ("Updating client: index=%u name='%s'",
6993
+ g_hash_table_insert (control->priv->clients,
6994
+ GUINT_TO_POINTER (info->index),
6995
+ g_strdup (info->name));
6999
+card_num_streams_to_status (guint sinks,
7003
+ char *sources_str;
7006
+ if (sinks == 0 && sources == 0) {
7008
+ * The device has been disabled */
7009
+ return g_strdup (_("Disabled"));
7015
+ * The number of sound outputs on a particular device */
7016
+ sinks_str = g_strdup_printf (ngettext ("%u Output",
7021
+ if (sources == 0) {
7022
+ sources_str = NULL;
7025
+ * The number of sound inputs on a particular device */
7026
+ sources_str = g_strdup_printf (ngettext ("%u Input",
7031
+ if (sources_str == NULL)
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);
7041
+* A utility method to gather which card profiles are relevant to the port .
7044
+determine_profiles_for_port (pa_card_port_info *port,
7045
+ GList* card_profiles)
7048
+ GList *supported_profiles = NULL;
7050
+ for (i = 0; i < port->n_profiles; i++) {
7051
+ for ( p = card_profiles; p != NULL; p = p->next) {
7052
+ GvcMixerCardProfile *prof;
7054
+ if (g_strcmp0 (port->profiles[i]->name, prof->profile) == 0) {
7055
+ supported_profiles = g_list_append (supported_profiles, prof);
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);
7066
+is_card_port_an_output (GvcMixerCardPort* port)
7068
+ return port->direction == PA_DIRECTION_OUTPUT ? TRUE : FALSE;
7072
+* This method will create a ui device for the given port.
7075
+create_ui_device_from_port (GvcMixerControl* control,
7076
+ GvcMixerCardPort* port,
7077
+ GvcMixerCard* card)
7079
+ UiDeviceDirection direction;
7081
+ direction = (is_card_port_an_output(port) == TRUE) ? UiDeviceOutput : UiDeviceInput;
7083
+ gboolean available = port->available == 0 || port->available == 2;
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,
7094
+ GvcMixerUIDevice* uidevice = GVC_MIXER_UI_DEVICE (object);
7095
+ gvc_mixer_ui_device_set_profiles (uidevice, port->profiles);
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));
7103
+ g_signal_emit (G_OBJECT (control),
7104
+ signals[is_card_port_an_output (port) ? OUTPUT_ADDED : INPUT_ADDED],
7106
+ gvc_mixer_ui_device_get_id (uidevice));
7109
+ g_debug ("\n create_ui_device_from_port, direction %u \n description %s \n origin %s \n port available %i \n \n",
7112
+ gvc_mixer_card_get_name (card),
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.
7123
+match_card_port_with_existing_device (GvcMixerControl *control,
7124
+ GvcMixerCardPort* card_port,
7125
+ GvcMixerCard* card,
7126
+ gboolean available)
7130
+ GvcMixerUIDevice *device;
7131
+ gboolean in_possession = FALSE;
7132
+ gboolean is_output = is_card_port_an_output (card_port);
7134
+ devices = g_hash_table_get_values (is_output ? control->priv->ui_outputs : control->priv->ui_inputs);
7136
+ for (d = devices; d != NULL; d = d->next) {
7139
+ gchar *device_port_name;
7141
+ g_object_get (G_OBJECT (device),
7142
+ "card-id", &card_id,
7143
+ "port-name", &device_port_name,
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",
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],
7157
+ gvc_mixer_ui_device_get_id (device));
7159
+ g_free (device_port_name);
7163
+At this point we can determine all devices available to us (besides network 'ports')
7164
+This is done by the following:
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.
7173
+update_card (GvcMixerControl *control,
7174
+ const pa_card_info *info)
7176
+ GvcMixerCard *card;
7177
+ gboolean is_new = FALSE;
7183
+ for (i = 0; i < info->n_profiles; i++) {
7184
+ struct pa_card_profile_info pi = info->profiles[i];
7185
+ gboolean is_default;
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)" : "");
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);
7200
+ card = g_hash_table_lookup (control->priv->cards,
7201
+ GUINT_TO_POINTER (info->index));
7202
+ if (card == NULL) {
7203
+ GList *profile_list = NULL;
7205
+ for (i = 0; i < info->n_profiles; i++) {
7206
+ struct pa_card_profile_info pi = info->profiles[i];
7207
+ GvcMixerCardProfile *profile;
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);
7218
+ card = gvc_mixer_card_new (control->priv->pa_context,
7220
+ gvc_mixer_card_set_profiles (card, profile_list);
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);
7234
+ gvc_mixer_card_set_ports (card, port_list);
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);
7243
+ g_hash_table_insert (control->priv->cards,
7244
+ GUINT_TO_POINTER (info->index),
7245
+ g_object_ref (card));
7248
+ const GList *card_ports = NULL;
7249
+ const GList *m = NULL;
7251
+ card_ports = gvc_mixer_card_get_ports (card);
7254
+ port_count = g_list_length (card_ports);
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);
7264
+ g_debug ("\n Portless card just registered - %i \n", gvc_mixer_card_get_index (card));
7267
+ object = g_object_new (GVC_TYPE_MIXER_UI_DEVICE,
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),
7275
+ GvcMixerUIDevice* in = GVC_MIXER_UI_DEVICE (object);
7276
+ gvc_mixer_ui_device_set_profiles (in, profiles);
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,
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),
7289
+ GvcMixerUIDevice* out = GVC_MIXER_UI_DEVICE (object);
7290
+ gvc_mixer_ui_device_set_profiles (out, profiles);
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));
7297
+ for (m = card_ports; m != NULL; m = m->next) {
7298
+ GvcMixerCardPort *card_port;
7299
+ card_port = m->data;
7301
+ create_ui_device_from_port (control, card_port, card);
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),
7311
+ card_port->available);
7312
+ match_card_port_with_existing_device (control,
7315
+ card_port->available == 0 ||
7316
+ card_port->available == 2);
7322
+ g_signal_emit (G_OBJECT (control),
7323
+ signals[CARD_ADDED],
7331
+_pa_context_get_sink_info_cb (pa_context *context,
7332
+ const pa_sink_info *i,
7336
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7339
+ if (pa_context_errno (context) == PA_ERR_NOENTITY) {
7343
+ g_warning ("Sink callback failure");
7348
+ dec_outstanding (control);
7352
+ update_sink (control, i);
7356
+_pa_context_get_source_info_cb (pa_context *context,
7357
+ const pa_source_info *i,
7361
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7364
+ if (pa_context_errno (context) == PA_ERR_NOENTITY) {
7368
+ g_warning ("Source callback failure");
7373
+ dec_outstanding (control);
7377
+ update_source (control, i);
7381
+_pa_context_get_sink_input_info_cb (pa_context *context,
7382
+ const pa_sink_input_info *i,
7386
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7389
+ if (pa_context_errno (context) == PA_ERR_NOENTITY) {
7393
+ g_warning ("Sink input callback failure");
7398
+ dec_outstanding (control);
7402
+ update_sink_input (control, i);
7406
+_pa_context_get_source_output_info_cb (pa_context *context,
7407
+ const pa_source_output_info *i,
7411
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7414
+ if (pa_context_errno (context) == PA_ERR_NOENTITY) {
7418
+ g_warning ("Source output callback failure");
7423
+ dec_outstanding (control);
7427
+ update_source_output (control, i);
7431
+_pa_context_get_client_info_cb (pa_context *context,
7432
+ const pa_client_info *i,
7436
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7439
+ if (pa_context_errno (context) == PA_ERR_NOENTITY) {
7443
+ g_warning ("Client callback failure");
7448
+ dec_outstanding (control);
7452
+ update_client (control, i);
7456
+_pa_context_get_card_info_by_index_cb (pa_context *context,
7457
+ const pa_card_info *i,
7461
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7464
+ if (pa_context_errno (context) == PA_ERR_NOENTITY)
7467
+ g_warning ("Card callback failure");
7472
+ dec_outstanding (control);
7476
+ update_card (control, i);
7480
+_pa_context_get_server_info_cb (pa_context *context,
7481
+ const pa_server_info *i,
7484
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7487
+ g_warning ("Server info callback failure");
7490
+ g_debug ("\n get server info \n");
7491
+ update_server (control, i);
7492
+ dec_outstanding (control);
7496
+remove_event_role_stream (GvcMixerControl *control)
7498
+ g_debug ("Removing event role");
7502
+update_event_role_stream (GvcMixerControl *control,
7503
+ const pa_ext_stream_restore_info *info)
7505
+ GvcMixerStream *stream;
7507
+ pa_volume_t max_volume;
7509
+ if (strcmp (info->name, "sink-input-by-media-role:event") != 0) {
7514
+ g_debug ("Updating event role: name='%s' device='%s'",
7521
+ if (!control->priv->event_sink_input_is_set) {
7522
+ pa_channel_map pa_map;
7523
+ GvcChannelMap *map;
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);
7529
+ stream = gvc_mixer_event_role_new (control->priv->pa_context,
7532
+ control->priv->event_sink_input_id = gvc_mixer_stream_get_id (stream);
7533
+ control->priv->event_sink_input_is_set = TRUE;
7537
+ stream = g_hash_table_lookup (control->priv->all_streams,
7538
+ GUINT_TO_POINTER (control->priv->event_sink_input_id));
7541
+ max_volume = pa_cvolume_max (&info->volume);
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);
7549
+ add_stream (control, stream);
7554
+_pa_ext_stream_restore_read_cb (pa_context *context,
7555
+ const pa_ext_stream_restore_info *i,
7559
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7562
+ g_debug ("Failed to initialized stream_restore extension: %s",
7563
+ pa_strerror (pa_context_errno (context)));
7564
+ remove_event_role_stream (control);
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;
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);
7584
+ update_event_role_stream (control, i);
7588
+_pa_ext_stream_restore_subscribe_cb (pa_context *context,
7591
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
7594
+ o = pa_ext_stream_restore_read (context,
7595
+ _pa_ext_stream_restore_read_cb,
7598
+ g_warning ("pa_ext_stream_restore_read() failed");
7602
+ pa_operation_unref (o);
7606
+req_update_server_info (GvcMixerControl *control,
7611
+ o = pa_context_get_server_info (control->priv->pa_context,
7612
+ _pa_context_get_server_info_cb,
7615
+ g_warning ("pa_context_get_server_info() failed");
7618
+ pa_operation_unref (o);
7622
+req_update_client_info (GvcMixerControl *control,
7628
+ o = pa_context_get_client_info_list (control->priv->pa_context,
7629
+ _pa_context_get_client_info_cb,
7632
+ o = pa_context_get_client_info (control->priv->pa_context,
7634
+ _pa_context_get_client_info_cb,
7639
+ g_warning ("pa_context_client_info_list() failed");
7642
+ pa_operation_unref (o);
7646
+req_update_card (GvcMixerControl *control,
7652
+ o = pa_context_get_card_info_list (control->priv->pa_context,
7653
+ _pa_context_get_card_info_by_index_cb,
7656
+ o = pa_context_get_card_info_by_index (control->priv->pa_context,
7658
+ _pa_context_get_card_info_by_index_cb,
7663
+ g_warning ("pa_context_get_card_info_by_index() failed");
7666
+ pa_operation_unref (o);
7670
+req_update_sink_info (GvcMixerControl *control,
7676
+ o = pa_context_get_sink_info_list (control->priv->pa_context,
7677
+ _pa_context_get_sink_info_cb,
7680
+ o = pa_context_get_sink_info_by_index (control->priv->pa_context,
7682
+ _pa_context_get_sink_info_cb,
7687
+ g_warning ("pa_context_get_sink_info_list() failed");
7690
+ pa_operation_unref (o);
7694
+req_update_source_info (GvcMixerControl *control,
7700
+ o = pa_context_get_source_info_list (control->priv->pa_context,
7701
+ _pa_context_get_source_info_cb,
7704
+ o = pa_context_get_source_info_by_index(control->priv->pa_context,
7706
+ _pa_context_get_source_info_cb,
7711
+ g_warning ("pa_context_get_source_info_list() failed");
7714
+ pa_operation_unref (o);
7718
+req_update_sink_input_info (GvcMixerControl *control,
7724
+ o = pa_context_get_sink_input_info_list (control->priv->pa_context,
7725
+ _pa_context_get_sink_input_info_cb,
7728
+ o = pa_context_get_sink_input_info (control->priv->pa_context,
7730
+ _pa_context_get_sink_input_info_cb,
7735
+ g_warning ("pa_context_get_sink_input_info_list() failed");
7738
+ pa_operation_unref (o);
7742
+req_update_source_output_info (GvcMixerControl *control,
7748
+ o = pa_context_get_source_output_info_list (control->priv->pa_context,
7749
+ _pa_context_get_source_output_info_cb,
7752
+ o = pa_context_get_source_output_info (control->priv->pa_context,
7754
+ _pa_context_get_source_output_info_cb,
7759
+ g_warning ("pa_context_get_source_output_info_list() failed");
7762
+ pa_operation_unref (o);
7766
+remove_client (GvcMixerControl *control,
7769
+ g_hash_table_remove (control->priv->clients,
7770
+ GUINT_TO_POINTER (index));
7774
+remove_card (GvcMixerControl *control,
7779
+ devices = g_list_concat (g_hash_table_get_values (control->priv->ui_inputs),
7780
+ g_hash_table_get_values (control->priv->ui_outputs));
7783
+ GvcMixerUIDevice *device;
7785
+ for (d = devices; d != NULL; d = d->next) {
7786
+ gint card_id = GVC_MIXER_UI_DEVICE_INVALID;
7788
+ g_object_get (G_OBJECT (device),
7789
+ "card-id", &card_id,
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],
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)));
7803
+ g_hash_table_remove (control->priv->cards,
7804
+ GUINT_TO_POINTER (index));
7806
+ g_signal_emit (G_OBJECT (control),
7807
+ signals[CARD_REMOVED],
7813
+remove_sink (GvcMixerControl *control,
7816
+ GvcMixerStream *stream;
7819
+ g_debug ("Removing sink: index=%u", index);
7822
+ stream = g_hash_table_lookup (control->priv->sinks,
7823
+ GUINT_TO_POINTER (index));
7824
+ if (stream == NULL) {
7828
+ GvcMixerUIDevice *device;
7829
+ device = gvc_mixer_control_lookup_device_from_stream (control, stream);
7831
+ if (device != NULL){
7832
+ g_debug ("\n invalidate stream on device - remove-sinks - %s \n", gvc_mixer_ui_device_get_description (device));
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],
7840
+ gvc_mixer_ui_device_get_id (device));
7842
+ // otherwise check to make sure to invalidate other devices which may have that stream
7847
+ devices = g_hash_table_get_values (control->priv->ui_outputs);
7849
+ for (d = devices; d != NULL; d = d->next) {
7850
+ gint stream_id = GVC_MIXER_UI_DEVICE_INVALID;
7852
+ g_object_get (G_OBJECT (device),
7853
+ "stream-id", &stream_id,
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);
7863
+ g_hash_table_remove (control->priv->sinks,
7864
+ GUINT_TO_POINTER (index));
7865
+ remove_stream (control, stream);
7869
+remove_source (GvcMixerControl *control,
7872
+ GvcMixerStream *stream;
7875
+ g_debug ("Removing source: index=%u", index);
7878
+ stream = g_hash_table_lookup (control->priv->sources,
7879
+ GUINT_TO_POINTER (index));
7880
+ if (stream == NULL) {
7884
+ GvcMixerUIDevice *device;
7885
+ device = gvc_mixer_control_lookup_device_from_stream (control, stream);
7887
+ if (device != NULL){
7888
+ g_debug ("\n invalidate stream on device - %s \n", gvc_mixer_ui_device_get_description (device));
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],
7896
+ gvc_mixer_ui_device_get_id (device));
7898
+ // otherwise check to make sure to invalidate other devices which may have that stream
7904
+ devices = g_hash_table_get_values (control->priv->ui_inputs);
7906
+ for (d = devices; d != NULL; d = d->next) {
7907
+ gint stream_id = GVC_MIXER_UI_DEVICE_INVALID;
7909
+ g_object_get (G_OBJECT (device),
7910
+ "stream-id", &stream_id,
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);
7921
+ g_hash_table_remove (control->priv->sources,
7922
+ GUINT_TO_POINTER (index));
7924
+ remove_stream (control, stream);
7928
+remove_sink_input (GvcMixerControl *control,
7931
+ GvcMixerStream *stream;
7934
+ g_debug ("Removing sink input: index=%u", index);
7936
+ stream = g_hash_table_lookup (control->priv->sink_inputs,
7937
+ GUINT_TO_POINTER (index));
7938
+ if (stream == NULL) {
7941
+ g_hash_table_remove (control->priv->sink_inputs,
7942
+ GUINT_TO_POINTER (index));
7944
+ remove_stream (control, stream);
7948
+remove_source_output (GvcMixerControl *control,
7951
+ GvcMixerStream *stream;
7954
+ g_debug ("Removing source output: index=%u", index);
7957
+ stream = g_hash_table_lookup (control->priv->source_outputs,
7958
+ GUINT_TO_POINTER (index));
7959
+ if (stream == NULL) {
7962
+ g_hash_table_remove (control->priv->source_outputs,
7963
+ GUINT_TO_POINTER (index));
7965
+ remove_stream (control, stream);
7969
+_pa_context_subscribe_cb (pa_context *context,
7970
+ pa_subscription_event_type_t t,
7974
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
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);
7981
+ req_update_sink_info (control, index);
7985
+ case PA_SUBSCRIPTION_EVENT_SOURCE:
7986
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
7987
+ remove_source (control, index);
7989
+ req_update_source_info (control, index);
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);
7997
+ req_update_sink_input_info (control, index);
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);
8005
+ req_update_source_output_info (control, index);
8009
+ case PA_SUBSCRIPTION_EVENT_CLIENT:
8010
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
8011
+ remove_client (control, index);
8013
+ req_update_client_info (control, index);
8017
+ case PA_SUBSCRIPTION_EVENT_SERVER:
8018
+ req_update_server_info (control, index);
8021
+ case PA_SUBSCRIPTION_EVENT_CARD:
8022
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
8023
+ remove_card (control, index);
8025
+ req_update_card (control, index);
8032
+gvc_mixer_control_ready (GvcMixerControl *control)
8036
+ pa_context_set_subscribe_callback (control->priv->pa_context,
8037
+ _pa_context_subscribe_cb,
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),
8052
+ g_warning ("pa_context_subscribe() failed");
8055
+ pa_operation_unref (o);
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);
8065
+ control->priv->n_outstanding = 6;
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,
8072
+ pa_operation_unref (o);
8073
+ control->priv->n_outstanding++;
8075
+ pa_ext_stream_restore_set_subscribe_cb (control->priv->pa_context,
8076
+ _pa_ext_stream_restore_subscribe_cb,
8079
+ o = pa_ext_stream_restore_subscribe (control->priv->pa_context,
8084
+ pa_operation_unref (o);
8088
+ g_debug ("Failed to initialized stream_restore extension: %s",
8089
+ pa_strerror (pa_context_errno (control->priv->pa_context)));
8094
+gvc_mixer_new_pa_context (GvcMixerControl *self)
8096
+ pa_proplist *proplist;
8098
+ g_return_if_fail (self);
8099
+ g_return_if_fail (!self->priv->pa_context);
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,
8115
+ self->priv->pa_context = pa_context_new_with_proplist (self->priv->pa_api, NULL, proplist);
8117
+ pa_proplist_free (proplist);
8118
+ g_assert (self->priv->pa_context);
8122
+remove_all_streams (GvcMixerControl *control, GHashTable *hash_table)
8124
+ GHashTableIter iter;
8125
+ gpointer key, value;
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);
8135
+idle_reconnect (gpointer data)
8137
+ GvcMixerControl *control = GVC_MIXER_CONTROL (data);
8138
+ GHashTableIter iter;
8139
+ gpointer key, value;
8141
+ g_return_val_if_fail (control, FALSE);
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);
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);
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);
8158
+ gvc_mixer_control_open (control); /* cannot fail */
8160
+ control->priv->reconnect_id = 0;
8165
+_pa_context_state_cb (pa_context *context,
8168
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
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:
8177
+ case PA_CONTEXT_READY:
8178
+ gvc_mixer_control_ready (control);
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);
8188
+ case PA_CONTEXT_TERMINATED:
8196
+gvc_mixer_control_open (GvcMixerControl *control)
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);
8204
+ pa_context_set_state_callback (control->priv->pa_context,
8205
+ _pa_context_state_cb,
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);
8212
+ g_warning ("Failed to connect context: %s",
8213
+ pa_strerror (pa_context_errno (control->priv->pa_context)));
8220
+gvc_mixer_control_close (GvcMixerControl *control)
8222
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE);
8223
+ g_return_val_if_fail (control->priv->pa_context != NULL, FALSE);
8225
+ pa_context_disconnect (control->priv->pa_context);
8227
+ control->priv->state = GVC_STATE_CLOSED;
8228
+ g_signal_emit (G_OBJECT (control), signals[STATE_CHANGED], 0, GVC_STATE_CLOSED);
8233
+gvc_mixer_control_dispose (GObject *object)
8235
+ GvcMixerControl *control = GVC_MIXER_CONTROL (object);
8237
+ if (control->priv->reconnect_id != 0) {
8238
+ g_source_remove (control->priv->reconnect_id);
8239
+ control->priv->reconnect_id = 0;
8242
+ if (control->priv->pa_context != NULL) {
8243
+ pa_context_unref (control->priv->pa_context);
8244
+ control->priv->pa_context = NULL;
8247
+ if (control->priv->default_source_name != NULL) {
8248
+ g_free (control->priv->default_source_name);
8249
+ control->priv->default_source_name = NULL;
8251
+ if (control->priv->default_sink_name != NULL) {
8252
+ g_free (control->priv->default_sink_name);
8253
+ control->priv->default_sink_name = NULL;
8256
+ if (control->priv->pa_mainloop != NULL) {
8257
+ pa_glib_mainloop_free (control->priv->pa_mainloop);
8258
+ control->priv->pa_mainloop = NULL;
8261
+ if (control->priv->all_streams != NULL) {
8262
+ g_hash_table_destroy (control->priv->all_streams);
8263
+ control->priv->all_streams = NULL;
8266
+ if (control->priv->sinks != NULL) {
8267
+ g_hash_table_destroy (control->priv->sinks);
8268
+ control->priv->sinks = NULL;
8270
+ if (control->priv->sources != NULL) {
8271
+ g_hash_table_destroy (control->priv->sources);
8272
+ control->priv->sources = NULL;
8274
+ if (control->priv->sink_inputs != NULL) {
8275
+ g_hash_table_destroy (control->priv->sink_inputs);
8276
+ control->priv->sink_inputs = NULL;
8278
+ if (control->priv->source_outputs != NULL) {
8279
+ g_hash_table_destroy (control->priv->source_outputs);
8280
+ control->priv->source_outputs = NULL;
8282
+ if (control->priv->clients != NULL) {
8283
+ g_hash_table_destroy (control->priv->clients);
8284
+ control->priv->clients = NULL;
8286
+ if (control->priv->cards != NULL) {
8287
+ g_hash_table_destroy (control->priv->cards);
8288
+ control->priv->cards = NULL;
8290
+ if (control->priv->ui_outputs != NULL) {
8291
+ g_hash_table_destroy (control->priv->ui_outputs);
8292
+ control->priv->ui_outputs = NULL;
8294
+ if (control->priv->ui_inputs != NULL) {
8295
+ g_hash_table_destroy (control->priv->ui_inputs);
8296
+ control->priv->ui_inputs = NULL;
8300
+ G_OBJECT_CLASS (gvc_mixer_control_parent_class)->dispose (object);
8304
+gvc_mixer_control_set_property (GObject *object,
8306
+ const GValue *value,
8307
+ GParamSpec *pspec)
8309
+ GvcMixerControl *self = GVC_MIXER_CONTROL (object);
8311
+ switch (prop_id) {
8313
+ g_free (self->priv->name);
8314
+ self->priv->name = g_value_dup_string (value);
8315
+ g_object_notify (G_OBJECT (self), "name");
8318
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
8324
+gvc_mixer_control_get_property (GObject *object,
8327
+ GParamSpec *pspec)
8329
+ GvcMixerControl *self = GVC_MIXER_CONTROL (object);
8331
+ switch (prop_id) {
8333
+ g_value_set_string (value, self->priv->name);
8336
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
8343
+gvc_mixer_control_constructor (GType type,
8344
+ guint n_construct_properties,
8345
+ GObjectConstructParam *construct_params)
8348
+ GvcMixerControl *self;
8350
+ object = G_OBJECT_CLASS (gvc_mixer_control_parent_class)->constructor (type, n_construct_properties, construct_params);
8352
+ self = GVC_MIXER_CONTROL (object);
8354
+ gvc_mixer_new_pa_context (self);
8355
+ self->priv->profile_swapping_device_id = GVC_MIXER_UI_DEVICE_INVALID;
8361
+gvc_mixer_control_class_init (GvcMixerControlClass *klass)
8363
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
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;
8371
+ g_object_class_install_property (object_class,
8373
+ g_param_spec_string ("name",
8375
+ "Name to display for this mixer control",
8377
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
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),
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),
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),
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),
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),
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),
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),
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),
8441
+ g_cclosure_marshal_VOID__UINT,
8442
+ G_TYPE_NONE, 1, G_TYPE_UINT);
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),
8450
+ g_cclosure_marshal_VOID__UINT,
8451
+ G_TYPE_NONE, 1, G_TYPE_UINT);
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),
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),
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),
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),
8483
+ g_cclosure_marshal_VOID__UINT,
8484
+ G_TYPE_NONE, 1, G_TYPE_UINT);
8485
+ g_type_class_add_private (klass, sizeof (GvcMixerControlPrivate));
8490
+gvc_mixer_control_init (GvcMixerControl *control)
8492
+ control->priv = GVC_MIXER_CONTROL_GET_PRIVATE (control);
8494
+ control->priv->pa_mainloop = pa_glib_mainloop_new (g_main_context_default ());
8495
+ g_assert (control->priv->pa_mainloop);
8497
+ control->priv->pa_api = pa_glib_mainloop_get_api (control->priv->pa_mainloop);
8498
+ g_assert (control->priv->pa_api);
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);
8509
+ control->priv->clients = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_free);
8511
+ control->priv->state = GVC_STATE_CLOSED;
8515
+gvc_mixer_control_finalize (GObject *object)
8517
+ GvcMixerControl *mixer_control;
8519
+ g_return_if_fail (object != NULL);
8520
+ g_return_if_fail (GVC_IS_MIXER_CONTROL (object));
8522
+ mixer_control = GVC_MIXER_CONTROL (object);
8523
+ g_free (mixer_control->priv->name);
8524
+ mixer_control->priv->name = NULL;
8526
+ g_return_if_fail (mixer_control->priv != NULL);
8527
+ G_OBJECT_CLASS (gvc_mixer_control_parent_class)->finalize (object);
8531
+gvc_mixer_control_new (const char *name)
8534
+ control = g_object_new (GVC_TYPE_MIXER_CONTROL,
8537
+ return GVC_MIXER_CONTROL (control);
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)
8546
+gvc_mixer_control_get_vol_max_norm (GvcMixerControl *control)
8548
+ return (gdouble) PA_VOLUME_NORM;
8552
+gvc_mixer_control_get_vol_max_amplified (GvcMixerControl *control)
8554
+ return (gdouble) PA_VOLUME_UI_MAX;
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
8561
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
8563
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
8581
+#ifndef __GVC_MIXER_CONTROL_H
8582
+#define __GVC_MIXER_CONTROL_H
8584
+#include <glib-object.h>
8585
+#include "gvc-mixer-stream.h"
8586
+#include "gvc-mixer-card.h"
8587
+#include "gvc-mixer-ui-device.h"
8595
+ GVC_STATE_CONNECTING,
8597
+} GvcMixerControlState;
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))
8606
+typedef struct GvcMixerControlPrivate GvcMixerControlPrivate;
8611
+ GvcMixerControlPrivate *priv;
8616
+ GObjectClass parent_class;
8618
+ void (*state_changed) (GvcMixerControl *control,
8619
+ GvcMixerControlState new_state);
8620
+ void (*stream_added) (GvcMixerControl *control,
8622
+ void (*stream_removed) (GvcMixerControl *control,
8624
+ void (*card_added) (GvcMixerControl *control,
8626
+ void (*card_removed) (GvcMixerControl *control,
8628
+ void (*default_sink_changed) (GvcMixerControl *control,
8630
+ void (*default_source_changed) (GvcMixerControl *control,
8632
+ void (*output_added) (GvcMixerControl *control,
8634
+ void (*output_removed) (GvcMixerControl *control,
8636
+ void (*active_output_update) (GvcMixerControl *control,
8638
+ void (*active_input_update) (GvcMixerControl *control,
8640
+ void (*input_added) (GvcMixerControl *control,
8642
+ void (*input_removed) (GvcMixerControl *control,
8645
+} GvcMixerControlClass;
8647
+GType gvc_mixer_control_get_type (void);
8649
+GvcMixerControl * gvc_mixer_control_new (const char *name);
8651
+gboolean gvc_mixer_control_open (GvcMixerControl *control);
8652
+gboolean gvc_mixer_control_close (GvcMixerControl *control);
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);
8661
+GvcMixerStream * gvc_mixer_control_lookup_stream_id (GvcMixerControl *control,
8663
+GvcMixerCard * gvc_mixer_control_lookup_card_id (GvcMixerControl *control,
8665
+GvcMixerUIDevice * gvc_mixer_control_lookup_output_id (GvcMixerControl *control,
8667
+GvcMixerUIDevice * gvc_mixer_control_lookup_input_id (GvcMixerControl *control,
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);
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);
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);
8694
+GvcMixerControlState gvc_mixer_control_get_state (GvcMixerControl *control);
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
8705
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
8707
+ * Copyright (C) 2008 William Jon McCann
8708
+ * Copyright (C) 2012 Conor Curran
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.
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.
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.
8726
+#include "config.h"
8728
+#include <stdlib.h>
8730
+#include <unistd.h>
8734
+#include <glib/gi18n-lib.h>
8735
+#include <gdk/gdkkeysyms.h>
8736
+#include <gtk/gtk.h>
8737
+#include <pulse/pulseaudio.h>
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"
8755
+#define SCALE_SIZE 128
8757
+#define GVC_MIXER_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_DIALOG, GvcMixerDialogPrivate))
8759
+struct GvcMixerDialogPrivate
8761
+ GvcMixerControl *mixer_control;
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;
8796
+ gdouble last_input_peak;
8815
+ HW_PROFILE_COLUMN,
8816
+ HW_PROFILE_HUMAN_COLUMN,
8817
+ HW_SENSITIVE_COLUMN,
8824
+ PROP_MIXER_CONTROL
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);
8831
+static void bar_set_stream (GvcMixerDialog *dialog,
8833
+ GvcMixerStream *stream);
8835
+static void on_adjustment_value_changed (GtkAdjustment *adjustment,
8836
+ GvcMixerDialog *dialog);
8837
+static void on_control_output_added (GvcMixerControl *control,
8839
+ GvcMixerDialog *dialog);
8840
+static void on_control_active_output_update (GvcMixerControl *control,
8842
+ GvcMixerDialog *dialog);
8844
+static void on_control_active_input_update (GvcMixerControl *control,
8846
+ GvcMixerDialog *dialog);
8848
+G_DEFINE_TYPE (GvcMixerDialog, gvc_mixer_dialog, GTK_TYPE_VBOX)
8852
+update_description (GvcMixerDialog *dialog,
8854
+ const char *value,
8855
+ GvcMixerStream *stream)
8857
+ GtkTreeModel *model;
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));
8866
+ g_assert_not_reached ();
8868
+ if (gtk_tree_model_get_iter_first (model, &iter) == FALSE){
8869
+ g_warning ("The tree is empty => Cannot update the description");
8873
+ id = gvc_mixer_stream_get_id (stream);
8877
+ gtk_tree_model_get (model, &iter,
8878
+ ID_COLUMN, ¤t_id,
8880
+ if (id != current_id)
8883
+ gtk_list_store_set (GTK_LIST_STORE (model),
8888
+ } while (gtk_tree_model_iter_next (model, &iter));
8892
+profile_selection_changed (GvcComboBox *combo_box,
8893
+ const char *profile,
8894
+ GvcMixerDialog *dialog)
8896
+ g_debug ("profile_selection_changed - %s", profile);
8897
+ GvcMixerUIDevice *out;
8898
+ out = g_object_get_data (G_OBJECT (combo_box), "uidevice");
8900
+ if (out == NULL) {
8901
+ g_warning ("Could not find Output for profile combo box");
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));
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));
8916
+#define DECAY_STEP .15
8919
+update_input_peak (GvcMixerDialog *dialog,
8922
+ GtkAdjustment *adj;
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;
8930
+ dialog->priv->last_input_peak = v;
8932
+ adj = gvc_level_bar_get_peak_adjustment (GVC_LEVEL_BAR (dialog->priv->input_level_bar));
8934
+ gtk_adjustment_set_value (adj, v);
8936
+ gtk_adjustment_set_value (adj, 0.0);
8941
+update_input_meter (GvcMixerDialog *dialog,
8942
+ uint32_t source_index,
8943
+ uint32_t sink_input_idx,
8946
+ update_input_peak (dialog, v);
8950
+on_monitor_suspended_callback (pa_stream *s,
8953
+ GvcMixerDialog *dialog;
8955
+ dialog = userdata;
8957
+ if (pa_stream_is_suspended (s)) {
8958
+ g_debug ("Stream suspended");
8959
+ update_input_meter (dialog,
8960
+ pa_stream_get_device_index (s),
8967
+on_monitor_read_callback (pa_stream *s,
8971
+ GvcMixerDialog *dialog;
8975
+ dialog = userdata;
8977
+ if (pa_stream_peek (s, &data, &length) < 0) {
8978
+ g_warning ("Failed to read data from stream");
8982
+ assert (length > 0);
8983
+ assert (length % sizeof (float) == 0);
8985
+ v = ((const float *) data)[length / sizeof (float) -1];
8987
+ pa_stream_drop (s);
8996
+ update_input_meter (dialog,
8997
+ pa_stream_get_device_index (s),
8998
+ pa_stream_get_monitor_stream (s),
9003
+create_monitor_stream_for_source (GvcMixerDialog *dialog,
9004
+ GvcMixerStream *stream)
9008
+ pa_buffer_attr attr;
9009
+ pa_sample_spec ss;
9010
+ pa_context *context;
9012
+ pa_proplist *proplist;
9013
+ gboolean has_monitor;
9015
+ if (stream == NULL) {
9016
+ g_debug ("\n create_monitor_stream_for_source - stream is null - returning\n");
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");
9025
+ g_debug ("Create monitor for %u",
9026
+ gvc_mixer_stream_get_index (stream));
9028
+ context = gvc_mixer_control_get_pa_context (dialog->priv->mixer_control);
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");
9036
+ ss.format = PA_SAMPLE_FLOAT32;
9039
+ memset (&attr, 0, sizeof (attr));
9040
+ attr.fragsize = sizeof (float);
9041
+ attr.maxlength = (uint32_t) -1;
9043
+ snprintf (t, sizeof (t), "%u", gvc_mixer_stream_get_index (stream));
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);
9050
+ g_warning ("Failed to create monitoring stream");
9054
+ pa_stream_set_read_callback (s, on_monitor_read_callback, dialog);
9055
+ pa_stream_set_suspended_callback (s, on_monitor_suspended_callback, dialog);
9057
+ res = pa_stream_connect_record (s,
9060
+ (pa_stream_flags_t) (PA_STREAM_DONT_MOVE
9061
+ |PA_STREAM_PEAK_DETECT
9062
+ |PA_STREAM_ADJUST_LATENCY));
9064
+ g_warning ("Failed to connect monitoring stream");
9065
+ pa_stream_unref (s);
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);
9075
+stop_monitor_stream_for_source (GvcMixerDialog *dialog)
9078
+ pa_context *context;
9080
+ GvcMixerStream *stream;
9082
+ stream = g_object_get_data (G_OBJECT (dialog->priv->input_level_bar), "stream");
9084
+ if (stream == NULL){
9085
+ g_debug ("\n stop_monitor_stream_for_source - gvcstream is null - returning \n");
9089
+ g_debug ("\n stop_monitor_stream_for_source - gvcstream is not null - continue \n");
9092
+ s = g_object_get_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream");
9095
+ res = pa_stream_disconnect (s);
9097
+ g_debug("stream has been disconnected");
9098
+ pa_stream_unref (s);
9100
+ g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream", NULL);
9103
+ context = gvc_mixer_control_get_pa_context (dialog->priv->mixer_control);
9105
+ if (pa_context_get_server_protocol_version (context) < 13) {
9109
+ g_object_set_data (G_OBJECT (stream), "has-monitor", GINT_TO_POINTER (FALSE));
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);
9116
+gvc_mixer_dialog_set_mixer_control (GvcMixerDialog *dialog,
9117
+ GvcMixerControl *control)
9119
+ g_return_if_fail (GVC_MIXER_DIALOG (dialog));
9120
+ g_return_if_fail (GVC_IS_MIXER_CONTROL (control));
9122
+ g_object_ref (control);
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),
9128
+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
9129
+ G_CALLBACK (on_control_active_input_update),
9131
+ g_object_unref (dialog->priv->mixer_control);
9134
+ dialog->priv->mixer_control = control;
9136
+ g_signal_connect (dialog->priv->mixer_control,
9137
+ "active-output-update",
9138
+ G_CALLBACK (on_control_active_output_update),
9140
+ g_signal_connect (dialog->priv->mixer_control,
9141
+ "active-input-update",
9142
+ G_CALLBACK (on_control_active_input_update),
9145
+ g_object_notify (G_OBJECT (dialog), "mixer-control");
9148
+static GvcMixerControl *
9149
+gvc_mixer_dialog_get_mixer_control (GvcMixerDialog *dialog)
9151
+ g_return_val_if_fail (GVC_IS_MIXER_DIALOG (dialog), NULL);
9153
+ return dialog->priv->mixer_control;
9157
+gvc_mixer_dialog_set_property (GObject *object,
9159
+ const GValue *value,
9160
+ GParamSpec *pspec)
9162
+ GvcMixerDialog *self = GVC_MIXER_DIALOG (object);
9164
+ switch (prop_id) {
9165
+ case PROP_MIXER_CONTROL:
9166
+ gvc_mixer_dialog_set_mixer_control (self, g_value_get_object (value));
9169
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
9175
+gvc_mixer_dialog_get_property (GObject *object,
9178
+ GParamSpec *pspec)
9180
+ GvcMixerDialog *self = GVC_MIXER_DIALOG (object);
9182
+ switch (prop_id) {
9183
+ case PROP_MIXER_CONTROL:
9184
+ g_value_set_object (value, gvc_mixer_dialog_get_mixer_control (self));
9187
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
9193
+on_adjustment_value_changed (GtkAdjustment *adjustment,
9194
+ GvcMixerDialog *dialog)
9196
+ GvcMixerStream *stream;
9198
+ stream = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-stream");
9199
+ if (stream != NULL) {
9201
+ gdouble volume, rounded;
9204
+ volume = gtk_adjustment_get_value (adjustment);
9205
+ rounded = round (volume);
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);
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);
9223
+on_bar_is_muted_notify (GObject *object,
9224
+ GParamSpec *pspec,
9225
+ GvcMixerDialog *dialog)
9227
+ gboolean is_muted;
9228
+ GvcMixerStream *stream;
9230
+ is_muted = gvc_channel_bar_get_is_muted (GVC_CHANNEL_BAR (object));
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);
9237
+ g_object_get (object, "name", &name, NULL);
9238
+ g_warning ("Unable to find stream for bar '%s'", name);
9244
+lookup_bar_for_stream (GvcMixerDialog *dialog,
9245
+ GvcMixerStream *stream)
9249
+ bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)));
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.
9259
+on_stream_description_notify (GvcMixerStream *stream,
9260
+ GParamSpec *pspec,
9261
+ GvcMixerDialog *dialog)
9263
+ update_description (dialog, NAME_COLUMN,
9264
+ gvc_mixer_stream_get_description (stream),
9269
+on_stream_volume_notify (GObject *object,
9270
+ GParamSpec *pspec,
9271
+ GvcMixerDialog *dialog)
9273
+ GvcMixerStream *stream;
9275
+ GtkAdjustment *adj;
9276
+ stream = GVC_MIXER_STREAM (object);
9278
+ bar = lookup_bar_for_stream (dialog, stream);
9280
+ if (bar == NULL) {
9281
+ if (stream == gvc_mixer_control_get_default_sink(dialog->priv->mixer_control)) {
9282
+ bar = dialog->priv->output_bar;
9284
+ else if(stream == gvc_mixer_control_get_default_source(dialog->priv->mixer_control)) {
9285
+ bar = dialog->priv->input_bar;
9288
+ g_warning ("Unable to find bar for stream %s in on_stream_volume_notify()",
9289
+ gvc_mixer_stream_get_name (stream));
9294
+ adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
9296
+ g_signal_handlers_block_by_func (adj,
9297
+ on_adjustment_value_changed,
9300
+ gtk_adjustment_set_value (adj,
9301
+ gvc_mixer_stream_get_volume (stream));
9303
+ g_signal_handlers_unblock_by_func (adj,
9304
+ on_adjustment_value_changed,
9309
+on_stream_is_muted_notify (GObject *object,
9310
+ GParamSpec *pspec,
9311
+ GvcMixerDialog *dialog)
9313
+ GvcMixerStream *stream;
9315
+ gboolean is_muted;
9317
+ stream = GVC_MIXER_STREAM (object);
9319
+ bar = lookup_bar_for_stream (dialog, stream);
9321
+ if (bar == NULL) {
9322
+ if (stream == gvc_mixer_control_get_default_sink(dialog->priv->mixer_control)) {
9323
+ bar = dialog->priv->output_bar;
9325
+ else if(stream == gvc_mixer_control_get_default_source(dialog->priv->mixer_control)) {
9326
+ bar = dialog->priv->input_bar;
9329
+ g_warning ("Unable to find bar for stream %s in on_stream_muted_notify()",
9330
+ gvc_mixer_stream_get_name (stream));
9336
+ is_muted = gvc_mixer_stream_get_is_muted (stream);
9337
+ gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar),
9340
+ if (stream == gvc_mixer_control_get_default_sink (dialog->priv->mixer_control)) {
9341
+ gtk_widget_set_sensitive (dialog->priv->applications_box,
9348
+save_bar_for_stream (GvcMixerDialog *dialog,
9349
+ GvcMixerStream *stream,
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)),
9360
+create_bar (GvcMixerDialog *dialog,
9361
+ gboolean add_to_size_group,
9362
+ gboolean symmetric)
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,
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),
9377
+ g_signal_connect (bar,
9378
+ "notify::is-muted",
9379
+ G_CALLBACK (on_bar_is_muted_notify),
9385
+create_app_bar (GvcMixerDialog *dialog,
9387
+ const char *icon_name)
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);
9397
+ char **tokens, *escaped;
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);
9409
+static gint test_it = 0;
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.
9417
+active_input_update (GvcMixerDialog *dialog,
9418
+ GvcMixerUIDevice *active_input)
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;
9425
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
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");
9433
+ gboolean is_selected = FALSE;
9436
+ gtk_tree_model_get (model, &iter,
9440
+ is_selected = id == gvc_mixer_ui_device_get_id (active_input);
9442
+ gtk_list_store_set (GTK_LIST_STORE (model),
9444
+ ACTIVE_COLUMN, is_selected,
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);
9453
+ }while (gtk_tree_model_iter_next (model, &iter));
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;
9463
+ GvcMixerStream *stream;
9464
+ const GvcChannelMap *map;
9465
+ GtkAdjustment *adj;
9467
+ stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control,
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,
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);
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)));
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));
9494
+ stop_monitor_stream_for_source (dialog);
9495
+ //if (test_it < 6){
9496
+ create_monitor_stream_for_source (dialog, stream);
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.
9503
+ const GHashTable *profs_entries;
9504
+ profs_entries = gvc_mixer_ui_device_get_profiles (active_input);
9506
+ const GList* profiles = NULL;
9507
+ profiles = g_hash_table_get_values (profs_entries);
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),
9515
+ active_profile = gvc_mixer_control_get_active_profile_from_ui_device (dialog->priv->mixer_control,
9517
+ if (active_profile)
9518
+ gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->input_profile_combo), active_profile);
9520
+ g_object_set_data (G_OBJECT (dialog->priv->input_profile_combo),
9524
+ g_signal_connect (G_OBJECT (dialog->priv->input_profile_combo), "changed",
9525
+ G_CALLBACK (profile_selection_changed), dialog);
9527
+ gtk_box_pack_start (GTK_BOX (dialog->priv->input_settings_box),
9528
+ dialog->priv->input_profile_combo,
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);
9535
+ gtk_widget_show (dialog->priv->input_profile_combo);
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.
9545
+active_output_update (GvcMixerDialog *dialog,
9546
+ GvcMixerUIDevice *active_output)
9548
+ // First make sure the correct UI device is selected.
9549
+ GtkTreeModel *model;
9551
+ g_debug ("\n\n active output update - device id = %i \n\n",
9552
+ gvc_mixer_ui_device_get_id (active_output));
9554
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
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");
9562
+ gboolean is_selected;
9565
+ gtk_tree_model_get (model, &iter,
9567
+ ACTIVE_COLUMN, &is_selected,
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");
9574
+ is_selected = id == gvc_mixer_ui_device_get_id (active_output);
9576
+ gtk_list_store_set (GTK_LIST_STORE (model),
9578
+ ACTIVE_COLUMN, is_selected,
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);
9587
+ }while (gtk_tree_model_iter_next (model, &iter));
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;
9596
+ GvcMixerStream *stream;
9597
+ const GvcChannelMap *map;
9598
+ GtkAdjustment *adj;
9600
+ stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control,
9603
+ if (stream == NULL) {
9604
+ g_warning ("active_output_update - couldn't find a stream from the supposed active output");
9608
+ gboolean is_muted = gvc_mixer_stream_get_is_muted (stream);
9609
+ gtk_widget_set_sensitive (dialog->priv->applications_box,
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);
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));
9625
+ map = gvc_mixer_stream_get_channel_map (stream);
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);
9637
+ // Swap bars to the active map
9638
+ gvc_balance_bar_set_map (GVC_BALANCE_BAR (dialog->priv->output_balance_bar),
9640
+ gvc_balance_bar_set_map (GVC_BALANCE_BAR (dialog->priv->output_fade_bar),
9642
+ gvc_balance_bar_set_map (GVC_BALANCE_BAR (dialog->priv->output_lfe_bar),
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,
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));
9660
+ const GHashTable *profs_entries;
9661
+ profs_entries = gvc_mixer_ui_device_get_profiles (active_output);
9663
+ GList* profiles = NULL;
9664
+ profiles = g_hash_table_get_values (profs_entries);
9666
+ if (profiles != NULL && !gvc_mixer_ui_device_should_profiles_be_hidden (active_output)) {
9667
+ const gchar *active_profile;
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),
9673
+ gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box),
9674
+ dialog->priv->output_profile_combo,
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);
9682
+ active_profile = gvc_mixer_control_get_active_profile_from_ui_device (dialog->priv->mixer_control,
9684
+ if (active_profile)
9685
+ gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->output_profile_combo), active_profile);
9688
+ g_object_set_data (G_OBJECT (dialog->priv->output_profile_combo),
9691
+ g_signal_connect (G_OBJECT (dialog->priv->output_profile_combo), "changed",
9692
+ G_CALLBACK (profile_selection_changed), dialog);
9694
+ gtk_widget_show (dialog->priv->output_profile_combo);
9700
+bar_set_stream (GvcMixerDialog *dialog,
9702
+ GvcMixerStream *stream)
9704
+ GtkAdjustment *adj;
9706
+ g_assert (bar != NULL);
9708
+ gtk_widget_set_sensitive (bar, (stream != NULL));
9710
+ adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
9712
+ g_signal_handlers_disconnect_by_func (adj, on_adjustment_value_changed, dialog);
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);
9718
+ if (stream != NULL) {
9719
+ gboolean is_muted;
9721
+ is_muted = gvc_mixer_stream_get_is_muted (stream);
9722
+ gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar), is_muted);
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),
9730
+ g_signal_connect (stream,
9732
+ G_CALLBACK (on_stream_volume_notify),
9734
+ g_signal_connect (adj,
9736
+ G_CALLBACK (on_adjustment_value_changed),
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.
9747
+add_stream (GvcMixerDialog *dialog,
9748
+ GvcMixerStream *stream)
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");
9758
+ // Must be a sink/source input/output
9760
+ name = gvc_mixer_stream_get_name (stream);
9761
+ g_debug ("\n Add bar for application stream : %s",
9764
+ bar = create_app_bar (dialog, name,
9765
+ gvc_mixer_stream_get_icon_name (stream));
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);
9771
+ // We should have a bar by now.
9772
+ g_assert (bar != NULL);
9773
+ GvcMixerStream *old_stream;
9775
+ if (bar != NULL) {
9776
+ old_stream = g_object_get_data (G_OBJECT (bar), "gvc-mixer-dialog-stream");
9777
+ if (old_stream != NULL) {
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);
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)));
9789
+ save_bar_for_stream (dialog, stream, bar);
9790
+ bar_set_stream (dialog, bar, stream);
9791
+ gtk_widget_show (bar);
9796
+remove_stream (GvcMixerDialog *dialog,
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)),
9805
+ dialog->priv->num_apps--;
9806
+ if (dialog->priv->num_apps == 0) {
9807
+ gtk_widget_show (dialog->priv->no_apps_label);
9814
+on_control_stream_added (GvcMixerControl *control,
9816
+ GvcMixerDialog *dialog)
9818
+ GvcMixerStream *stream;
9819
+ stream = gvc_mixer_control_lookup_stream_id (control, id);
9821
+ if (stream == NULL)
9824
+ const char *app_id;
9825
+ app_id = gvc_mixer_stream_get_application_id (stream);
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)) {
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);
9840
+ add_stream (dialog, stream);
9845
+on_control_stream_removed (GvcMixerControl *control,
9847
+ GvcMixerDialog *dialog)
9849
+ remove_stream (dialog, id);
9853
+find_item_by_id (GtkTreeModel *model,
9856
+ GtkTreeIter *iter)
9858
+ gboolean found_item;
9860
+ found_item = FALSE;
9862
+ if (!gtk_tree_model_get_iter_first (model, iter)) {
9869
+ gtk_tree_model_get (model, iter,
9870
+ column, &t_id, -1);
9873
+ found_item = TRUE;
9875
+ } while (!found_item && gtk_tree_model_iter_next (model, iter));
9877
+ return found_item;
9881
+add_input_ui_entry (GvcMixerDialog *dialog,
9882
+ GvcMixerUIDevice *input)
9884
+ g_debug ("\n Add input ui entry with id : %u \n",
9885
+ gvc_mixer_ui_device_get_id (input));
9889
+ gchar *description;
9891
+ gboolean available;
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,
9903
+ GtkTreeModel *model;
9905
+ const GvcChannelMap *map;
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);
9916
+ g_free (description);
9919
+ icon = gvc_mixer_stream_get_gicon (stream);
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);
9927
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
9928
+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
9930
+ gtk_list_store_set (GTK_LIST_STORE (model),
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,
9941
+ g_object_unref (icon);
9943
+ // TODO check this.
9944
+ /*g_signal_connect (output,
9945
+ "notify::description",
9946
+ G_CALLBACK (on_output_description_notify),
9949
+ g_free (port_name);
9951
+ g_free (description);
9955
+add_output_ui_entry (GvcMixerDialog *dialog,
9956
+ GvcMixerUIDevice *output)
9958
+ g_debug ("\n Add output ui entry with id : %u \n",
9959
+ gvc_mixer_ui_device_get_id (output));
9961
+ gchar *sink_port_name;
9963
+ gchar *description;
9965
+ gboolean available;
9967
+ gint sink_stream_id;
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,
9978
+ GtkTreeModel *model;
9980
+ const GvcChannelMap *map;
9983
+ if (card_id == GVC_MIXER_UI_DEVICE_INVALID) {
9984
+ g_debug ("just detected a network sink");
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);
9992
+ g_free (description);
9995
+ icon = gvc_mixer_stream_get_gicon (stream);
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);
10003
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
10004
+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
10006
+ gtk_list_store_set (GTK_LIST_STORE (model),
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,
10016
+ if (icon != NULL)
10017
+ g_object_unref (icon);
10019
+ // TODO check this.
10020
+ /*g_signal_connect (output,
10021
+ "notify::description",
10022
+ G_CALLBACK (on_output_description_notify),
10025
+ g_free (sink_port_name);
10027
+ g_free (description);
10031
+on_control_output_added (GvcMixerControl *control,
10033
+ GvcMixerDialog *dialog)
10035
+ GvcMixerUIDevice* out = NULL;
10036
+ out = gvc_mixer_control_lookup_output_id (control, id);
10038
+ if (out == NULL) {
10039
+ g_warning ("on_control_output_added - tried to fetch an output of id %u but got nothing", id);
10043
+ add_output_ui_entry (dialog, out);
10047
+on_control_active_output_update (GvcMixerControl *control,
10049
+ GvcMixerDialog *dialog)
10051
+ GvcMixerUIDevice* out = NULL;
10052
+ out = gvc_mixer_control_lookup_output_id (control, id);
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);
10058
+ active_output_update (dialog, out);
10062
+on_control_active_input_update (GvcMixerControl *control,
10064
+ GvcMixerDialog *dialog)
10066
+ GvcMixerUIDevice* in = NULL;
10067
+ in = gvc_mixer_control_lookup_input_id (control, id);
10069
+ if (in == NULL) {
10070
+ g_warning ("on_control_active_input_update - tried to fetch an input of id %u but got nothing", id);
10073
+ active_input_update (dialog, in);
10077
+on_control_input_added (GvcMixerControl *control,
10079
+ GvcMixerDialog *dialog)
10081
+ GvcMixerUIDevice* in = NULL;
10082
+ in = gvc_mixer_control_lookup_input_id (control, id);
10084
+ if (in == NULL) {
10085
+ g_warning ("on_control_input_added - tried to fetch an input of id %u but got nothing", id);
10088
+ add_input_ui_entry (dialog, in);
10092
+on_control_output_removed (GvcMixerControl *control,
10094
+ GvcMixerDialog *dialog)
10098
+ GtkTreeIter iter;
10099
+ GtkTreeModel *model;
10101
+ GvcMixerUIDevice* out = NULL;
10102
+ out = gvc_mixer_control_lookup_output_id (control, id);
10104
+ gint sink_stream_id;
10106
+ g_object_get (G_OBJECT (out),
10107
+ "stream-id", &sink_stream_id,
10110
+ g_debug ("Remove output from dialog \n id : %u \n sink stream id : %i \n",
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);
10118
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
10125
+on_control_input_removed (GvcMixerControl *control,
10127
+ GvcMixerDialog *dialog)
10131
+ GtkTreeIter iter;
10132
+ GtkTreeModel *model;
10134
+ GvcMixerUIDevice* in = NULL;
10135
+ in = gvc_mixer_control_lookup_input_id (control, id);
10139
+ g_object_get (G_OBJECT (in),
10140
+ "stream-id", &stream_id,
10143
+ g_debug ("Remove input from dialog \n id : %u \n stream id : %i \n",
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);
10151
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
10156
+_gtk_label_make_bold (GtkLabel *label)
10158
+ PangoFontDescription *font_desc;
10160
+ font_desc = pango_font_description_new ();
10162
+ pango_font_description_set_weight (font_desc,
10163
+ PANGO_WEIGHT_BOLD);
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.
10170
+ gtk_widget_modify_font (GTK_WIDGET (label), font_desc);
10172
+ pango_font_description_free (font_desc);
10177
+on_input_selection_changed (GtkTreeSelection *selection,
10178
+ GvcMixerDialog *dialog)
10180
+ GtkTreeModel *model;
10181
+ GtkTreeIter iter;
10182
+ gboolean toggled;
10185
+ if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) {
10186
+ g_debug ("Could not get default input from selection");
10190
+ gtk_tree_model_get (model, &iter,
10192
+ ACTIVE_COLUMN, &toggled,
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);
10200
+ if (input == NULL) {
10201
+ g_warning ("on_input_selection_changed - Unable to find input with id: %u", id);
10205
+ gvc_mixer_control_change_input (dialog->priv->mixer_control, input);
10209
+on_output_selection_changed (GtkTreeSelection *selection,
10210
+ GvcMixerDialog *dialog)
10212
+ GtkTreeModel *model;
10213
+ GtkTreeIter iter;
10217
+ if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) {
10218
+ g_debug ("Could not get default output from selection");
10222
+ gtk_tree_model_get (model, &iter,
10224
+ ACTIVE_COLUMN, &active,
10227
+ g_debug ("\n\n on_output_selection_changed - active %i \n\n", active);
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);
10236
+ if (output == NULL) {
10237
+ g_warning ("on_output_selection_changed - Unable to find output with id: %u", id);
10241
+ gvc_mixer_control_change_output (dialog->priv->mixer_control, output);
10245
+name_to_text (GtkTreeViewColumn *column,
10246
+ GtkCellRenderer *cell,
10247
+ GtkTreeModel *model,
10248
+ GtkTreeIter *iter,
10249
+ gpointer user_data)
10251
+ char *name, *mapping;
10253
+ gtk_tree_model_get(model, iter,
10254
+ NAME_COLUMN, &name,
10255
+ SPEAKERS_COLUMN, &mapping,
10258
+ if (mapping == NULL) {
10259
+ g_object_set (cell, "text", name, NULL);
10263
+ str = g_strdup_printf ("%s\n<i>%s</i>",
10265
+ g_object_set (cell, "markup", str, NULL);
10270
+ g_free (mapping);
10273
+static GtkWidget *
10274
+create_stream_treeview (GvcMixerDialog *dialog,
10275
+ GCallback on_selection_changed)
10277
+ GtkWidget *treeview;
10278
+ GtkListStore *store;
10279
+ GtkCellRenderer *renderer;
10280
+ GtkTreeViewColumn *column;
10281
+ GtkTreeSelection *selection;
10283
+ treeview = gtk_tree_view_new ();
10284
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
10286
+ store = gtk_list_store_new (NUM_COLUMNS,
10293
+ gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
10294
+ GTK_TREE_MODEL (store));
10296
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
10297
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
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,
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);
10314
+ g_signal_connect ( selection, "changed",
10315
+ on_selection_changed, dialog);
10317
+ renderer = gtk_cell_renderer_text_new ();
10318
+ column = gtk_tree_view_column_new_with_attributes (_("Device"),
10320
+ "text", DEVICE_COLUMN,
10322
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
10328
+on_profile_changed (GvcComboBox *widget,
10329
+ const char *profile,
10330
+ gpointer user_data)
10332
+ GvcMixerCard *card;
10334
+ card = g_object_get_data (G_OBJECT (widget), "card");
10335
+ if (card == NULL) {
10336
+ g_warning ("Could not find card for combobox");
10340
+ g_debug ("Profile changed to %s for card %s", profile,
10341
+ gvc_mixer_card_get_name (card));
10343
+ gvc_mixer_card_change_profile (card, profile);
10347
+on_test_speakers_clicked (GtkButton *widget,
10348
+ gpointer user_data)
10350
+ GvcMixerDialog *dialog = GVC_MIXER_DIALOG (user_data);
10351
+ GtkTreeModel *model;
10352
+ GtkTreeIter iter;
10353
+ gint active_output = GVC_MIXER_UI_DEVICE_INVALID;
10355
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
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");
10363
+ gboolean is_selected = FALSE ;
10366
+ gtk_tree_model_get (model, &iter,
10368
+ ACTIVE_COLUMN, &is_selected,
10371
+ if (is_selected) {
10372
+ active_output = id;
10376
+ }while (gtk_tree_model_iter_next (model, &iter));
10378
+ if (active_output == GVC_MIXER_UI_DEVICE_INVALID) {
10379
+ g_warning ("Cant find the active output from the UI");
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);
10387
+ if (stream_id == GVC_MIXER_UI_DEVICE_INVALID)
10390
+ g_debug ("Test the speakers on the %s", gvc_mixer_ui_device_get_description (output));
10392
+ GvcMixerStream *stream;
10393
+ GvcMixerCardProfile *profile;
10394
+ GtkWidget *d, *speaker_test, *container;
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");
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,
10408
+ gtk_window_set_has_resize_grip (GTK_WINDOW (d), FALSE);
10411
+ speaker_test = gvc_speaker_test_new (dialog->priv->mixer_control,
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);
10417
+ gtk_dialog_run (GTK_DIALOG (d));
10418
+ gtk_widget_destroy (d);
10422
+gvc_mixer_dialog_constructor (GType type,
10423
+ guint n_construct_properties,
10424
+ GObjectConstructParam *construct_params)
10427
+ GvcMixerDialog *self;
10428
+ GtkWidget *main_vbox;
10429
+ GtkWidget *label;
10430
+ GtkWidget *alignment;
10431
+ GtkWidget *alignment_settings_box;
10432
+ GtkWidget *settings_box;
10436
+ GtkWidget *test_sound_box;
10440
+ GvcMixerStream *stream;
10441
+ GvcMixerCard *card;
10442
+ GtkTreeSelection *selection;
10444
+ object = G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->constructor (type, n_construct_properties, construct_params);
10446
+ self = GVC_MIXER_DIALOG (object);
10448
+ main_vbox = GTK_WIDGET (self);
10449
+ gtk_box_set_spacing (GTK_BOX (main_vbox), 2);
10451
+ gtk_container_set_border_width (GTK_CONTAINER (self), 3);
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),
10459
+ FALSE, FALSE, 0);
10461
+ self->priv->notebook = gtk_notebook_new ();
10462
+ gtk_box_pack_start (GTK_BOX (main_vbox),
10463
+ self->priv->notebook,
10465
+ gtk_container_set_border_width (GTK_CONTAINER (self->priv->notebook), 5);
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,
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);
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);
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);
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),
10497
+ gtk_container_add (GTK_CONTAINER (box), self->priv->output_treeview);
10498
+ gtk_container_add (GTK_CONTAINER (alignment), box);
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);
10511
+ gtk_box_pack_start (GTK_BOX (self->priv->output_box),
10516
+ gtk_box_pack_start (GTK_BOX (settings_box),
10517
+ self->priv->selected_output_label,
10521
+ gtk_box_pack_start (GTK_BOX (settings_box),
10522
+ alignment_settings_box,
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,
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);
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,
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);
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,
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);
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),
10568
+ sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
10569
+ gtk_box_pack_start (GTK_BOX (test_sound_box),
10571
+ FALSE, FALSE, 0);
10573
+ label = gtk_label_new (_("Test:"));
10574
+ gtk_box_pack_start (GTK_BOX (sbox),
10576
+ FALSE, FALSE, 0);
10577
+ if (self->priv->size_group != NULL)
10578
+ gtk_size_group_add_widget (self->priv->size_group, sbox);
10580
+ self->priv->test_output_button = gtk_button_new_with_label (_("Test Sound"));
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,
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);
10592
+ gtk_widget_show (test_sound_box);
10594
+ //gtk_container_add (GTK_CONTAINER (box), self->priv->output_settings_box);
10595
+ g_signal_connect (self->priv->test_output_button,
10597
+ G_CALLBACK (on_test_speakers_clicked),
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,
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);
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);
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);
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),
10629
+ gtk_container_add (GTK_CONTAINER (box), self->priv->input_treeview);
10630
+ gtk_container_add (GTK_CONTAINER (alignment), box);
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));
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,
10642
+ gtk_box_pack_start (GTK_BOX (self->priv->input_settings_box),
10643
+ self->priv->selected_input_label,
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);
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,
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);
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),
10678
+ sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
10679
+ gtk_box_pack_start (GTK_BOX (input_level_box),
10681
+ FALSE, FALSE, 0);
10683
+ label = gtk_label_new (_("Input level:"));
10684
+ gtk_box_pack_start (GTK_BOX (sbox),
10686
+ FALSE, FALSE, 0);
10687
+ if (self->priv->size_group != NULL)
10688
+ gtk_size_group_add_widget (self->priv->size_group, sbox);
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);
10697
+ gtk_box_pack_start (GTK_BOX (input_level_box),
10698
+ self->priv->input_level_bar,
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,
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);
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,
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,
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,
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),
10739
+ FALSE, FALSE, 0);
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);
10747
+ gtk_box_pack_start (GTK_BOX (self->priv->output_stream_box),
10748
+ self->priv->output_bar, TRUE, FALSE, 12);
10750
+ gtk_widget_show_all (main_vbox);
10752
+ g_signal_connect (self->priv->mixer_control,
10754
+ G_CALLBACK (on_control_stream_added),
10756
+ g_signal_connect (self->priv->mixer_control,
10757
+ "stream-removed",
10758
+ G_CALLBACK (on_control_stream_removed),
10760
+ g_signal_connect (self->priv->mixer_control,
10762
+ G_CALLBACK (on_control_output_added),
10764
+ g_signal_connect (self->priv->mixer_control,
10765
+ "output-removed",
10766
+ G_CALLBACK (on_control_output_removed),
10768
+ g_signal_connect (self->priv->mixer_control,
10770
+ G_CALLBACK (on_control_input_added),
10772
+ g_signal_connect (self->priv->mixer_control,
10774
+ G_CALLBACK (on_control_input_removed),
10780
+gvc_mixer_dialog_dispose (GObject *object)
10782
+ GvcMixerDialog *dialog = GVC_MIXER_DIALOG (object);
10784
+ g_clear_object (&dialog->priv->indicator_settings);
10786
+ if (dialog->priv->mixer_control != NULL) {
10787
+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10788
+ on_control_output_added,
10790
+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10791
+ on_control_output_removed,
10793
+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10794
+ on_control_active_input_update,
10796
+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10797
+ on_control_active_output_update,
10799
+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10800
+ on_control_input_added,
10802
+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10803
+ on_control_input_removed,
10805
+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10806
+ on_control_stream_added,
10808
+ g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
10809
+ on_control_stream_removed,
10811
+ g_object_unref (dialog->priv->mixer_control);
10812
+ dialog->priv->mixer_control = NULL;
10815
+ if (dialog->priv->bars != NULL) {
10816
+ g_hash_table_destroy (dialog->priv->bars);
10817
+ dialog->priv->bars = NULL;
10820
+ G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->dispose (object);
10824
+gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass)
10826
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
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;
10834
+ g_object_class_install_property (object_class,
10835
+ PROP_MIXER_CONTROL,
10836
+ g_param_spec_object ("mixer-control",
10839
+ GVC_TYPE_MIXER_CONTROL,
10840
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
10842
+ g_type_class_add_private (klass, sizeof (GvcMixerDialogPrivate));
10847
+gvc_mixer_dialog_init (GvcMixerDialog *dialog)
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);
10855
+gvc_mixer_dialog_finalize (GObject *object)
10857
+ GvcMixerDialog *mixer_dialog;
10859
+ g_return_if_fail (object != NULL);
10860
+ g_return_if_fail (GVC_IS_MIXER_DIALOG (object));
10862
+ mixer_dialog = GVC_MIXER_DIALOG (object);
10864
+ g_return_if_fail (mixer_dialog->priv != NULL);
10865
+ G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->finalize (object);
10869
+gvc_mixer_dialog_new (GvcMixerControl *control)
10872
+ dialog = g_object_new (GVC_TYPE_MIXER_DIALOG,
10873
+ "mixer-control", control,
10875
+ return GVC_MIXER_DIALOG (dialog);
10882
+ PAGE_APPLICATIONS
10886
+gvc_mixer_dialog_set_page (GvcMixerDialog *self,
10887
+ const char *page)
10891
+ g_return_val_if_fail (self != NULL, FALSE);
10893
+ num = PAGE_OUTPUT;
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;
10904
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (self->priv->notebook), num);
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
10913
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
10915
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
10933
+#ifndef __GVC_MIXER_DIALOG_H
10934
+#define __GVC_MIXER_DIALOG_H
10936
+#include <glib-object.h>
10937
+#include "gvc-mixer-control.h"
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))
10948
+typedef struct GvcMixerDialogPrivate GvcMixerDialogPrivate;
10953
+ GvcMixerDialogPrivate *priv;
10958
+ GtkVBoxClass parent_class;
10959
+} GvcMixerDialogClass;
10961
+GType gvc_mixer_dialog_get_type (void);
10963
+GvcMixerDialog * gvc_mixer_dialog_new (GvcMixerControl *control);
10964
+gboolean gvc_mixer_dialog_set_page (GvcMixerDialog *dialog, const gchar* page);
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
10974
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
10976
+ * Copyright (C) 2008 William Jon McCann
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.
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.
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.
10994
+#include "config.h"
10996
+#include <stdlib.h>
10997
+#include <stdio.h>
10998
+#include <unistd.h>
11001
+#include <glib/gi18n-lib.h>
11003
+#include <pulse/pulseaudio.h>
11004
+#include <pulse/ext-stream-restore.h>
11006
+#include "gvc-mixer-event-role.h"
11007
+#include "gvc-mixer-stream-private.h"
11008
+#include "gvc-channel-map-private.h"
11010
+#define GVC_MIXER_EVENT_ROLE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRolePrivate))
11012
+struct GvcMixerEventRolePrivate
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);
11027
+G_DEFINE_TYPE (GvcMixerEventRole, gvc_mixer_event_role, GVC_TYPE_MIXER_STREAM)
11030
+update_settings (GvcMixerEventRole *role,
11031
+ gboolean is_muted,
11035
+ const GvcChannelMap *map;
11036
+ pa_context *context;
11037
+ pa_ext_stream_restore_info info;
11039
+ map = gvc_mixer_stream_get_channel_map (GVC_MIXER_STREAM(role));
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;
11047
+ context = gvc_mixer_stream_get_pa_context (GVC_MIXER_STREAM (role));
11049
+ o = pa_ext_stream_restore_write (context,
11050
+ PA_UPDATE_REPLACE,
11058
+ g_warning ("pa_ext_stream_restore_write() failed");
11069
+gvc_mixer_event_role_push_volume (GvcMixerStream *stream, gpointer *op)
11071
+ return update_settings (GVC_MIXER_EVENT_ROLE (stream),
11072
+ gvc_mixer_stream_get_is_muted (stream), op);
11076
+gvc_mixer_event_role_change_is_muted (GvcMixerStream *stream,
11077
+ gboolean is_muted)
11079
+ return update_settings (GVC_MIXER_EVENT_ROLE (stream),
11084
+gvc_mixer_event_role_set_device (GvcMixerEventRole *role,
11085
+ const char *device)
11087
+ g_return_val_if_fail (GVC_IS_MIXER_EVENT_ROLE (role), FALSE);
11089
+ g_free (role->priv->device);
11090
+ role->priv->device = g_strdup (device);
11091
+ g_object_notify (G_OBJECT (role), "device");
11097
+gvc_mixer_event_role_set_property (GObject *object,
11099
+ const GValue *value,
11100
+ GParamSpec *pspec)
11102
+ GvcMixerEventRole *self = GVC_MIXER_EVENT_ROLE (object);
11104
+ switch (prop_id) {
11105
+ case PROP_DEVICE:
11106
+ gvc_mixer_event_role_set_device (self, g_value_get_string (value));
11109
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
11115
+gvc_mixer_event_role_get_property (GObject *object,
11118
+ GParamSpec *pspec)
11120
+ GvcMixerEventRole *self = GVC_MIXER_EVENT_ROLE (object);
11122
+ switch (prop_id) {
11123
+ case PROP_DEVICE:
11124
+ g_value_set_string (value, self->priv->device);
11127
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
11133
+gvc_mixer_event_role_class_init (GvcMixerEventRoleClass *klass)
11135
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
11136
+ GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
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;
11142
+ stream_class->push_volume = gvc_mixer_event_role_push_volume;
11143
+ stream_class->change_is_muted = gvc_mixer_event_role_change_is_muted;
11145
+ g_object_class_install_property (object_class,
11147
+ g_param_spec_string ("device",
11151
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
11153
+ g_type_class_add_private (klass, sizeof (GvcMixerEventRolePrivate));
11157
+gvc_mixer_event_role_init (GvcMixerEventRole *event_role)
11159
+ event_role->priv = GVC_MIXER_EVENT_ROLE_GET_PRIVATE (event_role);
11164
+gvc_mixer_event_role_finalize (GObject *object)
11166
+ GvcMixerEventRole *mixer_event_role;
11168
+ g_return_if_fail (object != NULL);
11169
+ g_return_if_fail (GVC_IS_MIXER_EVENT_ROLE (object));
11171
+ mixer_event_role = GVC_MIXER_EVENT_ROLE (object);
11173
+ g_return_if_fail (mixer_event_role->priv != NULL);
11175
+ g_free (mixer_event_role->priv->device);
11177
+ G_OBJECT_CLASS (gvc_mixer_event_role_parent_class)->finalize (object);
11181
+ * gvc_mixer_event_role_new: (skip)
11190
+gvc_mixer_event_role_new (pa_context *context,
11191
+ const char *device,
11192
+ GvcChannelMap *channel_map)
11196
+ object = g_object_new (GVC_TYPE_MIXER_EVENT_ROLE,
11197
+ "pa-context", context,
11199
+ "device", device,
11200
+ "channel-map", channel_map,
11203
+ return GVC_MIXER_STREAM (object);
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
11210
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11212
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
11230
+#ifndef __GVC_MIXER_EVENT_ROLE_H
11231
+#define __GVC_MIXER_EVENT_ROLE_H
11233
+#include <glib-object.h>
11234
+#include "gvc-mixer-stream.h"
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))
11245
+typedef struct GvcMixerEventRolePrivate GvcMixerEventRolePrivate;
11249
+ GvcMixerStream parent;
11250
+ GvcMixerEventRolePrivate *priv;
11251
+} GvcMixerEventRole;
11255
+ GvcMixerStreamClass parent_class;
11256
+} GvcMixerEventRoleClass;
11258
+GType gvc_mixer_event_role_get_type (void);
11260
+GvcMixerStream * gvc_mixer_event_role_new (pa_context *context,
11261
+ const char *device,
11262
+ GvcChannelMap *channel_map);
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
11272
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11274
+ * Copyright (C) 2008 William Jon McCann
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.
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.
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.
11292
+#include "config.h"
11294
+#include <stdlib.h>
11295
+#include <stdio.h>
11296
+#include <unistd.h>
11299
+#include <glib/gi18n-lib.h>
11301
+#include <pulse/pulseaudio.h>
11303
+#include "gvc-mixer-sink-input.h"
11304
+#include "gvc-mixer-stream-private.h"
11305
+#include "gvc-channel-map-private.h"
11307
+#define GVC_MIXER_SINK_INPUT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputPrivate))
11309
+struct GvcMixerSinkInputPrivate
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);
11318
+G_DEFINE_TYPE (GvcMixerSinkInput, gvc_mixer_sink_input, GVC_TYPE_MIXER_STREAM)
11321
+gvc_mixer_sink_input_push_volume (GvcMixerStream *stream, gpointer *op)
11325
+ const GvcChannelMap *map;
11326
+ pa_context *context;
11327
+ const pa_cvolume *cv;
11329
+ index = gvc_mixer_stream_get_index (stream);
11331
+ map = gvc_mixer_stream_get_channel_map (stream);
11333
+ cv = gvc_channel_map_get_cvolume(map);
11335
+ context = gvc_mixer_stream_get_pa_context (stream);
11337
+ o = pa_context_set_sink_input_volume (context,
11344
+ g_warning ("pa_context_set_sink_input_volume() failed");
11354
+gvc_mixer_sink_input_change_is_muted (GvcMixerStream *stream,
11355
+ gboolean is_muted)
11359
+ pa_context *context;
11361
+ index = gvc_mixer_stream_get_index (stream);
11362
+ context = gvc_mixer_stream_get_pa_context (stream);
11364
+ o = pa_context_set_sink_input_mute (context,
11371
+ g_warning ("pa_context_set_sink_input_mute_by_index() failed");
11375
+ pa_operation_unref(o);
11381
+gvc_mixer_sink_input_class_init (GvcMixerSinkInputClass *klass)
11383
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
11384
+ GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
11386
+ object_class->finalize = gvc_mixer_sink_input_finalize;
11388
+ stream_class->push_volume = gvc_mixer_sink_input_push_volume;
11389
+ stream_class->change_is_muted = gvc_mixer_sink_input_change_is_muted;
11391
+ g_type_class_add_private (klass, sizeof (GvcMixerSinkInputPrivate));
11395
+gvc_mixer_sink_input_init (GvcMixerSinkInput *sink_input)
11397
+ sink_input->priv = GVC_MIXER_SINK_INPUT_GET_PRIVATE (sink_input);
11401
+gvc_mixer_sink_input_finalize (GObject *object)
11403
+ GvcMixerSinkInput *mixer_sink_input;
11405
+ g_return_if_fail (object != NULL);
11406
+ g_return_if_fail (GVC_IS_MIXER_SINK_INPUT (object));
11408
+ mixer_sink_input = GVC_MIXER_SINK_INPUT (object);
11410
+ g_return_if_fail (mixer_sink_input->priv != NULL);
11411
+ G_OBJECT_CLASS (gvc_mixer_sink_input_parent_class)->finalize (object);
11415
+ * gvc_mixer_sink_input_new: (skip)
11424
+gvc_mixer_sink_input_new (pa_context *context,
11426
+ GvcChannelMap *channel_map)
11430
+ object = g_object_new (GVC_TYPE_MIXER_SINK_INPUT,
11431
+ "pa-context", context,
11433
+ "channel-map", channel_map,
11436
+ return GVC_MIXER_STREAM (object);
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
11443
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11445
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
11463
+#ifndef __GVC_MIXER_SINK_INPUT_H
11464
+#define __GVC_MIXER_SINK_INPUT_H
11466
+#include <glib-object.h>
11467
+#include "gvc-mixer-stream.h"
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))
11478
+typedef struct GvcMixerSinkInputPrivate GvcMixerSinkInputPrivate;
11482
+ GvcMixerStream parent;
11483
+ GvcMixerSinkInputPrivate *priv;
11484
+} GvcMixerSinkInput;
11488
+ GvcMixerStreamClass parent_class;
11489
+} GvcMixerSinkInputClass;
11491
+GType gvc_mixer_sink_input_get_type (void);
11493
+GvcMixerStream * gvc_mixer_sink_input_new (pa_context *context,
11495
+ GvcChannelMap *map);
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
11505
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11507
+ * Copyright (C) 2008 William Jon McCann
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.
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.
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.
11525
+#include "config.h"
11527
+#include <stdlib.h>
11528
+#include <stdio.h>
11529
+#include <unistd.h>
11532
+#include <glib/gi18n-lib.h>
11534
+#include <pulse/pulseaudio.h>
11536
+#include "gvc-mixer-sink.h"
11537
+#include "gvc-mixer-stream-private.h"
11538
+#include "gvc-channel-map-private.h"
11540
+#define GVC_MIXER_SINK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SINK, GvcMixerSinkPrivate))
11542
+struct GvcMixerSinkPrivate
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);
11551
+G_DEFINE_TYPE (GvcMixerSink, gvc_mixer_sink, GVC_TYPE_MIXER_STREAM)
11554
+gvc_mixer_sink_push_volume (GvcMixerStream *stream, gpointer *op)
11558
+ const GvcChannelMap *map;
11559
+ pa_context *context;
11560
+ const pa_cvolume *cv;
11562
+ index = gvc_mixer_stream_get_index (stream);
11564
+ map = gvc_mixer_stream_get_channel_map (stream);
11566
+ /* set the volume */
11567
+ cv = gvc_channel_map_get_cvolume(map);
11569
+ context = gvc_mixer_stream_get_pa_context (stream);
11571
+ o = pa_context_set_sink_volume_by_index (context,
11578
+ g_warning ("pa_context_set_sink_volume_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
11588
+gvc_mixer_sink_change_is_muted (GvcMixerStream *stream,
11589
+ gboolean is_muted)
11593
+ pa_context *context;
11595
+ index = gvc_mixer_stream_get_index (stream);
11596
+ context = gvc_mixer_stream_get_pa_context (stream);
11598
+ o = pa_context_set_sink_mute_by_index (context,
11605
+ g_warning ("pa_context_set_sink_mute_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
11609
+ pa_operation_unref(o);
11615
+gvc_mixer_sink_change_port (GvcMixerStream *stream,
11616
+ const char *port)
11620
+ pa_context *context;
11622
+ index = gvc_mixer_stream_get_index (stream);
11623
+ context = gvc_mixer_stream_get_pa_context (stream);
11625
+ o = pa_context_set_sink_port_by_index (context,
11632
+ g_warning ("pa_context_set_sink_port_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
11636
+ pa_operation_unref(o);
11642
+gvc_mixer_sink_class_init (GvcMixerSinkClass *klass)
11644
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
11645
+ GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
11647
+ object_class->finalize = gvc_mixer_sink_finalize;
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;
11653
+ g_type_class_add_private (klass, sizeof (GvcMixerSinkPrivate));
11657
+gvc_mixer_sink_init (GvcMixerSink *sink)
11659
+ sink->priv = GVC_MIXER_SINK_GET_PRIVATE (sink);
11663
+gvc_mixer_sink_finalize (GObject *object)
11665
+ GvcMixerSink *mixer_sink;
11667
+ g_return_if_fail (object != NULL);
11668
+ g_return_if_fail (GVC_IS_MIXER_SINK (object));
11670
+ mixer_sink = GVC_MIXER_SINK (object);
11672
+ g_return_if_fail (mixer_sink->priv != NULL);
11673
+ G_OBJECT_CLASS (gvc_mixer_sink_parent_class)->finalize (object);
11677
+ * gvc_mixer_sink_new: (skip)
11686
+gvc_mixer_sink_new (pa_context *context,
11688
+ GvcChannelMap *channel_map)
11693
+ object = g_object_new (GVC_TYPE_MIXER_SINK,
11694
+ "pa-context", context,
11696
+ "channel-map", channel_map,
11699
+ return GVC_MIXER_STREAM (object);
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
11706
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11708
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
11726
+#ifndef __GVC_MIXER_SINK_H
11727
+#define __GVC_MIXER_SINK_H
11729
+#include <glib-object.h>
11730
+#include "gvc-mixer-stream.h"
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))
11741
+typedef struct GvcMixerSinkPrivate GvcMixerSinkPrivate;
11745
+ GvcMixerStream parent;
11746
+ GvcMixerSinkPrivate *priv;
11751
+ GvcMixerStreamClass parent_class;
11752
+} GvcMixerSinkClass;
11754
+GType gvc_mixer_sink_get_type (void);
11756
+GvcMixerStream * gvc_mixer_sink_new (pa_context *context,
11758
+ GvcChannelMap *map);
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
11768
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11770
+ * Copyright (C) 2008 William Jon McCann
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.
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.
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.
11788
+#include "config.h"
11790
+#include <stdlib.h>
11791
+#include <stdio.h>
11792
+#include <unistd.h>
11795
+#include <glib/gi18n-lib.h>
11797
+#include <pulse/pulseaudio.h>
11799
+#include "gvc-mixer-source-output.h"
11801
+#define GVC_MIXER_SOURCE_OUTPUT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputPrivate))
11803
+struct GvcMixerSourceOutputPrivate
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);
11812
+G_DEFINE_TYPE (GvcMixerSourceOutput, gvc_mixer_source_output, GVC_TYPE_MIXER_STREAM)
11815
+gvc_mixer_source_output_push_volume (GvcMixerStream *stream, gpointer *op)
11823
+gvc_mixer_source_output_change_is_muted (GvcMixerStream *stream,
11824
+ gboolean is_muted)
11831
+gvc_mixer_source_output_class_init (GvcMixerSourceOutputClass *klass)
11833
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
11834
+ GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
11836
+ object_class->finalize = gvc_mixer_source_output_finalize;
11838
+ stream_class->push_volume = gvc_mixer_source_output_push_volume;
11839
+ stream_class->change_is_muted = gvc_mixer_source_output_change_is_muted;
11841
+ g_type_class_add_private (klass, sizeof (GvcMixerSourceOutputPrivate));
11845
+gvc_mixer_source_output_init (GvcMixerSourceOutput *source_output)
11847
+ source_output->priv = GVC_MIXER_SOURCE_OUTPUT_GET_PRIVATE (source_output);
11852
+gvc_mixer_source_output_finalize (GObject *object)
11854
+ GvcMixerSourceOutput *mixer_source_output;
11856
+ g_return_if_fail (object != NULL);
11857
+ g_return_if_fail (GVC_IS_MIXER_SOURCE_OUTPUT (object));
11859
+ mixer_source_output = GVC_MIXER_SOURCE_OUTPUT (object);
11861
+ g_return_if_fail (mixer_source_output->priv != NULL);
11862
+ G_OBJECT_CLASS (gvc_mixer_source_output_parent_class)->finalize (object);
11866
+ * gvc_mixer_source_output_new: (skip)
11875
+gvc_mixer_source_output_new (pa_context *context,
11877
+ GvcChannelMap *channel_map)
11881
+ object = g_object_new (GVC_TYPE_MIXER_SOURCE_OUTPUT,
11882
+ "pa-context", context,
11884
+ "channel-map", channel_map,
11887
+ return GVC_MIXER_STREAM (object);
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
11894
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11896
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
11914
+#ifndef __GVC_MIXER_SOURCE_OUTPUT_H
11915
+#define __GVC_MIXER_SOURCE_OUTPUT_H
11917
+#include <glib-object.h>
11918
+#include "gvc-mixer-stream.h"
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))
11929
+typedef struct GvcMixerSourceOutputPrivate GvcMixerSourceOutputPrivate;
11933
+ GvcMixerStream parent;
11934
+ GvcMixerSourceOutputPrivate *priv;
11935
+} GvcMixerSourceOutput;
11939
+ GvcMixerStreamClass parent_class;
11940
+} GvcMixerSourceOutputClass;
11942
+GType gvc_mixer_source_output_get_type (void);
11944
+GvcMixerStream * gvc_mixer_source_output_new (pa_context *context,
11946
+ GvcChannelMap *map);
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
11956
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
11958
+ * Copyright (C) 2008 William Jon McCann
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.
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.
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.
11976
+#include "config.h"
11978
+#include <stdlib.h>
11979
+#include <stdio.h>
11980
+#include <unistd.h>
11983
+#include <glib/gi18n-lib.h>
11985
+#include <pulse/pulseaudio.h>
11987
+#include "gvc-mixer-source.h"
11988
+#include "gvc-mixer-stream-private.h"
11989
+#include "gvc-channel-map-private.h"
11991
+#define GVC_MIXER_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSourcePrivate))
11993
+struct GvcMixerSourcePrivate
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);
12002
+G_DEFINE_TYPE (GvcMixerSource, gvc_mixer_source, GVC_TYPE_MIXER_STREAM)
12005
+gvc_mixer_source_push_volume (GvcMixerStream *stream, gpointer *op)
12009
+ const GvcChannelMap *map;
12010
+ pa_context *context;
12011
+ const pa_cvolume *cv;
12013
+ index = gvc_mixer_stream_get_index (stream);
12015
+ map = gvc_mixer_stream_get_channel_map (stream);
12017
+ /* set the volume */
12018
+ cv = gvc_channel_map_get_cvolume (map);
12020
+ context = gvc_mixer_stream_get_pa_context (stream);
12022
+ o = pa_context_set_source_volume_by_index (context,
12029
+ g_warning ("pa_context_set_source_volume_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
12039
+gvc_mixer_source_change_is_muted (GvcMixerStream *stream,
12040
+ gboolean is_muted)
12044
+ pa_context *context;
12046
+ index = gvc_mixer_stream_get_index (stream);
12047
+ context = gvc_mixer_stream_get_pa_context (stream);
12049
+ o = pa_context_set_source_mute_by_index (context,
12056
+ g_warning ("pa_context_set_source_mute_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
12060
+ pa_operation_unref(o);
12066
+gvc_mixer_source_change_port (GvcMixerStream *stream,
12067
+ const char *port)
12071
+ pa_context *context;
12073
+ index = gvc_mixer_stream_get_index (stream);
12074
+ context = gvc_mixer_stream_get_pa_context (stream);
12076
+ o = pa_context_set_source_port_by_index (context,
12083
+ g_warning ("pa_context_set_source_port_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
12087
+ pa_operation_unref(o);
12093
+gvc_mixer_source_class_init (GvcMixerSourceClass *klass)
12095
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
12096
+ GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
12098
+ object_class->finalize = gvc_mixer_source_finalize;
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;
12104
+ g_type_class_add_private (klass, sizeof (GvcMixerSourcePrivate));
12108
+gvc_mixer_source_init (GvcMixerSource *source)
12110
+ source->priv = GVC_MIXER_SOURCE_GET_PRIVATE (source);
12114
+gvc_mixer_source_finalize (GObject *object)
12116
+ GvcMixerSource *mixer_source;
12118
+ g_return_if_fail (object != NULL);
12119
+ g_return_if_fail (GVC_IS_MIXER_SOURCE (object));
12121
+ mixer_source = GVC_MIXER_SOURCE (object);
12123
+ g_return_if_fail (mixer_source->priv != NULL);
12124
+ G_OBJECT_CLASS (gvc_mixer_source_parent_class)->finalize (object);
12128
+ * gvc_mixer_source_new: (skip)
12137
+gvc_mixer_source_new (pa_context *context,
12139
+ GvcChannelMap *channel_map)
12144
+ object = g_object_new (GVC_TYPE_MIXER_SOURCE,
12145
+ "pa-context", context,
12147
+ "channel-map", channel_map,
12150
+ return GVC_MIXER_STREAM (object);
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
12157
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
12159
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
12177
+#ifndef __GVC_MIXER_SOURCE_H
12178
+#define __GVC_MIXER_SOURCE_H
12180
+#include <glib-object.h>
12181
+#include "gvc-mixer-stream.h"
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))
12192
+typedef struct GvcMixerSourcePrivate GvcMixerSourcePrivate;
12196
+ GvcMixerStream parent;
12197
+ GvcMixerSourcePrivate *priv;
12202
+ GvcMixerStreamClass parent_class;
12203
+} GvcMixerSourceClass;
12205
+GType gvc_mixer_source_get_type (void);
12207
+GvcMixerStream * gvc_mixer_source_new (pa_context *context,
12209
+ GvcChannelMap *map);
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
12219
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
12221
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
12239
+#ifndef __GVC_MIXER_STREAM_PRIVATE_H
12240
+#define __GVC_MIXER_STREAM_PRIVATE_H
12242
+#include <glib-object.h>
12244
+#include "gvc-channel-map.h"
12248
+pa_context * gvc_mixer_stream_get_pa_context (GvcMixerStream *stream);
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
12258
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
12260
+ * Copyright (C) 2008 William Jon McCann
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.
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.
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.
12278
+#include "config.h"
12280
+#include <stdlib.h>
12281
+#include <stdio.h>
12282
+#include <unistd.h>
12285
+#include <glib/gi18n-lib.h>
12287
+#include <pulse/pulseaudio.h>
12289
+#include "gvc-mixer-stream.h"
12290
+#include "gvc-mixer-stream-private.h"
12291
+#include "gvc-channel-map-private.h"
12293
+#define GVC_MIXER_STREAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStreamPrivate))
12295
+static guint32 stream_serial = 1;
12297
+struct GvcMixerStreamPrivate
12299
+ pa_context *pa_context;
12303
+ GvcChannelMap *channel_map;
12305
+ char *description;
12306
+ char *application_id;
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;
12315
+ char *human_port;
12324
+ PROP_CHANNEL_MAP,
12327
+ PROP_DESCRIPTION,
12328
+ PROP_APPLICATION_ID,
12333
+ PROP_CAN_DECIBEL,
12334
+ PROP_IS_EVENT_STREAM,
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);
12344
+G_DEFINE_ABSTRACT_TYPE (GvcMixerStream, gvc_mixer_stream, G_TYPE_OBJECT)
12347
+get_next_stream_serial (void)
12351
+ serial = stream_serial++;
12353
+ if ((gint32)stream_serial < 0) {
12354
+ stream_serial = 1;
12361
+gvc_mixer_stream_get_pa_context (GvcMixerStream *stream)
12363
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
12364
+ return stream->priv->pa_context;
12368
+gvc_mixer_stream_get_index (GvcMixerStream *stream)
12370
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
12371
+ return stream->priv->index;
12375
+gvc_mixer_stream_get_id (GvcMixerStream *stream)
12377
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
12378
+ return stream->priv->id;
12381
+const GvcChannelMap *
12382
+gvc_mixer_stream_get_channel_map (GvcMixerStream *stream)
12384
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12385
+ return stream->priv->channel_map;
12389
+ * gvc_mixer_stream_get_volume:
12393
+ * Returns: (type guint32) (transfer none):
12396
+gvc_mixer_stream_get_volume (GvcMixerStream *stream)
12398
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
12400
+ return (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME];
12404
+gvc_mixer_stream_get_decibel (GvcMixerStream *stream)
12406
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
12408
+ return pa_sw_volume_to_dB(
12409
+ (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME]);
12413
+ * gvc_mixer_stream_set_volume:
12416
+ * @volume: (type guint32):
12421
+gvc_mixer_stream_set_volume (GvcMixerStream *stream,
12422
+ pa_volume_t volume)
12426
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12428
+ cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map);
12429
+ pa_cvolume_scale(&cv, volume);
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");
12441
+gvc_mixer_stream_set_decibel (GvcMixerStream *stream,
12446
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12448
+ cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map);
12449
+ pa_cvolume_scale(&cv, pa_sw_volume_from_dB(db));
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");
12460
+gvc_mixer_stream_get_is_muted (GvcMixerStream *stream)
12462
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12463
+ return stream->priv->is_muted;
12467
+gvc_mixer_stream_get_can_decibel (GvcMixerStream *stream)
12469
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12470
+ return stream->priv->can_decibel;
12474
+gvc_mixer_stream_set_is_muted (GvcMixerStream *stream,
12475
+ gboolean is_muted)
12477
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12479
+ if (is_muted != stream->priv->is_muted) {
12480
+ stream->priv->is_muted = is_muted;
12481
+ g_object_notify (G_OBJECT (stream), "is-muted");
12488
+gvc_mixer_stream_set_can_decibel (GvcMixerStream *stream,
12489
+ gboolean can_decibel)
12491
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12493
+ if (can_decibel != stream->priv->can_decibel) {
12494
+ stream->priv->can_decibel = can_decibel;
12495
+ g_object_notify (G_OBJECT (stream), "can-decibel");
12502
+gvc_mixer_stream_get_name (GvcMixerStream *stream)
12504
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12505
+ return stream->priv->name;
12509
+gvc_mixer_stream_get_description (GvcMixerStream *stream)
12511
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12512
+ return stream->priv->description;
12516
+gvc_mixer_stream_set_name (GvcMixerStream *stream,
12517
+ const char *name)
12519
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12521
+ g_free (stream->priv->name);
12522
+ stream->priv->name = g_strdup (name);
12523
+ g_object_notify (G_OBJECT (stream), "name");
12529
+gvc_mixer_stream_set_description (GvcMixerStream *stream,
12530
+ const char *description)
12532
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12534
+ g_free (stream->priv->description);
12535
+ stream->priv->description = g_strdup (description);
12536
+ g_object_notify (G_OBJECT (stream), "description");
12542
+gvc_mixer_stream_is_event_stream (GvcMixerStream *stream)
12544
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12546
+ return stream->priv->is_event_stream;
12550
+gvc_mixer_stream_set_is_event_stream (GvcMixerStream *stream,
12551
+ gboolean is_event_stream)
12553
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12555
+ stream->priv->is_event_stream = is_event_stream;
12556
+ g_object_notify (G_OBJECT (stream), "is-event-stream");
12562
+gvc_mixer_stream_is_virtual (GvcMixerStream *stream)
12564
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12566
+ return stream->priv->is_virtual;
12570
+gvc_mixer_stream_set_is_virtual (GvcMixerStream *stream,
12571
+ gboolean is_virtual)
12573
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12575
+ stream->priv->is_virtual = is_virtual;
12576
+ g_object_notify (G_OBJECT (stream), "is-virtual");
12582
+gvc_mixer_stream_get_application_id (GvcMixerStream *stream)
12584
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12585
+ return stream->priv->application_id;
12589
+gvc_mixer_stream_set_application_id (GvcMixerStream *stream,
12590
+ const char *application_id)
12592
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
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");
12602
+on_channel_map_volume_changed (GvcChannelMap *channel_map,
12604
+ GvcMixerStream *stream)
12607
+ gvc_mixer_stream_push_volume (stream);
12609
+ g_object_notify (G_OBJECT (stream), "volume");
12613
+gvc_mixer_stream_set_channel_map (GvcMixerStream *stream,
12614
+ GvcChannelMap *channel_map)
12616
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12618
+ if (channel_map != NULL) {
12619
+ g_object_ref (channel_map);
12622
+ if (stream->priv->channel_map != NULL) {
12623
+ g_signal_handlers_disconnect_by_func (stream->priv->channel_map,
12624
+ on_channel_map_volume_changed,
12626
+ g_object_unref (stream->priv->channel_map);
12629
+ stream->priv->channel_map = channel_map;
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),
12637
+ g_object_notify (G_OBJECT (stream), "channel-map");
12644
+gvc_mixer_stream_get_icon_name (GvcMixerStream *stream)
12646
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12647
+ return stream->priv->icon_name;
12651
+ * gvc_mixer_stream_get_gicon:
12652
+ * @stream: a #GvcMixerStream
12654
+ * Returns: (transfer full): a new #GIcon
12657
+gvc_mixer_stream_get_gicon (GvcMixerStream *stream)
12659
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12660
+ if (stream->priv->icon_name == NULL)
12662
+ return g_themed_icon_new_with_default_fallbacks (stream->priv->icon_name);
12666
+gvc_mixer_stream_set_icon_name (GvcMixerStream *stream,
12667
+ const char *icon_name)
12669
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
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");
12679
+ * gvc_mixer_stream_get_base_volume:
12683
+ * Returns: (type guint32) (transfer none):
12686
+gvc_mixer_stream_get_base_volume (GvcMixerStream *stream)
12688
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
12690
+ return stream->priv->base_volume;
12694
+ * gvc_mixer_stream_set_base_volume:
12697
+ * @base_volume: (type guint32):
12702
+gvc_mixer_stream_set_base_volume (GvcMixerStream *stream,
12703
+ pa_volume_t base_volume)
12705
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12707
+ stream->priv->base_volume = base_volume;
12712
+const GvcMixerStreamPort *
12713
+gvc_mixer_stream_get_port (GvcMixerStream *stream)
12717
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12718
+ g_return_val_if_fail (stream->priv->ports != NULL, NULL);
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) {
12727
+ g_assert_not_reached ();
12733
+gvc_mixer_stream_set_port (GvcMixerStream *stream,
12734
+ const char *port)
12738
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12739
+ g_return_val_if_fail (stream->priv->ports != NULL, FALSE);
12741
+ g_free (stream->priv->port);
12742
+ stream->priv->port = g_strdup (port);
12744
+ g_free (stream->priv->human_port);
12745
+ stream->priv->human_port = NULL;
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);
12755
+ g_object_notify (G_OBJECT (stream), "port");
12761
+gvc_mixer_stream_change_port (GvcMixerStream *stream,
12762
+ const char *port)
12764
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12765
+ return GVC_MIXER_STREAM_GET_CLASS (stream)->change_port (stream, port);
12769
+ * gvc_mixer_stream_get_ports:
12771
+ * Return value: (transfer none) (element-type GvcMixerStreamPort):
12774
+gvc_mixer_stream_get_ports (GvcMixerStream *stream)
12776
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
12777
+ return stream->priv->ports;
12781
+sort_ports (GvcMixerStreamPort *a,
12782
+ GvcMixerStreamPort *b)
12784
+ if (a->priority == b->priority)
12786
+ if (a->priority > b->priority)
12792
+ * gvc_mixer_stream_set_ports:
12793
+ * @ports: (transfer full) (element-type GvcMixerStreamPort):
12796
+gvc_mixer_stream_set_ports (GvcMixerStream *stream,
12799
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12800
+ g_return_val_if_fail (stream->priv->ports == NULL, FALSE);
12802
+ stream->priv->ports = g_list_sort (ports, (GCompareFunc) sort_ports);
12808
+gvc_mixer_stream_get_card_index (GvcMixerStream *stream)
12810
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), PA_INVALID_INDEX);
12811
+ return stream->priv->card_index;
12815
+gvc_mixer_stream_set_card_index (GvcMixerStream *stream,
12818
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12820
+ stream->priv->card_index = card_index;
12821
+ g_object_notify (G_OBJECT (stream), "card-index");
12827
+gvc_mixer_stream_set_property (GObject *object,
12829
+ const GValue *value,
12830
+ GParamSpec *pspec)
12832
+ GvcMixerStream *self = GVC_MIXER_STREAM (object);
12834
+ switch (prop_id) {
12835
+ case PROP_PA_CONTEXT:
12836
+ self->priv->pa_context = g_value_get_pointer (value);
12839
+ self->priv->index = g_value_get_ulong (value);
12842
+ self->priv->id = g_value_get_ulong (value);
12844
+ case PROP_CHANNEL_MAP:
12845
+ gvc_mixer_stream_set_channel_map (self, g_value_get_object (value));
12848
+ gvc_mixer_stream_set_name (self, g_value_get_string (value));
12850
+ case PROP_DESCRIPTION:
12851
+ gvc_mixer_stream_set_description (self, g_value_get_string (value));
12853
+ case PROP_APPLICATION_ID:
12854
+ gvc_mixer_stream_set_application_id (self, g_value_get_string (value));
12856
+ case PROP_ICON_NAME:
12857
+ gvc_mixer_stream_set_icon_name (self, g_value_get_string (value));
12859
+ case PROP_VOLUME:
12860
+ gvc_mixer_stream_set_volume (self, g_value_get_ulong (value));
12862
+ case PROP_DECIBEL:
12863
+ gvc_mixer_stream_set_decibel (self, g_value_get_double (value));
12865
+ case PROP_IS_MUTED:
12866
+ gvc_mixer_stream_set_is_muted (self, g_value_get_boolean (value));
12868
+ case PROP_IS_EVENT_STREAM:
12869
+ gvc_mixer_stream_set_is_event_stream (self, g_value_get_boolean (value));
12871
+ case PROP_IS_VIRTUAL:
12872
+ gvc_mixer_stream_set_is_virtual (self, g_value_get_boolean (value));
12874
+ case PROP_CAN_DECIBEL:
12875
+ gvc_mixer_stream_set_can_decibel (self, g_value_get_boolean (value));
12878
+ gvc_mixer_stream_set_port (self, g_value_get_string (value));
12880
+ case PROP_CARD_INDEX:
12881
+ self->priv->card_index = g_value_get_long (value);
12884
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
12890
+gvc_mixer_stream_get_property (GObject *object,
12893
+ GParamSpec *pspec)
12895
+ GvcMixerStream *self = GVC_MIXER_STREAM (object);
12897
+ switch (prop_id) {
12898
+ case PROP_PA_CONTEXT:
12899
+ g_value_set_pointer (value, self->priv->pa_context);
12902
+ g_value_set_ulong (value, self->priv->index);
12905
+ g_value_set_ulong (value, self->priv->id);
12907
+ case PROP_CHANNEL_MAP:
12908
+ g_value_set_object (value, self->priv->channel_map);
12911
+ g_value_set_string (value, self->priv->name);
12913
+ case PROP_DESCRIPTION:
12914
+ g_value_set_string (value, self->priv->description);
12916
+ case PROP_APPLICATION_ID:
12917
+ g_value_set_string (value, self->priv->application_id);
12919
+ case PROP_ICON_NAME:
12920
+ g_value_set_string (value, self->priv->icon_name);
12922
+ case PROP_VOLUME:
12923
+ g_value_set_ulong (value,
12924
+ pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map)));
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))));
12930
+ case PROP_IS_MUTED:
12931
+ g_value_set_boolean (value, self->priv->is_muted);
12933
+ case PROP_IS_EVENT_STREAM:
12934
+ g_value_set_boolean (value, self->priv->is_event_stream);
12936
+ case PROP_IS_VIRTUAL:
12937
+ g_value_set_boolean (value, self->priv->is_virtual);
12939
+ case PROP_CAN_DECIBEL:
12940
+ g_value_set_boolean (value, self->priv->can_decibel);
12943
+ g_value_set_string (value, self->priv->port);
12945
+ case PROP_CARD_INDEX:
12946
+ g_value_set_long (value, self->priv->card_index);
12949
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
12955
+gvc_mixer_stream_constructor (GType type,
12956
+ guint n_construct_properties,
12957
+ GObjectConstructParam *construct_params)
12960
+ GvcMixerStream *self;
12962
+ object = G_OBJECT_CLASS (gvc_mixer_stream_parent_class)->constructor (type, n_construct_properties, construct_params);
12964
+ self = GVC_MIXER_STREAM (object);
12966
+ self->priv->id = get_next_stream_serial ();
12972
+gvc_mixer_stream_real_change_port (GvcMixerStream *stream,
12973
+ const char *port)
12979
+gvc_mixer_stream_real_push_volume (GvcMixerStream *stream, gpointer *op)
12985
+gvc_mixer_stream_real_change_is_muted (GvcMixerStream *stream,
12986
+ gboolean is_muted)
12992
+gvc_mixer_stream_push_volume (GvcMixerStream *stream)
12994
+ pa_operation *op;
12997
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
12999
+ if (stream->priv->is_event_stream != FALSE)
13002
+ g_debug ("Pushing new volume to stream '%s' (%s)",
13003
+ stream->priv->description, stream->priv->name);
13005
+ ret = GVC_MIXER_STREAM_GET_CLASS (stream)->push_volume (stream, (gpointer *) &op);
13007
+ if (stream->priv->change_volume_op != NULL)
13008
+ pa_operation_unref (stream->priv->change_volume_op);
13009
+ stream->priv->change_volume_op = op;
13015
+gvc_mixer_stream_change_is_muted (GvcMixerStream *stream,
13016
+ gboolean is_muted)
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);
13025
+gvc_mixer_stream_is_running (GvcMixerStream *stream)
13027
+ if (stream->priv->change_volume_op == NULL)
13030
+ if ((pa_operation_get_state(stream->priv->change_volume_op) == PA_OPERATION_RUNNING))
13033
+ pa_operation_unref(stream->priv->change_volume_op);
13034
+ stream->priv->change_volume_op = NULL;
13040
+gvc_mixer_stream_class_init (GvcMixerStreamClass *klass)
13042
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
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;
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;
13053
+ g_object_class_install_property (gobject_class,
13055
+ g_param_spec_ulong ("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,
13062
+ g_param_spec_ulong ("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",
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,
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,
13082
+ g_param_spec_ulong ("volume",
13084
+ "The volume for this stream",
13085
+ 0, G_MAXULONG, 0,
13086
+ G_PARAM_READWRITE));
13087
+ g_object_class_install_property (gobject_class,
13089
+ g_param_spec_double ("decibel",
13091
+ "The decibel level for this stream",
13092
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
13093
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13095
+ g_object_class_install_property (gobject_class,
13097
+ g_param_spec_string ("name",
13099
+ "Name to display for this stream",
13101
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13102
+ g_object_class_install_property (gobject_class,
13103
+ PROP_DESCRIPTION,
13104
+ g_param_spec_string ("description",
13106
+ "Description to display for this stream",
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",
13115
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13116
+ g_object_class_install_property (gobject_class,
13118
+ g_param_spec_string ("icon-name",
13120
+ "Name of icon to display for this stream",
13122
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13123
+ g_object_class_install_property (gobject_class,
13125
+ g_param_spec_boolean ("is-muted",
13127
+ "Whether stream is muted",
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",
13134
+ "Whether stream volume can be converted to decibel units",
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",
13143
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13144
+ g_object_class_install_property (gobject_class,
13146
+ g_param_spec_boolean ("is-virtual",
13147
+ "is virtual stream",
13148
+ "Whether the stream is virtual",
13150
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
13151
+ g_object_class_install_property (gobject_class,
13153
+ g_param_spec_string ("port",
13155
+ "The name of the current port for this stream",
13157
+ G_PARAM_READWRITE));
13158
+ g_object_class_install_property (gobject_class,
13160
+ g_param_spec_long ("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));
13169
+gvc_mixer_stream_init (GvcMixerStream *stream)
13171
+ stream->priv = GVC_MIXER_STREAM_GET_PRIVATE (stream);
13175
+free_port (GvcMixerStreamPort *p)
13177
+ g_free (p->port);
13178
+ g_free (p->human_port);
13183
+gvc_mixer_stream_finalize (GObject *object)
13185
+ GvcMixerStream *mixer_stream;
13187
+ g_return_if_fail (object != NULL);
13188
+ g_return_if_fail (GVC_IS_MIXER_STREAM (object));
13190
+ mixer_stream = GVC_MIXER_STREAM (object);
13192
+ g_return_if_fail (mixer_stream->priv != NULL);
13194
+ g_object_unref (mixer_stream->priv->channel_map);
13195
+ mixer_stream->priv->channel_map = NULL;
13197
+ g_free (mixer_stream->priv->name);
13198
+ mixer_stream->priv->name = NULL;
13200
+ g_free (mixer_stream->priv->description);
13201
+ mixer_stream->priv->description = NULL;
13203
+ g_free (mixer_stream->priv->application_id);
13204
+ mixer_stream->priv->application_id = NULL;
13206
+ g_free (mixer_stream->priv->icon_name);
13207
+ mixer_stream->priv->icon_name = NULL;
13209
+ g_free (mixer_stream->priv->port);
13210
+ mixer_stream->priv->port = NULL;
13212
+ g_free (mixer_stream->priv->human_port);
13213
+ mixer_stream->priv->human_port = NULL;
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;
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;
13224
+ G_OBJECT_CLASS (gvc_mixer_stream_parent_class)->finalize (object);
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
13231
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
13233
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
13251
+#ifndef __GVC_MIXER_STREAM_H
13252
+#define __GVC_MIXER_STREAM_H
13254
+#include <glib-object.h>
13255
+#include "gvc-pulseaudio-fake.h"
13256
+#include "gvc-channel-map.h"
13257
+#include <gio/gio.h>
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))
13268
+typedef struct GvcMixerStreamPrivate GvcMixerStreamPrivate;
13273
+ GvcMixerStreamPrivate *priv;
13278
+ GObjectClass parent_class;
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;
13292
+ char *human_port;
13294
+ gboolean available;
13295
+} GvcMixerStreamPort;
13297
+GType gvc_mixer_stream_get_type (void);
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);
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);
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);
13327
+gboolean gvc_mixer_stream_set_volume (GvcMixerStream *stream,
13328
+ pa_volume_t volume);
13329
+gboolean gvc_mixer_stream_set_decibel (GvcMixerStream *stream,
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,
13353
+gboolean gvc_mixer_stream_set_card_index (GvcMixerStream *stream,
13354
+ gint card_index);
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
13364
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
13366
+ * gvc-mixer-ui-device.c
13367
+ * Copyright (C) Conor Curran 2011 <conor.curran@canonical.com>
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.
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.
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/>.
13383
+#include <string.h>
13384
+#include "gvc-mixer-ui-device.h"
13385
+#include "gvc-mixer-card.h"
13387
+#define GVC_MIXER_UI_DEVICE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GVC_TYPE_MIXER_UI_DEVICE, GvcMixerUIDevicePrivate))
13389
+static guint32 output_serial = 1;
13391
+struct GvcMixerUIDevicePrivate
13393
+ gchar* first_line_desc;
13394
+ gchar* second_line_desc;
13396
+ gchar* port_name;
13399
+ gboolean port_available;
13400
+ GList* supported_profiles;
13401
+ UiDeviceDirection type;
13402
+ GHashTable* profiles;
13403
+ gboolean disable_profile_swapping;
13404
+ gchar* user_preferred_profile;
13410
+ PROP_DESC_LINE_1,
13411
+ PROP_DESC_LINE_2,
13415
+ PROP_UI_DEVICE_TYPE,
13416
+ PROP_PORT_AVAILABLE,
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);
13423
+G_DEFINE_TYPE (GvcMixerUIDevice, gvc_mixer_ui_device, G_TYPE_OBJECT);
13426
+get_next_output_serial (void)
13430
+ serial = output_serial++;
13432
+ if ((gint32)output_serial < 0) {
13433
+ output_serial = 1;
13439
+gvc_mixer_ui_device_get_property (GObject *object,
13440
+ guint property_id,
13442
+ GParamSpec *pspec)
13444
+ GvcMixerUIDevice *self = GVC_MIXER_UI_DEVICE (object);
13446
+ switch (property_id)
13448
+ case PROP_DESC_LINE_1:
13449
+ g_value_set_string (value, self->priv->first_line_desc);
13451
+ case PROP_DESC_LINE_2:
13452
+ g_value_set_string (value, self->priv->second_line_desc);
13454
+ case PROP_CARD_ID:
13455
+ g_value_set_int (value, self->priv->card_id);
13457
+ case PROP_PORT_NAME:
13458
+ g_value_set_string (value, self->priv->port_name);
13460
+ case PROP_STREAM_ID:
13461
+ g_value_set_int (value, self->priv->stream_id);
13463
+ case PROP_UI_DEVICE_TYPE:
13464
+ g_value_set_uint (value, (guint)self->priv->type);
13466
+ case PROP_PORT_AVAILABLE:
13467
+ g_value_set_boolean (value, self->priv->port_available);
13470
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
13476
+gvc_mixer_ui_device_set_property (GObject *object,
13477
+ guint property_id,
13478
+ const GValue *value,
13479
+ GParamSpec *pspec)
13481
+ GvcMixerUIDevice *self = GVC_MIXER_UI_DEVICE (object);
13483
+ switch (property_id)
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);
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);
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);
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);
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);
13513
+ case PROP_UI_DEVICE_TYPE:
13514
+ self->priv->type = (UiDeviceDirection)g_value_get_uint (value);
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));
13522
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
13528
+gvc_mixer_ui_device_constructor (GType type,
13529
+ guint n_construct_properties,
13530
+ GObjectConstructParam *construct_params)
13533
+ GvcMixerUIDevice *self;
13535
+ object = G_OBJECT_CLASS (gvc_mixer_ui_device_parent_class)->constructor (type, n_construct_properties, construct_params);
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,
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;
13552
+gvc_mixer_ui_device_init (GvcMixerUIDevice *object)
13554
+ object->priv = GVC_MIXER_UI_DEVICE_GET_PRIVATE (object);
13558
+gvc_mixer_ui_device_dispose (GObject *object)
13560
+ g_return_if_fail (object != NULL);
13561
+ g_return_if_fail (GVC_MIXER_UI_DEVICE (object));
13563
+ GvcMixerUIDevice *device;
13564
+ device = GVC_MIXER_UI_DEVICE (object);
13566
+ if (device->priv->port_name != NULL){
13567
+ g_free (device->priv->port_name);
13568
+ device->priv->port_name = NULL;
13570
+ if (device->priv->first_line_desc != NULL){
13571
+ g_free (device->priv->first_line_desc);
13572
+ device->priv->first_line_desc = NULL;
13574
+ if (device->priv->second_line_desc != NULL){
13575
+ g_free (device->priv->second_line_desc);
13576
+ device->priv->second_line_desc = NULL;
13578
+ if (device->priv->profiles != NULL){
13579
+ g_hash_table_destroy (device->priv->profiles);
13580
+ device->priv->profiles = NULL;
13582
+ if (device->priv->user_preferred_profile != NULL){
13583
+ g_free (device->priv->user_preferred_profile);
13584
+ device->priv->user_preferred_profile = NULL;
13586
+ G_OBJECT_CLASS (gvc_mixer_ui_device_parent_class)->dispose (object);
13590
+gvc_mixer_ui_device_finalize (GObject *object)
13592
+ G_OBJECT_CLASS (gvc_mixer_ui_device_parent_class)->finalize (object);
13596
+gvc_mixer_ui_device_class_init (GvcMixerUIDeviceClass *klass)
13598
+ GObjectClass* object_class = G_OBJECT_CLASS (klass);
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;
13606
+ GParamSpec *pspec;
13608
+ pspec = g_param_spec_string ("description",
13609
+ "Description construct prop",
13610
+ "Set first line description",
13612
+ G_PARAM_READWRITE);
13613
+ g_object_class_install_property (object_class,
13614
+ PROP_DESC_LINE_1,
13617
+ pspec = g_param_spec_string ("origin",
13618
+ "origin construct prop",
13619
+ "Set second line description name",
13621
+ G_PARAM_READWRITE);
13622
+ g_object_class_install_property (object_class,
13623
+ PROP_DESC_LINE_2,
13626
+ pspec = g_param_spec_int ("card-id",
13627
+ "Card id from pulse",
13628
+ "Set/Get card id",
13631
+ GVC_MIXER_UI_DEVICE_INVALID,
13632
+ G_PARAM_READWRITE);
13634
+ g_object_class_install_property (object_class,
13638
+ pspec = g_param_spec_string ("port-name",
13639
+ "port-name construct prop",
13642
+ G_PARAM_READWRITE);
13643
+ g_object_class_install_property (object_class,
13647
+ pspec = g_param_spec_int ("stream-id",
13648
+ "stream id assigned by gvc-stream",
13649
+ "Set/Get stream id",
13652
+ GVC_MIXER_UI_DEVICE_INVALID,
13653
+ G_PARAM_READWRITE);
13654
+ g_object_class_install_property (object_class,
13658
+ pspec = g_param_spec_uint ("type",
13659
+ "ui-device type",
13660
+ "determine whether its an input and output",
13664
+ G_PARAM_READWRITE);
13665
+ g_object_class_install_property (object_class,
13666
+ PROP_UI_DEVICE_TYPE,
13669
+ pspec = g_param_spec_boolean ( "port-available",
13671
+ "determine whether this port is available",
13673
+ G_PARAM_READWRITE);
13674
+ g_object_class_install_property (object_class,
13675
+ PROP_PORT_AVAILABLE,
13678
+ g_type_class_add_private (klass, sizeof (GvcMixerUIDevicePrivate));
13682
+ gvc_mixer_ui_device_set_profiles (GvcMixerUIDevice *device, const GList *in_profiles)
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.
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.
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)
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.
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 ...
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
13723
+get_profile_canonical_name(const gchar *profile_name, const gchar *skip_prefix)
13725
+ gchar *result = g_strdup(profile_name);
13726
+ gchar *c = result;
13729
+ /* Find '\0' or past next '+' */
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);
13746
+ result = newresult;
13753
+ /* Cut a final '+' off */
13754
+ if (g_str_has_suffix(result, "+"))
13755
+ result[strlen(result)-1] = '\0';
13761
+gvc_mixer_ui_device_get_matching_profile (GvcMixerUIDevice *device, const gchar *profile)
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;
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;
13775
+ g_free(canonical_name);
13778
+ g_free(target_cname);
13779
+ g_debug("Matching profile for '%s' is '%s'", profile, result ? result : "(null)");
13784
+/** gvc_mixer_ui_device_set_profiles
13785
+ @param in_profiles a list of GvcMixerCardProfile
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)
13792
+gvc_mixer_ui_device_set_profiles (GvcMixerUIDevice *device, const GList *in_profiles)
13794
+ g_debug ("=== SET PROFILES === '%s'", gvc_mixer_ui_device_get_description(device));
13797
+ GHashTable *profile_descriptions;
13798
+ GHashTable *added_profiles;
13799
+ int only_canonical;
13800
+ gchar *skip_prefix = device->priv->type == UiDeviceInput ? "output:" : "input:";
13802
+ if (in_profiles == NULL)
13805
+ device->priv->supported_profiles = g_list_copy ((GList*) in_profiles);
13807
+ added_profiles = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
13809
+ /* Run two iterations: First, add profiles which are canonical themselves,
13810
+ Second, add profiles for which the canonical name is not added already
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);
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);
13824
+ if (only_canonical && strcmp(p->profile, canonical_name)) {
13825
+ g_free(canonical_name);
13829
+ g_free(canonical_name);
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);
13837
+ /* TODO: Consider adding the "Off" profile here */
13839
+ device->priv->disable_profile_swapping = g_hash_table_size(added_profiles) <= 1;
13841
+ g_hash_table_destroy(added_profiles);
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
13852
+gvc_mixer_ui_device_get_best_profile (GvcMixerUIDevice *device, const gchar *selected,
13853
+const gchar *current)
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;
13861
+ /* First make a list of profiles acceptable to switch to */
13863
+ canonical_name_selected = get_profile_canonical_name(selected, skip_prefix);
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);
13874
+ if (!candidates) {
13875
+ g_warning("No suitable profile candidates for '%s'", selected ? selected : "(null)");
13876
+ g_free(canonical_name_selected);
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;
13887
+ /* 2) Try to keep the other side unchanged if possible */
13888
+ if (result == NULL) {
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;
13900
+ g_free(p_reverse);
13902
+ g_free(current_reverse);
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) {
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;
13919
+ g_list_free(candidates);
13920
+ g_free(canonical_name_selected);
13926
+gvc_mixer_ui_device_should_profiles_be_hidden (GvcMixerUIDevice *device)
13928
+ return device->priv->disable_profile_swapping;
13932
+gvc_mixer_ui_device_get_profiles (GvcMixerUIDevice *device)
13934
+ return device->priv->profiles;
13938
+gvc_mixer_ui_device_get_supported_profiles (GvcMixerUIDevice *device)
13940
+ return device->priv->supported_profiles;
13944
+gvc_mixer_ui_device_get_id (GvcMixerUIDevice *op)
13946
+ g_return_val_if_fail (GVC_IS_MIXER_UI_DEVICE (op), 0);
13947
+ return op->priv->id;
13951
+gvc_mixer_ui_device_get_stream_id (GvcMixerUIDevice *op)
13954
+ g_object_get (G_OBJECT (op),
13955
+ "stream-id", &sink_id, NULL);
13960
+gvc_mixer_ui_device_invalidate_stream (GvcMixerUIDevice *self)
13962
+ self->priv->stream_id = GVC_MIXER_UI_DEVICE_INVALID;
13967
+gvc_mixer_ui_device_get_description (GvcMixerUIDevice *op)
13969
+ return op->priv->first_line_desc;
13973
+gvc_mixer_ui_device_get_origin (GvcMixerUIDevice *op)
13975
+ return op->priv->second_line_desc;
13979
+gvc_mixer_ui_device_get_user_preferred_profile (GvcMixerUIDevice *dev)
13981
+ return dev->priv->user_preferred_profile;
13985
+gvc_mixer_ui_device_get_top_priority_profile (GvcMixerUIDevice *dev)
13988
+ last = g_list_last (dev->priv->supported_profiles);
13989
+ GvcMixerCardProfile *profile;
13990
+ profile = last->data;
13991
+ return profile->profile;
13995
+gvc_mixer_ui_device_set_user_preferred_profile (GvcMixerUIDevice *device, const gchar* profile)
13997
+ if (device->priv->user_preferred_profile != NULL){
13998
+ g_free (device->priv->user_preferred_profile);
13999
+ device->priv->user_preferred_profile = NULL;
14001
+ device->priv->user_preferred_profile = g_strdup (profile);
14005
+gvc_mixer_ui_device_get_port (GvcMixerUIDevice *op)
14007
+ return op->priv->port_name;
14011
+gvc_mixer_ui_device_is_software (GvcMixerUIDevice *dev)
14013
+ return dev->priv->port_name == NULL && dev->priv->card_id == GVC_MIXER_UI_DEVICE_INVALID;
14017
+gvc_mixer_ui_device_is_bluetooth (GvcMixerUIDevice *dev)
14019
+ return dev->priv->port_name == NULL && dev->priv->card_id != GVC_MIXER_UI_DEVICE_INVALID;
14023
+gvc_mixer_ui_device_is_output (GvcMixerUIDevice *dev)
14025
+ return dev->priv->type == UiDeviceOutput;
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
14033
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
14035
+ * Copyright (C) Conor Curran 2011 <conor.curran@canonical.com>
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.
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.
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/>.
14051
+#ifndef _GVC_MIXER_UI_DEVICE_H_
14052
+#define _GVC_MIXER_UI_DEVICE_H_
14054
+#include <glib-object.h>
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
14067
+typedef struct GvcMixerUIDevicePrivate GvcMixerUIDevicePrivate;
14071
+ GObjectClass parent_class;
14072
+}GvcMixerUIDeviceClass;
14076
+ GObject parent_instance;
14077
+ GvcMixerUIDevicePrivate *priv;
14078
+}GvcMixerUIDevice;
14084
+}UiDeviceDirection;
14086
+GType gvc_mixer_ui_device_get_type (void) G_GNUC_CONST;
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);
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
14114
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
14116
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
14134
+#ifndef __GVC_PULSEAUDIO_FAKE_H
14135
+#define __GVC_PULSEAUDIO_FAKE_H
14137
+#ifdef WITH_INTROSPECTION
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 */
14145
+#endif /* WITH_INTROSPECTION */
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
14153
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
14155
+ * Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
14156
+ * Copyright (C) 2008 William Jon McCann
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.
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.
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.
14174
+#include "config.h"
14176
+#include <stdlib.h>
14177
+#include <stdio.h>
14178
+#include <unistd.h>
14179
+#include <utime.h>
14180
+#include <errno.h>
14183
+#include <glib/gi18n-lib.h>
14184
+#include <gtk/gtk.h>
14185
+#include <canberra-gtk.h>
14186
+#include <libxml/tree.h>
14188
+#include <gsettings-desktop-schemas/gdesktop-enums.h>
14190
+#include "gvc-sound-theme-chooser.h"
14191
+#include "sound-theme-file-utils.h"
14193
+#define GVC_SOUND_THEME_CHOOSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_SOUND_THEME_CHOOSER, GvcSoundThemeChooserPrivate))
14195
+struct GvcSoundThemeChooserPrivate
14197
+ GtkWidget *treeview;
14198
+ GtkWidget *selection_box;
14199
+ GSettings *settings;
14200
+ GSettings *sound_settings;
14201
+ char *current_theme;
14202
+ char *current_parent;
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);
14209
+G_DEFINE_TYPE (GvcSoundThemeChooser, gvc_sound_theme_chooser, GTK_TYPE_VBOX)
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"
14216
+#define WM_SCHEMA "org.gnome.desktop.wm.preferences"
14217
+#define AUDIO_BELL_KEY "audible-bell"
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"
14225
+ THEME_DISPLAY_COL,
14226
+ THEME_IDENTIFIER_COL,
14227
+ THEME_PARENT_ID_COL,
14232
+ ALERT_DISPLAY_COL,
14233
+ ALERT_IDENTIFIER_COL,
14234
+ ALERT_SOUND_TYPE_COL,
14239
+ SOUND_TYPE_UNSET,
14241
+ SOUND_TYPE_DEFAULT_FROM_THEME,
14242
+ SOUND_TYPE_BUILTIN,
14243
+ SOUND_TYPE_CUSTOM
14246
+#define GVC_SOUND_SOUND (xmlChar *) "sound"
14247
+#define GVC_SOUND_NAME (xmlChar *) "name"
14248
+#define GVC_SOUND_FILENAME (xmlChar *) "filename"
14250
+/* Adapted from yelp-toc-pager.c */
14252
+xml_get_and_trim_names (xmlNodePtr node)
14255
+ xmlChar *keep_lang = NULL;
14257
+ int j, keep_pri = INT_MAX;
14259
+ const gchar * const * langs = g_get_language_names ();
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;
14268
+ cur_lang = xmlNodeGetLang (cur);
14271
+ for (j = 0; langs[j]; j++) {
14272
+ if (g_str_equal (cur_lang, langs[j])) {
14278
+ cur_pri = INT_MAX - 1;
14281
+ if (cur_pri <= keep_pri) {
14283
+ xmlFree (keep_lang);
14287
+ value = xmlNodeGetContent (cur);
14289
+ keep_lang = cur_lang;
14290
+ keep_pri = cur_pri;
14293
+ xmlFree (cur_lang);
14298
+ /* Delete all GVC_SOUND_NAME nodes */
14299
+ cur = node->children;
14301
+ xmlNodePtr this = cur;
14303
+ if (! xmlStrcmp (this->name, GVC_SOUND_NAME)) {
14304
+ xmlUnlinkNode (this);
14305
+ xmlFreeNode (this);
14313
+populate_model_from_node (GvcSoundThemeChooser *chooser,
14314
+ GtkTreeModel *model,
14317
+ xmlNodePtr child;
14318
+ xmlChar *filename;
14322
+ name = xml_get_and_trim_names (node);
14323
+ for (child = node->children; child; child = child->next) {
14324
+ if (xmlNodeIsText (child)) {
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 */
14335
+ if (filename != NULL && name != NULL) {
14336
+ gtk_list_store_insert_with_values (GTK_LIST_STORE (model),
14339
+ ALERT_IDENTIFIER_COL, filename,
14340
+ ALERT_DISPLAY_COL, name,
14341
+ ALERT_SOUND_TYPE_COL, _("Built-in"),
14345
+ xmlFree (filename);
14350
+populate_model_from_file (GvcSoundThemeChooser *chooser,
14351
+ GtkTreeModel *model,
14352
+ const char *filename)
14356
+ xmlNodePtr child;
14359
+ exists = g_file_test (filename, G_FILE_TEST_EXISTS);
14364
+ doc = xmlParseFile (filename);
14365
+ if (doc == NULL) {
14369
+ root = xmlDocGetRootElement (doc);
14371
+ for (child = root->children; child; child = child->next) {
14372
+ if (xmlNodeIsText (child)) {
14375
+ if (xmlStrcmp (child->name, GVC_SOUND_SOUND) != 0) {
14379
+ populate_model_from_node (chooser, model, child);
14382
+ xmlFreeDoc (doc);
14386
+populate_model_from_dir (GvcSoundThemeChooser *chooser,
14387
+ GtkTreeModel *model,
14388
+ const char *dirname)
14391
+ const char *name;
14393
+ d = g_dir_open (dirname, 0, NULL);
14398
+ while ((name = g_dir_read_name (d)) != NULL) {
14401
+ if (! g_str_has_suffix (name, ".xml")) {
14405
+ path = g_build_filename (dirname, name, NULL);
14406
+ populate_model_from_file (chooser, model, path);
14412
+save_alert_sounds (GvcSoundThemeChooser *chooser,
14415
+ const char *sounds[3] = { "bell-terminal", "bell-window-system", NULL };
14418
+ if (strcmp (id, DEFAULT_ALERT_ID) == 0) {
14419
+ delete_old_files (sounds);
14420
+ delete_disabled_files (sounds);
14422
+ delete_old_files (sounds);
14423
+ delete_disabled_files (sounds);
14424
+ add_custom_file (sounds, id);
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));
14440
+update_alert_model (GvcSoundThemeChooser *chooser,
14443
+ GtkTreeModel *model;
14444
+ GtkTreeIter iter;
14446
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (chooser->priv->treeview));
14447
+ gtk_tree_model_get_iter_first (model, &iter);
14451
+ gtk_tree_model_get (model, &iter,
14452
+ ALERT_IDENTIFIER_COL, &this_id,
14455
+ if (strcmp (this_id, id) == 0) {
14456
+ GtkTreeSelection *selection;
14458
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (chooser->priv->treeview));
14459
+ gtk_tree_selection_select_iter (selection, &iter);
14462
+ g_free (this_id);
14463
+ } while (gtk_tree_model_iter_next (model, &iter));
14467
+save_theme_name (GvcSoundThemeChooser *chooser,
14468
+ const char *theme_name)
14470
+ /* If the name is empty, use "freedesktop" */
14471
+ if (theme_name == NULL || *theme_name == '\0') {
14472
+ theme_name = DEFAULT_THEME;
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);
14480
+ g_settings_set_boolean (chooser->priv->sound_settings, EVENT_SOUNDS_KEY, TRUE);
14483
+ g_settings_set_string (chooser->priv->sound_settings, SOUND_THEME_KEY, theme_name);
14487
+load_theme_file (const char *path,
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);
14498
+ /* Don't add hidden themes to the list */
14499
+ hidden = g_key_file_get_boolean (file, "Sound Theme", "Hidden", NULL);
14501
+ /* Save the parent theme, if there's one */
14502
+ if (parent != NULL) {
14503
+ *parent = g_key_file_get_string (file,
14510
+ g_key_file_free (file);
14516
+load_theme_name (const char *name,
14519
+ const char * const *data_dirs;
14520
+ const char *data_dir;
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);
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);
14545
+update_alert (GvcSoundThemeChooser *chooser,
14546
+ const char *alert_id)
14548
+ gboolean is_custom;
14549
+ gboolean is_default;
14550
+ gboolean add_custom;
14551
+ gboolean remove_custom;
14553
+ is_custom = strcmp (chooser->priv->current_theme, CUSTOM_THEME_NAME) == 0;
14554
+ is_default = strcmp (alert_id, DEFAULT_ALERT_ID) == 0;
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
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);
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;
14580
+ } else if (is_custom && ! is_default) {
14581
+ save_alert_sounds (chooser, alert_id);
14584
+ if (add_custom) {
14585
+ save_theme_name (chooser, CUSTOM_THEME_NAME);
14586
+ } else if (remove_custom) {
14587
+ delete_custom_theme_dir ();
14589
+ save_theme_name (chooser, chooser->priv->current_parent);
14593
+ update_alert_model (chooser, alert_id);
14597
+play_preview_for_id (GvcSoundThemeChooser *chooser,
14600
+ g_return_if_fail (id != NULL);
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",
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",
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",
14645
+on_treeview_selection_changed (GtkTreeSelection *selection,
14646
+ GvcSoundThemeChooser *chooser)
14648
+ GtkTreeModel *model;
14649
+ GtkTreeIter iter;
14652
+ if (chooser->priv->treeview == NULL) {
14656
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (chooser->priv->treeview));
14658
+ if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) {
14663
+ gtk_tree_model_get (model, &iter,
14664
+ ALERT_IDENTIFIER_COL, &id,
14666
+ if (id == NULL) {
14670
+ play_preview_for_id (chooser, id);
14671
+ update_alert (chooser, id);
14676
+on_treeview_button_pressed (GtkTreeView *treeview,
14677
+ GdkEventButton *event,
14678
+ GvcSoundThemeChooser *chooser)
14680
+ GtkTreeSelection *selection;
14681
+ GtkTreePath *path;
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) {
14689
+ if (gtk_tree_selection_path_is_selected (selection, path) == FALSE) {
14690
+ gtk_tree_path_free (path);
14693
+ gtk_tree_path_free (path);
14695
+ on_treeview_selection_changed (selection, chooser);
14700
+static GtkWidget *
14701
+create_alert_treeview (GvcSoundThemeChooser *chooser)
14703
+ GtkListStore *store;
14704
+ GtkWidget *treeview;
14705
+ GtkCellRenderer *renderer;
14706
+ GtkTreeViewColumn *column;
14707
+ GtkTreeSelection *selection;
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),
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,
14720
+ G_CALLBACK (on_treeview_selection_changed),
14723
+ /* Setup the tree model, 3 columns:
14728
+ store = gtk_list_store_new (ALERT_NUM_COLS,
14733
+ gtk_list_store_insert_with_values (store,
14736
+ ALERT_IDENTIFIER_COL, DEFAULT_ALERT_ID,
14737
+ ALERT_DISPLAY_COL, _("Default"),
14738
+ ALERT_SOUND_TYPE_COL, _("From theme"),
14741
+ populate_model_from_dir (chooser, GTK_TREE_MODEL (store), SOUND_SET_DIR);
14743
+ gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
14744
+ GTK_TREE_MODEL (store));
14746
+ renderer = gtk_cell_renderer_text_new ();
14747
+ column = gtk_tree_view_column_new_with_attributes (_("Name"),
14749
+ "text", ALERT_DISPLAY_COL,
14751
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
14757
+get_file_type (const char *sound_name,
14758
+ char **linked_name)
14760
+ char *name, *filename;
14762
+ *linked_name = NULL;
14764
+ name = g_strdup_printf ("%s.disabled", sound_name);
14765
+ filename = custom_theme_dir_path (name);
14768
+ if (g_file_test (filename, G_FILE_TEST_IS_REGULAR) != FALSE) {
14769
+ g_free (filename);
14770
+ return SOUND_TYPE_OFF;
14772
+ g_free (filename);
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);
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;
14785
+ g_free (filename);
14787
+ return SOUND_TYPE_BUILTIN;
14791
+update_alerts_from_theme_name (GvcSoundThemeChooser *chooser,
14792
+ const char *name)
14794
+ if (strcmp (name, CUSTOM_THEME_NAME) != 0) {
14795
+ /* reset alert to default */
14796
+ update_alert (chooser, DEFAULT_ALERT_ID);
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);
14811
+update_theme (GvcSoundThemeChooser *chooser)
14813
+ gboolean events_enabled;
14814
+ char *last_theme;
14816
+ events_enabled = g_settings_get_boolean (chooser->priv->sound_settings, EVENT_SOUNDS_KEY);
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);
14822
+ chooser->priv->current_theme = g_strdup (NO_SOUNDS_THEME_NAME);
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);
14835
+ g_free (last_theme);
14837
+ gtk_widget_set_sensitive (chooser->priv->selection_box, events_enabled);
14839
+ update_alerts_from_theme_name (chooser, chooser->priv->current_theme);
14843
+gvc_sound_theme_chooser_constructor (GType type,
14844
+ guint n_construct_properties,
14845
+ GObjectConstructParam *construct_params)
14848
+ GvcSoundThemeChooser *self;
14850
+ object = G_OBJECT_CLASS (gvc_sound_theme_chooser_parent_class)->constructor (type, n_construct_properties, construct_params);
14852
+ self = GVC_SOUND_THEME_CHOOSER (object);
14854
+ update_theme (self);
14860
+gvc_sound_theme_chooser_class_init (GvcSoundThemeChooserClass *klass)
14862
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
14864
+ object_class->constructor = gvc_sound_theme_chooser_constructor;
14865
+ object_class->finalize = gvc_sound_theme_chooser_finalize;
14867
+ g_type_class_add_private (klass, sizeof (GvcSoundThemeChooserPrivate));
14871
+on_sound_settings_changed (GSettings *settings,
14873
+ GvcSoundThemeChooser *chooser)
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);
14885
+on_audible_bell_changed (GSettings *settings,
14887
+ GvcSoundThemeChooser *chooser)
14889
+ update_theme (chooser);
14893
+setup_list_size_constraint (GtkWidget *widget,
14894
+ GtkWidget *to_size)
14896
+ GtkRequisition req;
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;
14902
+ gtk_widget_get_preferred_size (to_size, NULL, &req);
14904
+ gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (widget),
14905
+ MIN (req.height, max_height));
14909
+gvc_sound_theme_chooser_init (GvcSoundThemeChooser *chooser)
14912
+ GtkWidget *label;
14913
+ GtkWidget *scrolled_window;
14914
+ GtkWidget *alignment;
14917
+ chooser->priv = GVC_SOUND_THEME_CHOOSER_GET_PRIVATE (chooser);
14919
+ chooser->priv->settings = g_settings_new (WM_SCHEMA);
14920
+ chooser->priv->sound_settings = g_settings_new (KEY_SOUNDS_SCHEMA);
14922
+ str = g_strdup_printf ("<b>%s</b>", _("C_hoose an alert sound:"));
14923
+ chooser->priv->selection_box = box = gtk_frame_new (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);
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);
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);
14939
+ chooser->priv->treeview = create_alert_treeview (chooser);
14940
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), chooser->priv->treeview);
14942
+ scrolled_window = gtk_scrolled_window_new (NULL, NULL);
14943
+ setup_list_size_constraint (scrolled_window, chooser->priv->treeview);
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),
14950
+ gtk_container_add (GTK_CONTAINER (scrolled_window), chooser->priv->treeview);
14951
+ gtk_container_add (GTK_CONTAINER (alignment), scrolled_window);
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);
14960
+gvc_sound_theme_chooser_finalize (GObject *object)
14962
+ GvcSoundThemeChooser *sound_theme_chooser;
14964
+ g_return_if_fail (object != NULL);
14965
+ g_return_if_fail (GVC_IS_SOUND_THEME_CHOOSER (object));
14967
+ sound_theme_chooser = GVC_SOUND_THEME_CHOOSER (object);
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);
14974
+ G_OBJECT_CLASS (gvc_sound_theme_chooser_parent_class)->finalize (object);
14978
+gvc_sound_theme_chooser_new (void)
14980
+ GObject *chooser;
14981
+ chooser = g_object_new (GVC_TYPE_SOUND_THEME_CHOOSER,
14984
+ return GTK_WIDGET (chooser);
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
14991
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
14993
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
15011
+#ifndef __GVC_SOUND_THEME_CHOOSER_H
15012
+#define __GVC_SOUND_THEME_CHOOSER_H
15014
+#include <glib-object.h>
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))
15025
+typedef struct GvcSoundThemeChooserPrivate GvcSoundThemeChooserPrivate;
15030
+ GvcSoundThemeChooserPrivate *priv;
15031
+} GvcSoundThemeChooser;
15035
+ GtkVBoxClass parent_class;
15036
+} GvcSoundThemeChooserClass;
15038
+GType gvc_sound_theme_chooser_get_type (void);
15040
+GtkWidget * gvc_sound_theme_chooser_new (void);
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
15050
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
15052
+ * Copyright (C) 2009 Bastien Nocera
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.
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.
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.
15070
+#include "config.h"
15072
+#include <stdlib.h>
15073
+#include <stdio.h>
15074
+#include <unistd.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>
15083
+#include "gvc-speaker-test.h"
15084
+#include "gvc-mixer-stream.h"
15085
+/* #include "gvc-mixer-card.h" */
15087
+#define GVC_SPEAKER_TEST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_SPEAKER_TEST, GvcSpeakerTestPrivate))
15089
+struct GvcSpeakerTestPrivate
15091
+ GtkWidget *channel_controls[PA_CHANNEL_POSITION_MAX];
15092
+ ca_context *canberra;
15093
+ GvcMixerStream *stream;
15094
+ GvcMixerControl *control;
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);
15114
+G_DEFINE_TYPE (GvcSpeakerTest, gvc_speaker_test, GTK_TYPE_TABLE)
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
15133
+gvc_speaker_test_set_property (GObject *object,
15135
+ const GValue *value,
15136
+ GParamSpec *pspec)
15138
+ GvcSpeakerTest *self = GVC_SPEAKER_TEST (object);
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);
15146
+ case PROP_CONTROL:
15147
+ self->priv->control = g_value_dup_object (value);
15148
+ if (self->priv->stream != NULL)
15149
+ update_channel_map (self);
15152
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
15158
+gvc_speaker_test_get_property (GObject *object,
15161
+ GParamSpec *pspec)
15163
+ GvcSpeakerTest *self = GVC_SPEAKER_TEST (object);
15165
+ switch (prop_id) {
15166
+ case PROP_STREAM:
15167
+ g_value_set_object (value, self->priv->stream);
15169
+ case PROP_CONTROL:
15170
+ g_value_set_object (value, self->priv->control);
15173
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
15179
+gvc_speaker_test_class_init (GvcSpeakerTestClass *klass)
15181
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
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;
15187
+ g_object_class_install_property (object_class,
15189
+ g_param_spec_object ("stream",
15192
+ GVC_TYPE_MIXER_STREAM,
15193
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
15194
+ g_object_class_install_property (object_class,
15196
+ g_param_spec_object ("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));
15204
+static const char *
15205
+sound_name (pa_channel_position_t position)
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";
15231
+static const char *
15232
+icon_name (pa_channel_position_t position, gboolean playing)
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";
15259
+update_button (GtkWidget *control)
15261
+ GtkWidget *button;
15262
+ GtkWidget *image;
15263
+ pa_channel_position_t position;
15264
+ gboolean playing;
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);
15274
+static const char *
15275
+pretty_position (pa_channel_position_t position)
15277
+ if (position == PA_CHANNEL_POSITION_LFE)
15278
+ return N_("Subwoofer");
15280
+ return pa_channel_position_to_pretty_string (position);
15284
+idle_cb (GtkWidget *control)
15286
+ if (control == NULL)
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);
15298
+finish_cb (ca_context *c, uint32_t id, int error_code, void *userdata)
15300
+ GtkWidget *control = (GtkWidget *) userdata;
15302
+ if (error_code == CA_ERROR_DESTROYED || control == NULL)
15304
+ g_idle_add ((GSourceFunc) idle_cb, control);
15308
+on_test_button_clicked (GtkButton *button,
15309
+ GtkWidget *control)
15311
+ gboolean playing;
15312
+ ca_context *canberra;
15314
+ canberra = g_object_get_data (G_OBJECT (control), "canberra");
15316
+ ca_context_cancel (canberra, 1);
15318
+ playing = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (control), "playing"));
15321
+ g_object_set_data (G_OBJECT (control), "playing", GINT_TO_POINTER(FALSE));
15323
+ pa_channel_position_t position;
15324
+ const char *name;
15325
+ ca_proplist *proplist;
15327
+ position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (control), "position"));
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");
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;
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;
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;
15351
+ g_object_set_data (G_OBJECT (control), "playing", GINT_TO_POINTER(playing));
15354
+ update_button (control);
15357
+static GtkWidget *
15358
+channel_control_new (ca_context *canberra, pa_channel_position_t position)
15360
+ GtkWidget *control;
15362
+ GtkWidget *label;
15363
+ GtkWidget *image;
15364
+ GtkWidget *test_button;
15365
+ const char *name;
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);
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);
15379
+ label = gtk_label_new (pretty_position (position));
15380
+ gtk_box_pack_start (GTK_BOX (control), label, FALSE, FALSE, 0);
15382
+ test_button = gtk_button_new_with_label (_("Test"));
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);
15388
+ atk_object_add_relationship (gtk_widget_get_accessible (test_button),
15389
+ ATK_RELATION_LABELLED_BY,
15390
+ gtk_widget_get_accessible (label));
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);
15396
+ gtk_widget_show_all (control);
15402
+create_channel_controls (GvcSpeakerTest *speaker_test)
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);
15419
+static const GvcChannelMap *
15420
+get_channel_map_for_card (GvcMixerControl *control,
15421
+ GvcMixerCard *card,
15422
+ char **output_name)
15425
+ GSList *sinks, *l;
15426
+ GvcMixerStream *stream;
15427
+ const GvcChannelMap *map;
15429
+ /* This gets the channel map for the only
15430
+ * output for the card */
15432
+ card_index = gvc_mixer_card_get_index (card);
15433
+ if (card_index == PA_INVALID_INDEX)
15435
+ sinks = gvc_mixer_control_get_sinks (control);
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);
15444
+ g_slist_free (sinks);
15446
+ if (stream == NULL)
15449
+ g_debug ("Found stream '%s' for card '%s'",
15450
+ gvc_mixer_stream_get_name (stream),
15451
+ gvc_mixer_card_get_name (card));
15453
+ *output_name = g_strdup (gvc_mixer_stream_get_name (stream));
15454
+ map = gvc_mixer_stream_get_channel_map (stream);
15456
+ g_debug ("Got channel map '%s' for port '%s'",
15457
+ gvc_channel_map_get_mapping (map), *output_name);
15464
+update_channel_map (GvcSpeakerTest *speaker_test)
15467
+ const GvcChannelMap *map;
15468
+ char *output_name;
15470
+ g_return_if_fail (speaker_test->priv->control != NULL);
15471
+ g_return_if_fail (speaker_test->priv->stream != NULL);
15473
+ g_debug ("XXX update_channel_map called XXX");
15475
+ map = gvc_mixer_stream_get_channel_map (speaker_test->priv->stream);
15477
+ map = get_channel_map_for_stream (speaker_test->priv->control,
15478
+ speaker_test->priv->stream,
15481
+ g_return_if_fail (map != NULL);
15483
+ ca_context_change_device (speaker_test->priv->canberra,
15484
+ gvc_mixer_stream_get_name (speaker_test->priv->stream));
15485
+ g_free (output_name);
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]));
15494
+gvc_speaker_test_set_theme (ca_context *ca)
15496
+ GtkSettings *settings;
15497
+ char *theme_name;
15499
+ settings = gtk_settings_get_for_screen (gdk_screen_get_default ());
15501
+ g_object_get (G_OBJECT (settings),
15502
+ "gtk-sound-theme-name", &theme_name,
15506
+ ca_context_change_props (ca, CA_PROP_CANBERRA_XDG_THEME_NAME, theme_name, NULL);
15508
+ g_free (theme_name);
15512
+gvc_speaker_test_init (GvcSpeakerTest *speaker_test)
15516
+ speaker_test->priv = GVC_SPEAKER_TEST_GET_PRIVATE (speaker_test);
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",
15523
+ gvc_speaker_test_set_theme (speaker_test->priv->canberra);
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);
15532
+ create_channel_controls (speaker_test);
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);
15541
+gvc_speaker_test_finalize (GObject *object)
15543
+ GvcSpeakerTest *speaker_test;
15545
+ g_return_if_fail (object != NULL);
15546
+ g_return_if_fail (GVC_IS_SPEAKER_TEST (object));
15548
+ speaker_test = GVC_SPEAKER_TEST (object);
15550
+ g_return_if_fail (speaker_test->priv != NULL);
15552
+ g_object_unref (speaker_test->priv->stream);
15553
+ speaker_test->priv->stream = NULL;
15555
+ g_object_unref (speaker_test->priv->control);
15556
+ speaker_test->priv->control = NULL;
15558
+ ca_context_destroy (speaker_test->priv->canberra);
15559
+ speaker_test->priv->canberra = NULL;
15561
+ G_OBJECT_CLASS (gvc_speaker_test_parent_class)->finalize (object);
15565
+gvc_speaker_test_new (GvcMixerControl *control,
15566
+ GvcMixerStream *stream)
15568
+ GObject *speaker_test;
15570
+ g_return_val_if_fail (stream != NULL, NULL);
15571
+ g_return_val_if_fail (control != NULL, NULL);
15573
+ speaker_test = g_object_new (GVC_TYPE_SPEAKER_TEST,
15574
+ "stream", stream,
15575
+ "control", control,
15578
+ return GTK_WIDGET (speaker_test);
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
15586
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
15588
+ * Copyright (C) 2009 Red Hat, Inc.
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.
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.
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.
15606
+#ifndef __GVC_SPEAKER_TEST_H
15607
+#define __GVC_SPEAKER_TEST_H
15609
+#include <glib-object.h>
15610
+#include <gvc-mixer-card.h>
15611
+#include <gvc-mixer-control.h>
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))
15622
+typedef struct GvcSpeakerTestPrivate GvcSpeakerTestPrivate;
15626
+ GtkNotebook parent;
15627
+ GvcSpeakerTestPrivate *priv;
15632
+ GtkNotebookClass parent_class;
15633
+} GvcSpeakerTestClass;
15635
+GType gvc_speaker_test_get_type (void);
15637
+GtkWidget * gvc_speaker_test_new (GvcMixerControl *control,
15638
+ GvcMixerStream *stream);
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
15648
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
15650
+ * Copyright (C) 2008 William Jon McCann
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.
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.
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.
15668
+#include "config.h"
15670
+#include <stdlib.h>
15671
+#include <stdio.h>
15672
+#include <unistd.h>
15675
+#include <glib/gi18n.h>
15676
+#include <gdk/gdkkeysyms.h>
15677
+#include <gtk/gtk.h>
15678
+#include <pulse/pulseaudio.h>
15680
+#include "gvc-mixer-stream.h"
15681
+#include "gvc-channel-bar.h"
15682
+#include "gvc-stream-status-icon.h"
15684
+#define GVC_STREAM_STATUS_ICON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_STREAM_STATUS_ICON, GvcStreamStatusIconPrivate))
15686
+struct GvcStreamStatusIconPrivate
15688
+ char **icon_names;
15689
+ GvcMixerStream *mixer_stream;
15692
+ guint current_icon;
15693
+ char *display_name;
15700
+ PROP_DISPLAY_NAME,
15701
+ PROP_MIXER_STREAM,
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);
15709
+G_DEFINE_TYPE (GvcStreamStatusIcon, gvc_stream_status_icon, GTK_TYPE_STATUS_ICON)
15712
+on_adjustment_value_changed (GtkAdjustment *adjustment,
15713
+ GvcStreamStatusIcon *icon)
15717
+ if (icon->priv->thaw)
15720
+ volume = gtk_adjustment_get_value (adjustment);
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);
15730
+update_dock (GvcStreamStatusIcon *icon)
15732
+ GtkAdjustment *adj;
15733
+ gboolean is_muted;
15735
+ g_return_if_fail (icon);
15737
+ adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (icon->priv->bar)));
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;
15748
+popup_dock (GvcStreamStatusIcon *icon,
15751
+ GdkRectangle area;
15752
+ GtkOrientation orientation;
15753
+ GdkDisplay *display;
15754
+ GdkScreen *screen;
15759
+ GdkRectangle monitor;
15760
+ GtkRequisition dock_req;
15762
+ update_dock (icon);
15764
+ screen = gtk_status_icon_get_screen (GTK_STATUS_ICON (icon));
15765
+ res = gtk_status_icon_get_geometry (GTK_STATUS_ICON (icon),
15770
+ g_warning ("Unable to determine geometry of status icon");
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);
15779
+ monitor_num = gdk_screen_get_monitor_at_point (screen, area.x, area.y);
15780
+ gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
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);
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;
15790
+ x = area.x - dock_req.width;
15792
+ if (area.y + dock_req.height <= monitor.y + monitor.height) {
15795
+ y = monitor.y + monitor.height - dock_req.height;
15798
+ if (area.y + area.height + dock_req.height <= monitor.y + monitor.height) {
15799
+ y = area.y + area.height;
15801
+ y = area.y - dock_req.height;
15803
+ if (area.x + dock_req.width <= monitor.x + monitor.width) {
15806
+ x = monitor.x + monitor.width - dock_req.width;
15810
+ gtk_window_move (GTK_WINDOW (icon->priv->dock), x, y);
15812
+ /* FIXME: without this, the popup window appears as a square
15813
+ * after changing the orientation
15815
+ gtk_window_resize (GTK_WINDOW (icon->priv->dock), 1, 1);
15817
+ gtk_widget_show_all (icon->priv->dock);
15820
+ gtk_grab_add (icon->priv->dock);
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,
15826
+ != GDK_GRAB_SUCCESS) {
15827
+ gtk_grab_remove (icon->priv->dock);
15828
+ gtk_widget_hide (icon->priv->dock);
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);
15840
+ gtk_widget_grab_focus (icon->priv->dock);
15846
+on_status_icon_activate (GtkStatusIcon *status_icon,
15847
+ GvcStreamStatusIcon *icon)
15849
+ popup_dock (icon, GDK_CURRENT_TIME);
15853
+on_menu_mute_toggled (GtkMenuItem *item,
15854
+ GvcStreamStatusIcon *icon)
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);
15862
+on_menu_activate_open_volume_control (GtkMenuItem *item,
15863
+ GvcStreamStatusIcon *icon)
15866
+ GdkAppLaunchContext *context;
15870
+ context = gdk_app_launch_context_new ();
15871
+ app = g_app_info_create_from_commandline ("gnome-control-center sound", "Sound preferences", 0, &error);
15873
+ g_app_info_launch (app, NULL, G_APP_LAUNCH_CONTEXT (context), &error);
15875
+ if (error != NULL) {
15876
+ GtkWidget *dialog;
15878
+ dialog = gtk_message_dialog_new (NULL,
15880
+ GTK_MESSAGE_ERROR,
15881
+ GTK_BUTTONS_CLOSE,
15882
+ _("Failed to start Sound Preferences: %s"),
15884
+ g_signal_connect (dialog,
15886
+ G_CALLBACK (gtk_widget_destroy),
15888
+ gtk_widget_show (dialog);
15889
+ g_error_free (error);
15892
+ g_object_unref (context);
15893
+ g_object_unref (app);
15897
+on_status_icon_popup_menu (GtkStatusIcon *status_icon,
15899
+ guint activate_time,
15900
+ GvcStreamStatusIcon *icon)
15904
+ GtkWidget *image;
15906
+ menu = gtk_menu_new ();
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,
15913
+ G_CALLBACK (on_menu_mute_toggled),
15915
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
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,
15923
+ G_CALLBACK (on_menu_activate_open_volume_control),
15925
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
15927
+ gtk_widget_show_all (menu);
15928
+ gtk_menu_popup (GTK_MENU (menu),
15931
+ gtk_status_icon_position_menu,
15938
+on_status_icon_scroll_event (GtkStatusIcon *status_icon,
15939
+ GdkEventScroll *event,
15940
+ GvcStreamStatusIcon *icon)
15942
+ return gvc_channel_bar_scroll (GVC_CHANNEL_BAR (icon->priv->bar), event);
15946
+gvc_icon_release_grab (GvcStreamStatusIcon *icon,
15947
+ GdkEventButton *event)
15949
+ GdkDisplay *display;
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);
15958
+ gtk_widget_hide (icon->priv->dock);
15962
+on_dock_button_press (GtkWidget *widget,
15963
+ GdkEventButton *event,
15964
+ GvcStreamStatusIcon *icon)
15966
+ if (event->type == GDK_BUTTON_PRESS) {
15967
+ gvc_icon_release_grab (icon, event);
15975
+popdown_dock (GvcStreamStatusIcon *icon)
15977
+ GdkDisplay *display;
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);
15986
+ gtk_widget_hide (icon->priv->dock);
15990
+on_dock_key_release (GtkWidget *widget,
15991
+ GdkEventKey *event,
15992
+ GvcStreamStatusIcon *icon)
15994
+ if (event->keyval == GDK_KEY_Escape) {
15995
+ popdown_dock (icon);
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);
16009
+on_dock_scroll_event (GtkWidget *widget,
16010
+ GdkEventScroll *event,
16011
+ GvcStreamStatusIcon *icon)
16013
+ /* Forward event to the status icon */
16014
+ on_status_icon_scroll_event (NULL, event, icon);
16019
+update_icon (GvcStreamStatusIcon *icon)
16022
+ gboolean is_muted;
16025
+ gboolean can_decibel;
16028
+ if (icon->priv->mixer_stream == NULL) {
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);
16037
+ /* select image */
16038
+ if (volume <= 0 || is_muted) {
16041
+ n = 3 * volume / PA_VOLUME_NORM + 1;
16044
+ } else if (n > 3) {
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;
16059
+ markup = g_strdup_printf (
16060
+ "<b>%s: %s</b>\n<small>%s</small>",
16061
+ icon->priv->display_name,
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,
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>-∞ 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));
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));
16084
+ gtk_status_icon_set_tooltip_markup (GTK_STATUS_ICON (icon), markup);
16089
+gvc_stream_status_icon_set_icon_names (GvcStreamStatusIcon *icon,
16090
+ const char **names)
16092
+ g_return_if_fail (GVC_IS_STREAM_STATUS_ICON (icon));
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");
16101
+on_stream_volume_notify (GObject *object,
16102
+ GParamSpec *pspec,
16103
+ GvcStreamStatusIcon *icon)
16105
+ update_icon (icon);
16106
+ update_dock (icon);
16110
+on_stream_is_muted_notify (GObject *object,
16111
+ GParamSpec *pspec,
16112
+ GvcStreamStatusIcon *icon)
16114
+ update_icon (icon);
16115
+ update_dock (icon);
16119
+gvc_stream_status_icon_set_display_name (GvcStreamStatusIcon *icon,
16120
+ const char *name)
16122
+ g_return_if_fail (GVC_STREAM_STATUS_ICON (icon));
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");
16131
+gvc_stream_status_icon_set_mixer_stream (GvcStreamStatusIcon *icon,
16132
+ GvcMixerStream *stream)
16134
+ g_return_if_fail (GVC_STREAM_STATUS_ICON (icon));
16136
+ if (stream != NULL) {
16137
+ g_object_ref (stream);
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),
16144
+ g_signal_handlers_disconnect_by_func (icon->priv->mixer_stream,
16145
+ G_CALLBACK (on_stream_is_muted_notify),
16147
+ g_object_unref (icon->priv->mixer_stream);
16148
+ icon->priv->mixer_stream = NULL;
16151
+ icon->priv->mixer_stream = stream;
16153
+ if (icon->priv->mixer_stream != NULL) {
16154
+ GtkAdjustment *adj;
16156
+ g_object_ref (icon->priv->mixer_stream);
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;
16164
+ g_signal_connect (icon->priv->mixer_stream,
16165
+ "notify::volume",
16166
+ G_CALLBACK (on_stream_volume_notify),
16168
+ g_signal_connect (icon->priv->mixer_stream,
16169
+ "notify::is-muted",
16170
+ G_CALLBACK (on_stream_is_muted_notify),
16174
+ update_icon (icon);
16176
+ g_object_notify (G_OBJECT (icon), "mixer-stream");
16180
+gvc_stream_status_icon_set_property (GObject *object,
16182
+ const GValue *value,
16183
+ GParamSpec *pspec)
16185
+ GvcStreamStatusIcon *self = GVC_STREAM_STATUS_ICON (object);
16187
+ switch (prop_id) {
16188
+ case PROP_MIXER_STREAM:
16189
+ gvc_stream_status_icon_set_mixer_stream (self, g_value_get_object (value));
16191
+ case PROP_DISPLAY_NAME:
16192
+ gvc_stream_status_icon_set_display_name (self, g_value_get_string (value));
16194
+ case PROP_ICON_NAMES:
16195
+ gvc_stream_status_icon_set_icon_names (self, g_value_get_boxed (value));
16198
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
16204
+gvc_stream_status_icon_get_property (GObject *object,
16207
+ GParamSpec *pspec)
16209
+ GvcStreamStatusIcon *self = GVC_STREAM_STATUS_ICON (object);
16210
+ GvcStreamStatusIconPrivate *priv = self->priv;
16212
+ switch (prop_id) {
16213
+ case PROP_MIXER_STREAM:
16214
+ g_value_set_object (value, priv->mixer_stream);
16216
+ case PROP_DISPLAY_NAME:
16217
+ g_value_set_string (value, priv->display_name);
16219
+ case PROP_ICON_NAMES:
16220
+ g_value_set_boxed (value, priv->icon_names);
16223
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
16229
+on_bar_is_muted_notify (GObject *object,
16230
+ GParamSpec *pspec,
16231
+ GvcStreamStatusIcon *icon)
16233
+ gboolean is_muted;
16235
+ is_muted = gvc_channel_bar_get_is_muted (GVC_CHANNEL_BAR (object));
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,
16246
+gvc_stream_status_icon_constructor (GType type,
16247
+ guint n_construct_properties,
16248
+ GObjectConstructParam *construct_params)
16251
+ GvcStreamStatusIcon *icon;
16252
+ GtkWidget *frame;
16254
+ GtkAdjustment *adj;
16256
+ object = G_OBJECT_CLASS (gvc_stream_status_icon_parent_class)->constructor (type, n_construct_properties, construct_params);
16258
+ icon = GVC_STREAM_STATUS_ICON (object);
16260
+ gtk_status_icon_set_from_icon_name (GTK_STATUS_ICON (icon),
16261
+ icon->priv->icon_names[0]);
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),
16270
+ g_signal_connect (icon->priv->dock,
16271
+ "key-release-event",
16272
+ G_CALLBACK (on_dock_key_release),
16274
+ g_signal_connect (icon->priv->dock,
16276
+ G_CALLBACK (on_dock_scroll_event),
16279
+ gtk_window_set_decorated (GTK_WINDOW (icon->priv->dock), FALSE);
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);
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);
16289
+ icon->priv->bar = gvc_channel_bar_new ();
16290
+ gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (icon->priv->bar),
16291
+ GTK_ORIENTATION_VERTICAL);
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),
16299
+ adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (icon->priv->bar)));
16300
+ g_signal_connect (adj,
16302
+ G_CALLBACK (on_adjustment_value_changed),
16309
+gvc_stream_status_icon_dispose (GObject *object)
16311
+ GvcStreamStatusIcon *icon = GVC_STREAM_STATUS_ICON (object);
16313
+ if (icon->priv->dock != NULL) {
16314
+ gtk_widget_destroy (icon->priv->dock);
16315
+ icon->priv->dock = NULL;
16318
+ if (icon->priv->mixer_stream != NULL) {
16319
+ g_object_unref (icon->priv->mixer_stream);
16320
+ icon->priv->mixer_stream = NULL;
16323
+ G_OBJECT_CLASS (gvc_stream_status_icon_parent_class)->dispose (object);
16327
+gvc_stream_status_icon_class_init (GvcStreamStatusIconClass *klass)
16329
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
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;
16337
+ g_object_class_install_property (object_class,
16338
+ PROP_MIXER_STREAM,
16339
+ g_param_spec_object ("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",
16348
+ "Name to display for this stream",
16350
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
16351
+ g_object_class_install_property (object_class,
16353
+ g_param_spec_boxed ("icon-names",
16355
+ "Name of icon to display for this stream",
16357
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
16359
+ g_type_class_add_private (klass, sizeof (GvcStreamStatusIconPrivate));
16363
+on_status_icon_visible_notify (GvcStreamStatusIcon *icon)
16365
+ gboolean visible;
16367
+ g_object_get (icon, "visible", &visible, NULL);
16369
+ if (icon->priv->dock != NULL) {
16370
+ gtk_widget_hide (icon->priv->dock);
16376
+gvc_stream_status_icon_init (GvcStreamStatusIcon *icon)
16378
+ icon->priv = GVC_STREAM_STATUS_ICON_GET_PRIVATE (icon);
16380
+ g_signal_connect (icon,
16382
+ G_CALLBACK (on_status_icon_activate),
16384
+ g_signal_connect (icon,
16386
+ G_CALLBACK (on_status_icon_popup_menu),
16388
+ g_signal_connect (icon,
16390
+ G_CALLBACK (on_status_icon_scroll_event),
16392
+ g_signal_connect (icon,
16393
+ "notify::visible",
16394
+ G_CALLBACK (on_status_icon_visible_notify),
16397
+ icon->priv->thaw = FALSE;
16401
+gvc_stream_status_icon_finalize (GObject *object)
16403
+ GvcStreamStatusIcon *stream_status_icon;
16405
+ g_return_if_fail (object != NULL);
16406
+ g_return_if_fail (GVC_IS_STREAM_STATUS_ICON (object));
16408
+ stream_status_icon = GVC_STREAM_STATUS_ICON (object);
16410
+ g_return_if_fail (stream_status_icon->priv != NULL);
16412
+ g_strfreev (stream_status_icon->priv->icon_names);
16414
+ G_OBJECT_CLASS (gvc_stream_status_icon_parent_class)->finalize (object);
16417
+GvcStreamStatusIcon *
16418
+gvc_stream_status_icon_new (GvcMixerStream *stream,
16419
+ const char **icon_names)
16422
+ icon = g_object_new (GVC_TYPE_STREAM_STATUS_ICON,
16423
+ "mixer-stream", stream,
16424
+ "icon-names", icon_names,
16426
+ return GVC_STREAM_STATUS_ICON (icon);
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
16433
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
16435
+ * Copyright (C) 2008 Red Hat, Inc.
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.
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.
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.
16453
+#ifndef __GVC_STREAM_STATUS_ICON_H
16454
+#define __GVC_STREAM_STATUS_ICON_H
16456
+#include <glib-object.h>
16457
+#include "gvc-mixer-stream.h"
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))
16468
+typedef struct GvcStreamStatusIconPrivate GvcStreamStatusIconPrivate;
16472
+ GtkStatusIcon parent;
16473
+ GvcStreamStatusIconPrivate *priv;
16474
+} GvcStreamStatusIcon;
16478
+ GtkStatusIconClass parent_class;
16479
+} GvcStreamStatusIconClass;
16481
+GType gvc_stream_status_icon_get_type (void);
16483
+GvcStreamStatusIcon * gvc_stream_status_icon_new (GvcMixerStream *stream,
16484
+ const char **icon_names);
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);
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
16501
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
16502
+ * Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
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.
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.
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.
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>
16527
+#include "sound-theme-file-utils.h"
16529
+#define CUSTOM_THEME_NAME "__custom"
16531
+/* This function needs to be called after each individual
16532
+ * changeset to the theme */
16534
+custom_theme_update_time (void)
16538
+ path = custom_theme_dir_path (NULL);
16539
+ utime (path, NULL);
16544
+custom_theme_dir_path (const char *child)
16546
+ static char *dir = NULL;
16547
+ const char *data_dir;
16549
+ if (dir == NULL) {
16550
+ data_dir = g_get_user_data_dir ();
16551
+ dir = g_build_filename (data_dir, "sounds", CUSTOM_THEME_NAME, NULL);
16553
+ if (child == NULL)
16554
+ return g_strdup (dir);
16556
+ return g_build_filename (dir, child, NULL);
16560
+directory_delete_recursive (GFile *directory, GError **error)
16562
+ GFileEnumerator *enumerator;
16564
+ gboolean success = TRUE;
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,
16571
+ if (enumerator == NULL)
16574
+ while (success &&
16575
+ (info = g_file_enumerator_next_file (enumerator, NULL, NULL))) {
16578
+ child = g_file_get_child (directory, g_file_info_get_name (info));
16580
+ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
16581
+ success = directory_delete_recursive (child, error);
16583
+ g_object_unref (info);
16586
+ success = g_file_delete (child, NULL, error);
16588
+ g_file_enumerator_close (enumerator, NULL, NULL);
16591
+ success = g_file_delete (directory, NULL, error);
16597
+ * capplet_file_delete_recursive :
16601
+ * A utility routine to delete files and/or directories,
16602
+ * including non-empty directories.
16605
+capplet_file_delete_recursive (GFile *file, GError **error)
16610
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
16612
+ info = g_file_query_info (file,
16613
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
16614
+ G_FILE_QUERY_INFO_NONE,
16616
+ if (info == NULL)
16619
+ type = g_file_info_get_file_type (info);
16620
+ g_object_unref (info);
16622
+ if (type == G_FILE_TYPE_DIRECTORY)
16623
+ return directory_delete_recursive (file, error);
16625
+ return g_file_delete (file, NULL, error);
16629
+delete_custom_theme_dir (void)
16634
+ dir = custom_theme_dir_path (NULL);
16635
+ file = g_file_new_for_path (dir);
16637
+ capplet_file_delete_recursive (file, NULL);
16638
+ g_object_unref (file);
16640
+ g_debug ("deleted the custom theme dir");
16644
+custom_theme_dir_is_empty (void)
16648
+ gboolean is_empty;
16649
+ GFileEnumerator *enumerator;
16651
+ GError *error = NULL;
16653
+ dir = custom_theme_dir_path (NULL);
16654
+ file = g_file_new_for_path (dir);
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,
16664
+ if (enumerator == NULL) {
16665
+ g_warning ("Unable to enumerate files: %s", error->message);
16666
+ g_error_free (error);
16670
+ while (is_empty &&
16671
+ (info = g_file_enumerator_next_file (enumerator, NULL, NULL))) {
16673
+ if (strcmp ("index.theme", g_file_info_get_name (info)) != 0) {
16674
+ is_empty = FALSE;
16677
+ g_object_unref (info);
16679
+ g_file_enumerator_close (enumerator, NULL, NULL);
16682
+ g_object_unref (file);
16688
+delete_one_file (const char *sound_name, const char *pattern)
16691
+ char *name, *filename;
16693
+ name = g_strdup_printf (pattern, sound_name);
16694
+ filename = custom_theme_dir_path (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);
16703
+delete_old_files (const char **sounds)
16707
+ for (i = 0; sounds[i] != NULL; i++) {
16708
+ delete_one_file (sounds[i], "%s.ogg");
16713
+delete_disabled_files (const char **sounds)
16717
+ for (i = 0; sounds[i] != NULL; i++)
16718
+ delete_one_file (sounds[i], "%s.disabled");
16722
+create_one_file (GFile *file)
16724
+ GFileOutputStream* stream;
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);
16734
+add_disabled_file (const char **sounds)
16738
+ for (i = 0; sounds[i] != NULL; i++) {
16740
+ char *name, *filename;
16742
+ name = g_strdup_printf ("%s.disabled", sounds[i]);
16743
+ filename = custom_theme_dir_path (name);
16745
+ file = g_file_new_for_path (filename);
16746
+ g_free (filename);
16748
+ create_one_file (file);
16749
+ g_object_unref (file);
16754
+add_custom_file (const char **sounds, const char *filename)
16758
+ for (i = 0; sounds[i] != NULL; i++) {
16760
+ char *name, *path;
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);
16767
+ /* In case there's already a link there, delete it */
16769
+ file = g_file_new_for_path (path);
16772
+ /* Create the link */
16773
+ g_file_make_symbolic_link (file, filename, NULL, NULL);
16774
+ g_object_unref (file);
16779
+create_custom_theme (const char *parent)
16781
+ GKeyFile *keyfile;
16785
+ /* Create the custom directory */
16786
+ path = custom_theme_dir_path (NULL);
16787
+ g_mkdir_with_parents (path, 0755);
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);
16798
+ /* Save the index.theme */
16799
+ path = custom_theme_dir_path ("index.theme");
16800
+ g_file_set_contents (path, data, -1, NULL);
16804
+ custom_theme_update_time ();
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
16811
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
16812
+ * Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
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.
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.
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.
16829
+#ifndef __SOUND_THEME_FILE_UTILS_HH__
16830
+#define __SOUND_THEME_FILE_UTILS_HH__
16832
+#include <gio/gio.h>
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);
16838
+void delete_custom_theme_dir (void);
16839
+void delete_old_files (const char **sounds);
16840
+void delete_disabled_files (const char **sounds);
16842
+void add_disabled_file (const char **sounds);
16843
+void add_custom_file (const char **sounds, const char *filename);
16845
+void custom_theme_update_time (void);
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
16855
Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel;
16856
-OnlyShowIn=GNOME;Unity;
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 @@
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);
16873
+ cc_shell_set_active_panel_from_id (shell, "sound", NULL, NULL);
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 @@
16883
GnomeControlCenterPrivate *priv = GNOME_CONTROL_CENTER (shell)->priv;
16885
+ if (!g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity") &&
16886
+ !g_strcmp0(start_id, "sound"))
16887
+ start_id = "sound-nua";
16889
/* clear any custom widgets */
16890
_shell_remove_all_custom_widgets (priv);