1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3
* Copyright (C) 2008 William Jon McCann
4
* Copyright (C) 2012 Conor Curran
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30
#include <glib/gi18n-lib.h>
31
#include <gdk/gdkkeysyms.h>
33
#include <pulse/pulseaudio.h>
36
#include "gvc-channel-bar.h"
37
#include "gvc-balance-bar.h"
38
#include "gvc-combo-box.h"
39
#include "gvc-mixer-control.h"
40
#include "gvc-mixer-card.h"
41
#include "gvc-mixer-ui-device.h"
42
#include "gvc-mixer-sink.h"
43
#include "gvc-mixer-source.h"
44
#include "gvc-mixer-source-output.h"
45
#include "gvc-mixer-dialog.h"
46
#include "gvc-sound-theme-chooser.h"
47
#include "gvc-level-bar.h"
48
#include "gvc-speaker-test.h"
49
#include "gvc-mixer-control-private.h"
51
#define SCALE_SIZE 128
53
#define GVC_MIXER_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_DIALOG, GvcMixerDialogPrivate))
55
struct GvcMixerDialogPrivate
57
GvcMixerControl *mixer_control;
60
GtkWidget *output_bar;
62
GtkWidget *input_level_bar;
63
GtkWidget *effects_bar;
64
GtkWidget *output_stream_box;
65
GtkWidget *sound_effects_box;
67
GtkWidget *hw_treeview;
68
GtkWidget *hw_settings_box;
69
GtkWidget *hw_profile_combo;
71
GtkWidget *output_box;
72
GtkWidget *applications_box;
73
GtkWidget *no_apps_label;
74
GtkWidget *output_treeview;
75
GtkWidget *output_settings_box;
76
GtkWidget *output_balance_bar;
77
GtkWidget *output_fade_bar;
78
GtkWidget *output_lfe_bar;
79
GtkWidget *output_profile_combo;
80
GtkWidget *input_profile_combo;
81
GtkWidget *input_treeview;
82
GtkWidget *input_settings_box;
83
GtkWidget *sound_theme_chooser;
84
GtkWidget *click_feedback_button;
85
GtkWidget *audible_bell_button;
86
GtkSizeGroup *size_group;
87
GtkWidget *selected_output_label;
88
GtkWidget *selected_input_label;
89
GtkWidget *test_output_button;
90
GSettings *indicator_settings;
92
gdouble last_input_peak;
112
HW_PROFILE_HUMAN_COLUMN,
123
static void gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass);
124
static void gvc_mixer_dialog_init (GvcMixerDialog *mixer_dialog);
125
static void gvc_mixer_dialog_finalize (GObject *object);
127
static void bar_set_stream (GvcMixerDialog *dialog,
129
GvcMixerStream *stream);
131
static void on_adjustment_value_changed (GtkAdjustment *adjustment,
132
GvcMixerDialog *dialog);
133
static void on_control_output_added (GvcMixerControl *control,
135
GvcMixerDialog *dialog);
136
static void on_control_active_output_update (GvcMixerControl *control,
138
GvcMixerDialog *dialog);
140
static void on_control_active_input_update (GvcMixerControl *control,
142
GvcMixerDialog *dialog);
144
G_DEFINE_TYPE (GvcMixerDialog, gvc_mixer_dialog, GTK_TYPE_VBOX)
148
update_description (GvcMixerDialog *dialog,
151
GvcMixerStream *stream)
157
if (GVC_IS_MIXER_SOURCE (stream))
158
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
159
else if (GVC_IS_MIXER_SINK (stream))
160
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
162
g_assert_not_reached ();
164
if (gtk_tree_model_get_iter_first (model, &iter) == FALSE){
165
g_warning ("The tree is empty => Cannot update the description");
169
id = gvc_mixer_stream_get_id (stream);
173
gtk_tree_model_get (model, &iter,
174
ID_COLUMN, ¤t_id,
176
if (id != current_id)
179
gtk_list_store_set (GTK_LIST_STORE (model),
184
} while (gtk_tree_model_iter_next (model, &iter));
188
profile_selection_changed (GvcComboBox *combo_box,
190
GvcMixerDialog *dialog)
192
g_print ("profile_selection_changed - %s", profile);
193
GvcMixerUIDevice *out;
194
out = g_object_get_data (G_OBJECT (combo_box), "uidevice");
197
g_warning ("Could not find Output for profile combo box");
201
g_print (" \n on profile selection changed on output with \n description %s \n origin %s \n id %i \n \n",
202
gvc_mixer_ui_device_get_description (out),
203
gvc_mixer_ui_device_get_origin (out),
204
gvc_mixer_ui_device_get_id (out));
206
if (gvc_mixer_control_change_profile_on_selected_device (dialog->priv->mixer_control, out, profile) == FALSE) {
207
g_warning ("Could not change profile on device %s",
208
gvc_mixer_ui_device_get_description (out));
212
#define DECAY_STEP .15
215
update_input_peak (GvcMixerDialog *dialog,
220
if (dialog->priv->last_input_peak >= DECAY_STEP) {
221
if (v < dialog->priv->last_input_peak - DECAY_STEP) {
222
v = dialog->priv->last_input_peak - DECAY_STEP;
226
dialog->priv->last_input_peak = v;
228
adj = gvc_level_bar_get_peak_adjustment (GVC_LEVEL_BAR (dialog->priv->input_level_bar));
230
gtk_adjustment_set_value (adj, v);
232
gtk_adjustment_set_value (adj, 0.0);
237
update_input_meter (GvcMixerDialog *dialog,
238
uint32_t source_index,
239
uint32_t sink_input_idx,
242
update_input_peak (dialog, v);
246
on_monitor_suspended_callback (pa_stream *s,
249
GvcMixerDialog *dialog;
253
if (pa_stream_is_suspended (s)) {
254
g_debug ("Stream suspended");
255
update_input_meter (dialog,
256
pa_stream_get_device_index (s),
263
on_monitor_read_callback (pa_stream *s,
267
GvcMixerDialog *dialog;
273
if (pa_stream_peek (s, &data, &length) < 0) {
274
g_warning ("Failed to read data from stream");
279
assert (length % sizeof (float) == 0);
281
v = ((const float *) data)[length / sizeof (float) -1];
292
update_input_meter (dialog,
293
pa_stream_get_device_index (s),
294
pa_stream_get_monitor_stream (s),
299
create_monitor_stream_for_source (GvcMixerDialog *dialog,
300
GvcMixerStream *stream)
308
pa_proplist *proplist;
309
gboolean has_monitor;
311
if (stream == NULL) {
314
has_monitor = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (stream), "has-monitor"));
315
if (has_monitor != FALSE) {
319
g_debug ("Create monitor for %u",
320
gvc_mixer_stream_get_index (stream));
322
context = gvc_mixer_control_get_pa_context (dialog->priv->mixer_control);
324
if (pa_context_get_server_protocol_version (context) < 13) {
329
ss.format = PA_SAMPLE_FLOAT32;
332
memset (&attr, 0, sizeof (attr));
333
attr.fragsize = sizeof (float);
334
attr.maxlength = (uint32_t) -1;
336
snprintf (t, sizeof (t), "%u", gvc_mixer_stream_get_index (stream));
338
proplist = pa_proplist_new ();
339
pa_proplist_sets (proplist, PA_PROP_APPLICATION_ID, "org.gnome.VolumeControl");
340
s = pa_stream_new_with_proplist (context, _("Peak detect"), &ss, NULL, proplist);
341
pa_proplist_free (proplist);
343
g_warning ("Failed to create monitoring stream");
347
pa_stream_set_read_callback (s, on_monitor_read_callback, dialog);
348
pa_stream_set_suspended_callback (s, on_monitor_suspended_callback, dialog);
350
res = pa_stream_connect_record (s,
353
(pa_stream_flags_t) (PA_STREAM_DONT_MOVE
354
|PA_STREAM_PEAK_DETECT
355
|PA_STREAM_ADJUST_LATENCY));
357
g_warning ("Failed to connect monitoring stream");
360
g_object_set_data (G_OBJECT (stream), "has-monitor", GINT_TO_POINTER (TRUE));
361
g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream", s);
362
g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "stream", stream);
367
stop_monitor_stream_for_source (GvcMixerDialog *dialog)
372
GvcMixerStream *stream;
374
s = g_object_get_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream");
377
stream = g_object_get_data (G_OBJECT (dialog->priv->input_level_bar), "stream");
378
g_assert (stream != NULL);
380
g_debug ("Stopping monitor for %u", pa_stream_get_index (s));
382
context = gvc_mixer_control_get_pa_context (dialog->priv->mixer_control);
384
if (pa_context_get_server_protocol_version (context) < 13) {
388
res = pa_stream_disconnect (s);
390
g_object_set_data (G_OBJECT (stream), "has-monitor", GINT_TO_POINTER (FALSE));
391
g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream", NULL);
392
g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "stream", NULL);
396
gvc_mixer_dialog_set_mixer_control (GvcMixerDialog *dialog,
397
GvcMixerControl *control)
399
g_return_if_fail (GVC_MIXER_DIALOG (dialog));
400
g_return_if_fail (GVC_IS_MIXER_CONTROL (control));
402
g_object_ref (control);
404
if (dialog->priv->mixer_control != NULL) {
405
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
406
G_CALLBACK (on_control_active_output_update),
408
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
409
G_CALLBACK (on_control_active_input_update),
411
g_object_unref (dialog->priv->mixer_control);
414
dialog->priv->mixer_control = control;
416
g_signal_connect (dialog->priv->mixer_control,
417
"active-output-update",
418
G_CALLBACK (on_control_active_output_update),
420
g_signal_connect (dialog->priv->mixer_control,
421
"active-input-update",
422
G_CALLBACK (on_control_active_input_update),
425
g_object_notify (G_OBJECT (dialog), "mixer-control");
428
static GvcMixerControl *
429
gvc_mixer_dialog_get_mixer_control (GvcMixerDialog *dialog)
431
g_return_val_if_fail (GVC_IS_MIXER_DIALOG (dialog), NULL);
433
return dialog->priv->mixer_control;
437
gvc_mixer_dialog_set_property (GObject *object,
442
GvcMixerDialog *self = GVC_MIXER_DIALOG (object);
445
case PROP_MIXER_CONTROL:
446
gvc_mixer_dialog_set_mixer_control (self, g_value_get_object (value));
449
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
455
gvc_mixer_dialog_get_property (GObject *object,
460
GvcMixerDialog *self = GVC_MIXER_DIALOG (object);
463
case PROP_MIXER_CONTROL:
464
g_value_set_object (value, gvc_mixer_dialog_get_mixer_control (self));
467
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
473
on_adjustment_value_changed (GtkAdjustment *adjustment,
474
GvcMixerDialog *dialog)
476
GvcMixerStream *stream;
478
stream = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-stream");
479
if (stream != NULL) {
481
gdouble volume, rounded;
484
volume = gtk_adjustment_get_value (adjustment);
485
rounded = round (volume);
487
bar = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-bar");
488
g_object_get (bar, "name", &name, NULL);
489
g_debug ("Setting stream volume %lf (rounded: %lf) for bar '%s'", volume, rounded, name);
492
/* FIXME would need to do that in the balance bar really... */
493
/* Make sure we do not unmute muted streams, there's a button for that */
495
gvc_mixer_stream_set_is_muted (stream, TRUE);
496
/* Only push the volume if it's actually changed */
497
if (gvc_mixer_stream_set_volume(stream, (pa_volume_t) rounded) != FALSE)
498
gvc_mixer_stream_push_volume (stream);
503
on_bar_is_muted_notify (GObject *object,
505
GvcMixerDialog *dialog)
508
GvcMixerStream *stream;
510
is_muted = gvc_channel_bar_get_is_muted (GVC_CHANNEL_BAR (object));
512
stream = g_object_get_data (object, "gvc-mixer-dialog-stream");
513
if (stream != NULL) {
514
gvc_mixer_stream_change_is_muted (stream, is_muted);
517
g_object_get (object, "name", &name, NULL);
518
g_warning ("Unable to find stream for bar '%s'", name);
524
lookup_bar_for_stream (GvcMixerDialog *dialog,
525
GvcMixerStream *stream)
529
bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)));
536
// UI devices now pull description material mainly for the card ports.
537
// Therefore the need for stream description dynamic changes more than ever seems unneccessary.
539
on_stream_description_notify (GvcMixerStream *stream,
541
GvcMixerDialog *dialog)
543
update_description (dialog, NAME_COLUMN,
544
gvc_mixer_stream_get_description (stream),
549
on_stream_volume_notify (GObject *object,
551
GvcMixerDialog *dialog)
553
GvcMixerStream *stream;
556
stream = GVC_MIXER_STREAM (object);
558
bar = lookup_bar_for_stream (dialog, stream);
561
if (stream == gvc_mixer_control_get_default_sink(dialog->priv->mixer_control)) {
562
bar = dialog->priv->output_bar;
564
else if(stream == gvc_mixer_control_get_default_source(dialog->priv->mixer_control)) {
565
bar = dialog->priv->input_bar;
568
g_warning ("Unable to find bar for stream %s in on_stream_volume_notify()",
569
gvc_mixer_stream_get_name (stream));
574
adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
576
g_signal_handlers_block_by_func (adj,
577
on_adjustment_value_changed,
580
gtk_adjustment_set_value (adj,
581
gvc_mixer_stream_get_volume (stream));
583
g_signal_handlers_unblock_by_func (adj,
584
on_adjustment_value_changed,
589
on_stream_is_muted_notify (GObject *object,
591
GvcMixerDialog *dialog)
593
GvcMixerStream *stream;
597
stream = GVC_MIXER_STREAM (object);
599
bar = lookup_bar_for_stream (dialog, stream);
602
if (stream == gvc_mixer_control_get_default_sink(dialog->priv->mixer_control)) {
603
bar = dialog->priv->output_bar;
605
else if(stream == gvc_mixer_control_get_default_source(dialog->priv->mixer_control)) {
606
bar = dialog->priv->input_bar;
609
g_warning ("Unable to find bar for stream %s in on_stream_muted_notify()",
610
gvc_mixer_stream_get_name (stream));
616
is_muted = gvc_mixer_stream_get_is_muted (stream);
617
gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar),
620
if (stream == gvc_mixer_control_get_default_sink (dialog->priv->mixer_control)) {
621
gtk_widget_set_sensitive (dialog->priv->applications_box,
628
save_bar_for_stream (GvcMixerDialog *dialog,
629
GvcMixerStream *stream,
632
g_print ("\n saving bar for stream %s",
633
gvc_mixer_stream_get_name (stream));
634
g_hash_table_insert (dialog->priv->bars,
635
GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)),
640
create_bar (GvcMixerDialog *dialog,
641
gboolean add_to_size_group,
646
bar = gvc_channel_bar_new ();
647
gtk_widget_set_sensitive (bar, FALSE);
648
if (add_to_size_group && dialog->priv->size_group != NULL) {
649
gvc_channel_bar_set_size_group (GVC_CHANNEL_BAR (bar),
650
dialog->priv->size_group,
653
gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (bar),
654
GTK_ORIENTATION_HORIZONTAL);
655
gvc_channel_bar_set_show_mute (GVC_CHANNEL_BAR (bar),
657
g_signal_connect (bar,
659
G_CALLBACK (on_bar_is_muted_notify),
665
create_app_bar (GvcMixerDialog *dialog,
667
const char *icon_name)
671
bar = create_bar (dialog, FALSE, FALSE);
672
gvc_channel_bar_set_ellipsize (GVC_CHANNEL_BAR (bar), TRUE);
673
gvc_channel_bar_set_icon_name (GVC_CHANNEL_BAR (bar), icon_name);
674
if (name == NULL || strchr (name, '_') == NULL) {
675
gvc_channel_bar_set_name (GVC_CHANNEL_BAR (bar), name);
677
char **tokens, *escaped;
679
tokens = g_strsplit (name, "_", -1);
680
escaped = g_strjoinv ("__", tokens);
682
gvc_channel_bar_set_name (GVC_CHANNEL_BAR (bar), escaped);
689
/* active_input_update
690
* Handle input update change from the backend (control).
691
* Trust the backend whole-heartedly to deliver the correct input
695
active_input_update (GvcMixerDialog *dialog,
696
GvcMixerUIDevice *active_input)
698
g_print ("\n active_input_update %s \n", gvc_mixer_ui_device_get_description (active_input));
699
// First make sure the correct UI device is selected.
703
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
705
if (gtk_tree_model_get_iter_first (model, &iter) == FALSE){
706
g_warning ("The tree is empty => we have no devices so cannot set the active input");
711
gboolean is_selected = FALSE;
714
gtk_tree_model_get (model, &iter,
718
is_selected = id == gvc_mixer_ui_device_get_id (active_input);
720
gtk_list_store_set (GTK_LIST_STORE (model),
722
ACTIVE_COLUMN, is_selected,
726
GtkTreeSelection *selection;
727
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->input_treeview));
728
gtk_tree_selection_select_iter (selection, &iter);
731
}while (gtk_tree_model_iter_next (model, &iter));
733
stop_monitor_stream_for_source (dialog);
735
// Not ideal but for now destroy the combo and recreate below.
736
if (dialog->priv->input_profile_combo != NULL) {
737
gtk_container_remove (GTK_CONTAINER (dialog->priv->input_settings_box),
738
dialog->priv->input_profile_combo);
739
dialog->priv->input_profile_combo = NULL;
742
GvcMixerStream *stream;
743
const GvcChannelMap *map;
746
stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control,
748
if (stream == NULL) {
749
g_warning ("active_input_update - couldn't find a stream from the supposed active input");
750
gtk_widget_set_sensitive (dialog->priv->input_bar,
755
// Set the label accordingly
756
gtk_label_set_label (GTK_LABEL(dialog->priv->selected_input_label),
757
g_strdup_printf("Settings for %s",
758
gvc_mixer_ui_device_get_description (active_input)));
760
gvc_channel_bar_set_base_volume (GVC_CHANNEL_BAR (dialog->priv->input_bar),
761
gvc_mixer_stream_get_base_volume (stream));
762
gvc_channel_bar_set_is_amplified (GVC_CHANNEL_BAR (dialog->priv->input_bar),
763
gvc_mixer_stream_get_can_decibel (stream));
764
/* Update the adjustment in case the previous bar wasn't decibel
765
* capable, and we clipped it */
766
adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->input_bar)));
767
gtk_adjustment_set_value (adj,
768
gvc_mixer_stream_get_volume (stream));
770
create_monitor_stream_for_source (dialog, stream);
771
// remove any previous stream that might have been pointed at
772
// the static input bar and connect new signals from new stream.
773
bar_set_stream (dialog, dialog->priv->input_bar, stream);
775
const GHashTable *profs_entries;
776
profs_entries = gvc_mixer_ui_device_get_profiles (active_input);
778
const GList* profiles = NULL;
779
profiles = g_hash_table_get_values (profs_entries);
781
if (profiles != NULL){
782
dialog->priv->input_profile_combo = gvc_combo_box_new (_("Mode:"));
783
gvc_combo_box_set_profiles (GVC_COMBO_BOX (dialog->priv->input_profile_combo),
787
disabled = gvc_mixer_ui_device_determine_profile_sensitivity (active_input);
790
GvcMixerCardProfile *p;
791
// We can be sure that its just one profile in the list when it's disabled
792
p = g_list_last (profiles)->data;
793
gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->input_profile_combo),
797
gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->input_profile_combo),
798
gvc_mixer_control_get_active_profile_from_ui_device (dialog->priv->mixer_control,
801
g_object_set_data (G_OBJECT (dialog->priv->input_profile_combo),
805
g_signal_connect (G_OBJECT (dialog->priv->input_profile_combo), "changed",
806
G_CALLBACK (profile_selection_changed), dialog);
808
gtk_box_pack_start (GTK_BOX (dialog->priv->input_settings_box),
809
dialog->priv->input_profile_combo,
812
if (dialog->priv->size_group != NULL) {
813
gvc_combo_box_set_size_group (GVC_COMBO_BOX (dialog->priv->input_profile_combo),
814
dialog->priv->size_group, FALSE);
816
gtk_widget_show (dialog->priv->input_profile_combo);
817
gtk_widget_set_sensitive (dialog->priv->input_profile_combo,
822
/* active_output_update
823
* Handle output update change from the backend (control).
824
* Trust the backend whole heartedly to deliver the correct output
828
active_output_update (GvcMixerDialog *dialog,
829
GvcMixerUIDevice *active_output)
831
// First make sure the correct UI device is selected.
834
g_print ("\n\n active output update - device id = %i \n\n",
835
gvc_mixer_ui_device_get_id (active_output));
837
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
839
if (gtk_tree_model_get_iter_first (model, &iter) == FALSE){
840
g_warning ("The tree is empty => we have no devices in the tree => cannot set the active output");
845
gboolean is_selected;
848
gtk_tree_model_get (model, &iter,
850
ACTIVE_COLUMN, &is_selected,
853
if (is_selected && id == gvc_mixer_ui_device_get_id (active_output)) {
854
g_print ("\n\n unneccessary active output update unless it was a profile change on the same device ? \n\n");
857
is_selected = id == gvc_mixer_ui_device_get_id (active_output);
859
gtk_list_store_set (GTK_LIST_STORE (model),
861
ACTIVE_COLUMN, is_selected,
865
GtkTreeSelection *selection;
866
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->output_treeview));
867
gtk_tree_selection_select_iter (selection, &iter);
870
}while (gtk_tree_model_iter_next (model, &iter));
872
// Not ideal but for now destroy the combo and recreate below.
873
if (dialog->priv->output_profile_combo != NULL) {
874
gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box),
875
dialog->priv->output_profile_combo);
876
dialog->priv->output_profile_combo = NULL;
879
GvcMixerStream *stream;
880
const GvcChannelMap *map;
883
stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control,
886
if (stream == NULL) {
887
g_warning ("active_output_update - couldn't find a stream from the supposed active output");
891
gboolean is_muted = gvc_mixer_stream_get_is_muted (stream);
892
gtk_widget_set_sensitive (dialog->priv->applications_box,
894
adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->output_bar)));
895
g_signal_handlers_disconnect_by_func(adj, on_adjustment_value_changed, dialog);
897
bar_set_stream (dialog, dialog->priv->output_bar, stream);
898
gvc_channel_bar_set_base_volume (GVC_CHANNEL_BAR (dialog->priv->output_bar),
899
gvc_mixer_stream_get_base_volume (stream));
900
gvc_channel_bar_set_is_amplified (GVC_CHANNEL_BAR (dialog->priv->output_bar),
901
gvc_mixer_stream_get_can_decibel (stream));
902
/* Update the adjustment in case the previous bar wasn't decibel
903
* capable, and we clipped it */
904
adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->output_bar)));
905
gtk_adjustment_set_value (adj,
906
gvc_mixer_stream_get_volume (stream));
908
map = gvc_mixer_stream_get_channel_map (stream);
911
g_warning ("Active output stream has no channel map");
912
gtk_widget_set_sensitive (dialog->priv->output_bar, FALSE);
913
gtk_widget_set_sensitive (dialog->priv->output_balance_bar, FALSE);
914
gtk_widget_set_sensitive (dialog->priv->output_lfe_bar, FALSE);
915
gtk_widget_set_sensitive (dialog->priv->output_fade_bar, FALSE);
920
// Swap bars to the active map
921
gvc_balance_bar_set_map (GVC_BALANCE_BAR (dialog->priv->output_balance_bar),
923
gvc_balance_bar_set_map (GVC_BALANCE_BAR (dialog->priv->output_fade_bar),
925
gvc_balance_bar_set_map (GVC_BALANCE_BAR (dialog->priv->output_lfe_bar),
928
// Set sensitivities accordingly.
929
gtk_widget_set_sensitive (dialog->priv->output_balance_bar,
930
gvc_channel_map_can_balance (map));
931
gtk_widget_set_sensitive (dialog->priv->output_fade_bar,
932
gvc_channel_map_can_fade (map));
933
gtk_widget_set_sensitive (dialog->priv->output_lfe_bar,
934
gvc_channel_map_has_lfe (map));
935
gtk_widget_set_sensitive (dialog->priv->output_bar,
937
// Set the label accordingly
938
gtk_label_set_label (GTK_LABEL(dialog->priv->selected_output_label),
939
g_strdup_printf("Settings for %s",
940
gvc_mixer_ui_device_get_description (active_output)));
941
g_print ("\n active_output_update %s \n", gvc_mixer_ui_device_get_description (active_output));
943
const GHashTable *profs_entries;
944
profs_entries = gvc_mixer_ui_device_get_profiles (active_output);
946
GList* profiles = NULL;
947
profiles = g_hash_table_get_values (profs_entries);
949
if (profiles != NULL || gvc_mixer_ui_device_determine_profile_sensitivity (active_output)) {
951
dialog->priv->output_profile_combo = gvc_combo_box_new (_("Mode:"));
952
gvc_combo_box_set_profiles (GVC_COMBO_BOX (dialog->priv->output_profile_combo),
956
disabled = gvc_mixer_ui_device_determine_profile_sensitivity (active_output);
958
gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box),
959
dialog->priv->output_profile_combo,
962
if (dialog->priv->size_group != NULL) {
963
gvc_combo_box_set_size_group (GVC_COMBO_BOX (dialog->priv->output_profile_combo),
964
dialog->priv->size_group, FALSE);
968
GvcMixerCardProfile *p;
969
// We can be sure that its just one profile in the list when it's disabled
970
p = g_list_last (profiles)->data;
971
gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->output_profile_combo),
975
gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->output_profile_combo),
976
gvc_mixer_control_get_active_profile_from_ui_device (dialog->priv->mixer_control,
979
g_object_set_data (G_OBJECT (dialog->priv->output_profile_combo),
982
g_signal_connect (G_OBJECT (dialog->priv->output_profile_combo), "changed",
983
G_CALLBACK (profile_selection_changed), dialog);
985
gtk_widget_show (dialog->priv->output_profile_combo);
986
gtk_widget_set_sensitive (dialog->priv->output_profile_combo,
993
bar_set_stream (GvcMixerDialog *dialog,
995
GvcMixerStream *stream)
998
GvcMixerStream *old_stream;
1000
g_assert (bar != NULL);
1002
gtk_widget_set_sensitive (bar, (stream != NULL));
1004
adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
1006
g_signal_handlers_disconnect_by_func (adj, on_adjustment_value_changed, dialog);
1008
g_object_set_data (G_OBJECT (bar), "gvc-mixer-dialog-stream", stream);
1009
g_object_set_data (G_OBJECT (adj), "gvc-mixer-dialog-stream", stream);
1010
g_object_set_data (G_OBJECT (adj), "gvc-mixer-dialog-bar", bar);
1012
if (stream != NULL) {
1015
is_muted = gvc_mixer_stream_get_is_muted (stream);
1016
gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar), is_muted);
1018
gtk_adjustment_set_value (adj,
1019
gvc_mixer_stream_get_volume (stream));
1020
g_signal_connect (stream,
1022
G_CALLBACK (on_stream_is_muted_notify),
1024
g_signal_connect (stream,
1026
G_CALLBACK (on_stream_volume_notify),
1028
g_signal_connect (adj,
1030
G_CALLBACK (on_adjustment_value_changed),
1036
* This method handles all streams that are not an input or output
1037
* i.e. effects streams and application streams
1038
* TODO rename to truly reflect its usage.
1041
add_stream (GvcMixerDialog *dialog,
1042
GvcMixerStream *stream)
1048
if (stream == gvc_mixer_control_get_event_sink_input (dialog->priv->mixer_control)) {
1049
bar = dialog->priv->effects_bar;
1050
g_debug ("Adding effects stream");
1052
// Must be a sink/source input/output
1054
name = gvc_mixer_stream_get_name (stream);
1055
g_print ("\n Add bar for application stream : %s",
1058
bar = create_app_bar (dialog, name,
1059
gvc_mixer_stream_get_icon_name (stream));
1061
gtk_box_pack_start (GTK_BOX (dialog->priv->applications_box), bar, FALSE, FALSE, 12);
1062
dialog->priv->num_apps++;
1063
gtk_widget_hide (dialog->priv->no_apps_label);
1065
// We should have a bar by now.
1066
g_assert (bar != NULL);
1067
GvcMixerStream *old_stream;
1070
old_stream = g_object_get_data (G_OBJECT (bar), "gvc-mixer-dialog-stream");
1071
if (old_stream != NULL) {
1073
g_object_get (bar, "name", &name, NULL);
1074
g_debug ("Disconnecting old stream '%s' from bar '%s'",
1075
gvc_mixer_stream_get_name (old_stream), name);
1078
g_signal_handlers_disconnect_by_func (old_stream, on_stream_is_muted_notify, dialog);
1079
g_signal_handlers_disconnect_by_func (old_stream, on_stream_volume_notify, dialog);
1080
g_hash_table_remove (dialog->priv->bars, GUINT_TO_POINTER (gvc_mixer_stream_get_id (old_stream)));
1082
save_bar_for_stream (dialog, stream, bar);
1083
bar_set_stream (dialog, bar, stream);
1084
gtk_widget_show (bar);
1089
remove_stream (GvcMixerDialog *dialog,
1093
bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (id));
1095
g_hash_table_remove (dialog->priv->bars, GUINT_TO_POINTER (id));
1096
gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (bar)),
1098
dialog->priv->num_apps--;
1099
if (dialog->priv->num_apps == 0) {
1100
gtk_widget_show (dialog->priv->no_apps_label);
1107
on_control_stream_added (GvcMixerControl *control,
1109
GvcMixerDialog *dialog)
1111
GvcMixerStream *stream;
1112
stream = gvc_mixer_control_lookup_stream_id (control, id);
1118
app_id = gvc_mixer_stream_get_application_id (stream);
1120
if (stream == gvc_mixer_control_get_event_sink_input (dialog->priv->mixer_control) || (!GVC_IS_MIXER_SOURCE (stream) &&
1121
!GVC_IS_MIXER_SINK (stream)
1122
&& !gvc_mixer_stream_is_virtual (stream)
1123
&& g_strcmp0 (app_id, "org.gnome.VolumeControl") != 0
1124
&& g_strcmp0 (app_id, "org.PulseAudio.pavucontrol") != 0)) {
1128
bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (id));
1130
g_debug ("GvcMixerDialog: Stream %u already added", id);
1133
add_stream (dialog, stream);
1138
on_control_stream_removed (GvcMixerControl *control,
1140
GvcMixerDialog *dialog)
1142
remove_stream (dialog, id);
1146
find_item_by_id (GtkTreeModel *model,
1151
gboolean found_item;
1155
if (!gtk_tree_model_get_iter_first (model, iter)) {
1162
gtk_tree_model_get (model, iter,
1168
} while (!found_item && gtk_tree_model_iter_next (model, iter));
1174
add_input_ui_entry (GvcMixerDialog *dialog,
1175
GvcMixerUIDevice *input)
1177
g_print ("\n Add input ui entry with id : %u \n",
1178
gvc_mixer_ui_device_get_id (input));
1188
g_object_get (G_OBJECT (input),
1189
"stream-id", &stream_id,
1190
"card-id", &card_id,
1192
"description", &description,
1193
"port-name", &port_name,
1194
"port-available", &available,
1197
GtkTreeModel *model;
1199
const GvcChannelMap *map;
1202
if (card_id == GVC_MIXER_UI_DEVICE_INVALID) {
1203
GvcMixerStream *stream;
1204
g_print ("just detected a network source");
1205
stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control, input);
1206
if (stream == NULL) {
1207
g_warning ("tried to add the network source but the stream was null - fail ?!");
1210
g_free (description);
1213
icon = gvc_mixer_stream_get_gicon (stream);
1217
card = gvc_mixer_control_lookup_card_id (dialog->priv->mixer_control, card_id);
1218
icon = gvc_mixer_card_get_gicon (card);
1221
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
1222
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1224
gtk_list_store_set (GTK_LIST_STORE (model),
1226
NAME_COLUMN, description,
1227
DEVICE_COLUMN, origin,
1228
ACTIVE_COLUMN, FALSE,
1230
ID_COLUMN, gvc_mixer_ui_device_get_id (input),
1231
SPEAKERS_COLUMN,origin,
1235
g_object_unref (icon);
1238
/*g_signal_connect (output,
1239
"notify::description",
1240
G_CALLBACK (on_output_description_notify),
1245
g_free (description);
1249
add_output_ui_entry (GvcMixerDialog *dialog,
1250
GvcMixerUIDevice *output)
1252
g_print ("\n Add output ui entry with id : %u \n",
1253
gvc_mixer_ui_device_get_id (output));
1255
gchar *sink_port_name;
1261
gint sink_stream_id;
1263
g_object_get (G_OBJECT (output),
1264
"stream-id", &sink_stream_id,
1265
"card-id", &card_id,
1267
"description", &description,
1268
"port-name", &sink_port_name,
1269
"port-available", &available,
1272
GtkTreeModel *model;
1274
const GvcChannelMap *map;
1277
if (card_id == GVC_MIXER_UI_DEVICE_INVALID) {
1278
g_print ("just detected a network sink");
1280
GvcMixerStream *stream;
1281
stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control, output);
1282
if (stream == NULL) {
1283
g_warning ("tried to add the network sink but the stream was null - fail ?!");
1284
g_free (sink_port_name);
1286
g_free (description);
1289
icon = gvc_mixer_stream_get_gicon (stream);
1293
card = gvc_mixer_control_lookup_card_id (dialog->priv->mixer_control, card_id);
1294
icon = gvc_mixer_card_get_gicon (card);
1297
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
1298
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1300
gtk_list_store_set (GTK_LIST_STORE (model),
1302
NAME_COLUMN, description,
1303
DEVICE_COLUMN, origin,
1304
ACTIVE_COLUMN, FALSE,
1306
ID_COLUMN, gvc_mixer_ui_device_get_id (output),
1307
SPEAKERS_COLUMN,origin,
1311
g_object_unref (icon);
1314
/*g_signal_connect (output,
1315
"notify::description",
1316
G_CALLBACK (on_output_description_notify),
1319
g_free (sink_port_name);
1321
g_free (description);
1325
on_control_output_added (GvcMixerControl *control,
1327
GvcMixerDialog *dialog)
1329
GvcMixerUIDevice* out = NULL;
1330
out = gvc_mixer_control_lookup_output_id (control, id);
1333
g_warning ("on_control_output_added - tried to fetch an output of id %u but got nothing", id);
1337
add_output_ui_entry (dialog, out);
1341
on_control_active_output_update (GvcMixerControl *control,
1343
GvcMixerDialog *dialog)
1345
GvcMixerUIDevice* out = NULL;
1346
out = gvc_mixer_control_lookup_output_id (control, id);
1349
g_warning ("\n on_control_active_output_update - tried to fetch an output of id %u but got nothing", id);
1352
active_output_update (dialog, out);
1356
on_control_active_input_update (GvcMixerControl *control,
1358
GvcMixerDialog *dialog)
1360
GvcMixerUIDevice* in = NULL;
1361
in = gvc_mixer_control_lookup_input_id (control, id);
1364
g_warning ("on_control_active_input_update - tried to fetch an input of id %u but got nothing", id);
1367
active_input_update (dialog, in);
1371
on_control_input_added (GvcMixerControl *control,
1373
GvcMixerDialog *dialog)
1375
GvcMixerUIDevice* in = NULL;
1376
in = gvc_mixer_control_lookup_input_id (control, id);
1379
g_warning ("on_control_input_added - tried to fetch an input of id %u but got nothing", id);
1382
add_input_ui_entry (dialog, in);
1386
on_control_output_removed (GvcMixerControl *control,
1388
GvcMixerDialog *dialog)
1393
GtkTreeModel *model;
1395
GvcMixerUIDevice* out = NULL;
1396
out = gvc_mixer_control_lookup_output_id (control, id);
1398
gint sink_stream_id;
1400
g_object_get (G_OBJECT (out),
1401
"stream-id", &sink_stream_id,
1404
g_print ("Remove output from dialog \n id : %u \n sink stream id : %i \n",
1408
/* remove from any models */
1409
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
1410
found = find_item_by_id (GTK_TREE_MODEL (model), id, ID_COLUMN, &iter);
1412
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
1419
on_control_input_removed (GvcMixerControl *control,
1421
GvcMixerDialog *dialog)
1426
GtkTreeModel *model;
1428
GvcMixerUIDevice* in = NULL;
1429
in = gvc_mixer_control_lookup_input_id (control, id);
1433
g_object_get (G_OBJECT (in),
1434
"stream-id", &stream_id,
1437
g_print ("Remove input from dialog \n id : %u \n stream id : %i \n",
1441
/* remove from any models */
1442
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
1443
found = find_item_by_id (GTK_TREE_MODEL (model), id, ID_COLUMN, &iter);
1445
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
1450
_gtk_label_make_bold (GtkLabel *label)
1452
PangoFontDescription *font_desc;
1454
font_desc = pango_font_description_new ();
1456
pango_font_description_set_weight (font_desc,
1459
/* This will only affect the weight of the font, the rest is
1460
* from the current state of the widget, which comes from the
1461
* theme or user prefs, since the font desc only has the
1462
* weight flag turned on.
1464
gtk_widget_modify_font (GTK_WIDGET (label), font_desc);
1466
pango_font_description_free (font_desc);
1471
on_input_selection_changed (GtkTreeSelection *selection,
1472
GvcMixerDialog *dialog)
1474
GtkTreeModel *model;
1479
if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) {
1480
g_debug ("Could not get default input from selection");
1484
gtk_tree_model_get (model, &iter,
1486
ACTIVE_COLUMN, &toggled,
1490
GvcMixerUIDevice *input;
1491
//g_print ("on_input_selection_changed - try swap to input with id %u", id);
1492
input = gvc_mixer_control_lookup_input_id (dialog->priv->mixer_control, id);
1494
if (input == NULL) {
1495
g_warning ("on_input_selection_changed - Unable to find input with id: %u", id);
1499
gvc_mixer_control_change_input (dialog->priv->mixer_control, input);
1503
on_output_selection_changed (GtkTreeSelection *selection,
1504
GvcMixerDialog *dialog)
1506
GtkTreeModel *model;
1511
if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) {
1512
g_debug ("Could not get default output from selection");
1516
gtk_tree_model_get (model, &iter,
1518
ACTIVE_COLUMN, &active,
1521
g_print ("\n\n on_output_selection_changed - active %i \n\n", active);
1526
GvcMixerUIDevice *output;
1527
g_print ("\n on_output_selection_changed - try swap to output with id %u", id);
1528
output = gvc_mixer_control_lookup_output_id (dialog->priv->mixer_control, id);
1530
if (output == NULL) {
1531
g_warning ("on_output_selection_changed - Unable to find output with id: %u", id);
1535
gvc_mixer_control_change_output (dialog->priv->mixer_control, output);
1539
name_to_text (GtkTreeViewColumn *column,
1540
GtkCellRenderer *cell,
1541
GtkTreeModel *model,
1545
char *name, *mapping;
1547
gtk_tree_model_get(model, iter,
1549
SPEAKERS_COLUMN, &mapping,
1552
if (mapping == NULL) {
1553
g_object_set (cell, "text", name, NULL);
1557
str = g_strdup_printf ("%s\n<i>%s</i>",
1559
g_object_set (cell, "markup", str, NULL);
1568
create_stream_treeview (GvcMixerDialog *dialog,
1569
GCallback on_selection_changed)
1571
GtkWidget *treeview;
1572
GtkListStore *store;
1573
GtkCellRenderer *renderer;
1574
GtkTreeViewColumn *column;
1575
GtkTreeSelection *selection;
1577
treeview = gtk_tree_view_new ();
1578
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
1580
store = gtk_list_store_new (NUM_COLUMNS,
1587
gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
1588
GTK_TREE_MODEL (store));
1590
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
1591
gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1593
column = gtk_tree_view_column_new ();
1594
gtk_tree_view_column_set_title (column, _("Name"));
1595
renderer = gtk_cell_renderer_pixbuf_new ();
1596
gtk_tree_view_column_pack_start (column, renderer, FALSE);
1597
g_object_set (G_OBJECT (renderer), "stock-size", GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
1598
gtk_tree_view_column_set_attributes (column, renderer,
1599
"gicon", ICON_COLUMN,
1602
renderer = gtk_cell_renderer_text_new ();
1603
gtk_tree_view_column_pack_start (column, renderer, TRUE);
1604
gtk_tree_view_column_set_cell_data_func (column, renderer,
1605
name_to_text, NULL, NULL);
1606
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1608
g_signal_connect ( selection, "changed",
1609
on_selection_changed, dialog);
1611
renderer = gtk_cell_renderer_text_new ();
1612
column = gtk_tree_view_column_new_with_attributes (_("Device"),
1614
"text", DEVICE_COLUMN,
1616
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1622
on_profile_changed (GvcComboBox *widget,
1623
const char *profile,
1628
card = g_object_get_data (G_OBJECT (widget), "card");
1630
g_warning ("Could not find card for combobox");
1634
g_debug ("Profile changed to %s for card %s", profile,
1635
gvc_mixer_card_get_name (card));
1637
gvc_mixer_card_change_profile (card, profile);
1641
on_test_speakers_clicked (GtkButton *widget,
1644
GvcMixerDialog *dialog = GVC_MIXER_DIALOG (user_data);
1645
GtkTreeModel *model;
1647
gint active_output = GVC_MIXER_UI_DEVICE_INVALID;
1649
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
1651
if (gtk_tree_model_get_iter_first (model, &iter) == FALSE){
1652
g_warning ("The tree is empty => we have no device to test speakers with return");
1657
gboolean is_selected = FALSE ;
1660
gtk_tree_model_get (model, &iter,
1662
ACTIVE_COLUMN, &is_selected,
1670
}while (gtk_tree_model_iter_next (model, &iter));
1672
if (active_output == GVC_MIXER_UI_DEVICE_INVALID) {
1673
g_warning ("Cant find the active output from the UI");
1677
GvcMixerUIDevice *output;
1678
output = gvc_mixer_control_lookup_output_id (dialog->priv->mixer_control, (guint)active_output);
1679
gint stream_id = gvc_mixer_ui_device_get_stream_id(output);
1681
if (stream_id == GVC_MIXER_UI_DEVICE_INVALID)
1684
g_print ("Test the speakers on the %s", gvc_mixer_ui_device_get_description (output));
1686
GvcMixerStream *stream;
1687
GvcMixerCardProfile *profile;
1688
GtkWidget *d, *speaker_test, *container;
1691
stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, stream_id);
1692
if (stream == NULL) {
1693
g_print ("Stream/sink not found");
1696
title = g_strdup_printf (_("Speaker Testing for %s"), gvc_mixer_ui_device_get_description (output));
1697
d = gtk_dialog_new_with_buttons (title,
1698
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget))),
1699
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1700
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
1702
gtk_window_set_has_resize_grip (GTK_WINDOW (d), FALSE);
1705
speaker_test = gvc_speaker_test_new (dialog->priv->mixer_control,
1707
gtk_widget_show (speaker_test);
1708
container = gtk_dialog_get_content_area (GTK_DIALOG (d));
1709
gtk_container_add (GTK_CONTAINER (container), speaker_test);
1711
gtk_dialog_run (GTK_DIALOG (d));
1712
gtk_widget_destroy (d);
1716
gvc_mixer_dialog_constructor (GType type,
1717
guint n_construct_properties,
1718
GObjectConstructParam *construct_params)
1721
GvcMixerDialog *self;
1722
GtkWidget *main_vbox;
1724
GtkWidget *alignment;
1728
GtkWidget *test_sound_box;
1732
GvcMixerStream *stream;
1734
GtkTreeSelection *selection;
1736
object = G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->constructor (type, n_construct_properties, construct_params);
1738
self = GVC_MIXER_DIALOG (object);
1740
main_vbox = GTK_WIDGET (self);
1741
gtk_box_set_spacing (GTK_BOX (main_vbox), 2);
1743
gtk_container_set_border_width (GTK_CONTAINER (self), 3);
1745
self->priv->output_stream_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1746
alignment = gtk_alignment_new (0, 0, 1, 1);
1747
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 0, 0);
1748
gtk_container_add (GTK_CONTAINER (alignment), self->priv->output_stream_box);
1749
gtk_box_pack_start (GTK_BOX (main_vbox),
1753
self->priv->notebook = gtk_notebook_new ();
1754
gtk_box_pack_start (GTK_BOX (main_vbox),
1755
self->priv->notebook,
1757
gtk_container_set_border_width (GTK_CONTAINER (self->priv->notebook), 5);
1760
self->priv->output_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1761
gtk_container_set_border_width (GTK_CONTAINER (self->priv->output_box), 12);
1762
label = gtk_label_new (_("Output"));
1763
gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
1764
self->priv->output_box,
1767
box = gtk_frame_new (_("Play sound through:"));
1768
gtk_widget_set_size_request (GTK_WIDGET (box), 310, -1);
1769
label = gtk_frame_get_label_widget (GTK_FRAME (box));
1770
_gtk_label_make_bold (GTK_LABEL (label));
1771
gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
1772
gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
1773
gtk_box_pack_start (GTK_BOX (self->priv->output_box), box, FALSE, TRUE, 0);
1775
alignment = gtk_alignment_new (0, 0, 1, 1);
1776
gtk_container_add (GTK_CONTAINER (box), alignment);
1777
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 10, 5, 0, 15);
1779
self->priv->output_treeview = create_stream_treeview (self,
1780
G_CALLBACK (on_output_selection_changed));
1781
gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->output_treeview);
1783
box = gtk_scrolled_window_new (NULL, NULL);
1784
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (box),
1786
GTK_POLICY_AUTOMATIC);
1787
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (box),
1789
gtk_container_add (GTK_CONTAINER (box), self->priv->output_treeview);
1790
gtk_container_add (GTK_CONTAINER (alignment), box);
1792
self->priv->selected_output_label = gtk_label_new (_("Settings for the selected device:"));
1793
gtk_widget_set_halign (self->priv->selected_output_label, GTK_ALIGN_START);
1794
_gtk_label_make_bold (GTK_LABEL (self->priv->selected_output_label));
1795
self->priv->output_settings_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1797
gtk_box_pack_start (GTK_BOX (self->priv->output_box),
1798
self->priv->output_settings_box,
1802
gtk_box_pack_start (GTK_BOX (self->priv->output_settings_box),
1803
self->priv->selected_output_label,
1808
self->priv->output_balance_bar = gvc_balance_bar_new (BALANCE_TYPE_RL);
1809
if (self->priv->size_group != NULL) {
1810
gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (self->priv->output_balance_bar),
1811
self->priv->size_group,
1814
gtk_box_pack_start (GTK_BOX (self->priv->output_settings_box),
1815
self->priv->output_balance_bar,
1817
gtk_widget_show (self->priv->output_balance_bar);
1819
self->priv->output_fade_bar = gvc_balance_bar_new (BALANCE_TYPE_FR);
1820
if (self->priv->size_group != NULL) {
1821
gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (self->priv->output_fade_bar),
1822
self->priv->size_group,
1825
gtk_box_pack_start (GTK_BOX (self->priv->output_settings_box),
1826
self->priv->output_fade_bar,
1828
gtk_widget_show (self->priv->output_fade_bar);
1830
self->priv->output_lfe_bar = gvc_balance_bar_new (BALANCE_TYPE_LFE);
1831
if (self->priv->size_group != NULL) {
1832
gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (self->priv->output_lfe_bar),
1833
self->priv->size_group,
1836
gtk_box_pack_start (GTK_BOX (self->priv->output_settings_box),
1837
self->priv->output_lfe_bar,
1839
gtk_widget_show (self->priv->output_lfe_bar);
1841
/* Creating a box and try to deal using the same size group. */
1842
test_sound_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1843
gtk_box_pack_end (GTK_BOX (self->priv->output_settings_box),
1849
sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1850
gtk_box_pack_start (GTK_BOX (test_sound_box),
1854
label = gtk_label_new (_("Test:"));
1855
gtk_box_pack_start (GTK_BOX (sbox),
1858
if (self->priv->size_group != NULL)
1859
gtk_size_group_add_widget (self->priv->size_group, sbox);
1861
self->priv->test_output_button = gtk_button_new_with_label (_("Test Sound"));
1863
/* FIXME: I am getting mental with all these hardcoded padding values,
1864
* Here 8 works fine, not sure why. */
1865
gtk_box_pack_start (GTK_BOX (test_sound_box),
1866
self->priv->test_output_button,
1869
/* Is this needed */
1870
if (self->priv->size_group != NULL)
1871
gtk_size_group_add_widget (self->priv->size_group, self->priv->test_output_button);
1873
gtk_widget_show (test_sound_box);
1875
gtk_container_add (GTK_CONTAINER (box), self->priv->output_settings_box);
1876
g_signal_connect (self->priv->test_output_button,
1878
G_CALLBACK (on_test_speakers_clicked),
1882
self->priv->input_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1883
gtk_container_set_border_width (GTK_CONTAINER (self->priv->input_box), 12);
1884
label = gtk_label_new (_("Input"));
1885
gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
1886
self->priv->input_box,
1888
box = gtk_frame_new (_("Record sound from:"));
1889
gtk_widget_set_size_request (GTK_WIDGET (box), 310, -1);
1890
label = gtk_frame_get_label_widget (GTK_FRAME (box));
1891
_gtk_label_make_bold (GTK_LABEL (label));
1892
gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
1893
gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
1894
gtk_box_pack_start (GTK_BOX (self->priv->input_box), box, FALSE, TRUE, 0);
1896
alignment = gtk_alignment_new (0, 0, 1, 1);
1897
gtk_container_add (GTK_CONTAINER (box), alignment);
1898
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 10, 5, 0, 15);
1900
self->priv->input_treeview = create_stream_treeview (self,
1901
G_CALLBACK (on_input_selection_changed));
1902
gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->input_treeview);
1904
box = gtk_scrolled_window_new (NULL, NULL);
1905
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (box),
1907
GTK_POLICY_AUTOMATIC);
1908
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (box),
1910
gtk_container_add (GTK_CONTAINER (box), self->priv->input_treeview);
1911
gtk_container_add (GTK_CONTAINER (alignment), box);
1913
self->priv->selected_input_label = gtk_label_new (_("Settings for the selected device:"));
1914
gtk_widget_set_halign (self->priv->selected_input_label, GTK_ALIGN_START);
1915
_gtk_label_make_bold (GTK_LABEL (self->priv->selected_input_label));
1917
self->priv->input_settings_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1918
gtk_box_pack_start (GTK_BOX (self->priv->input_box),
1919
self->priv->input_settings_box,
1923
gtk_box_pack_start (GTK_BOX (self->priv->input_settings_box),
1924
self->priv->selected_input_label,
1929
self->priv->input_bar = create_bar (self, FALSE, TRUE);
1930
gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->input_bar),
1931
_("_Input volume:"));
1932
gvc_channel_bar_set_low_icon_name (GVC_CHANNEL_BAR (self->priv->input_bar),
1933
"audio-input-microphone-low-symbolic");
1934
gvc_channel_bar_set_high_icon_name (GVC_CHANNEL_BAR (self->priv->input_bar),
1935
"audio-input-microphone-high-symbolic");
1936
gtk_widget_set_sensitive (self->priv->input_bar, FALSE);
1938
if (self->priv->size_group != NULL) {
1939
gvc_channel_bar_set_size_group (GVC_CHANNEL_BAR (self->priv->input_bar),
1940
self->priv->size_group,
1944
gtk_box_pack_start (GTK_BOX (self->priv->input_settings_box),
1945
self->priv->input_bar,
1947
gtk_widget_show (self->priv->input_bar);
1950
/* Creating a box and try to deal using the same size group. */
1951
GtkWidget *input_level_box;
1952
input_level_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1953
gtk_box_pack_start (GTK_BOX (self->priv->input_settings_box),
1959
sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1960
gtk_box_pack_start (GTK_BOX (input_level_box),
1964
label = gtk_label_new (_("Input level:"));
1965
gtk_box_pack_start (GTK_BOX (sbox),
1968
if (self->priv->size_group != NULL)
1969
gtk_size_group_add_widget (self->priv->size_group, sbox);
1972
self->priv->input_level_bar = gvc_level_bar_new ();
1973
gvc_level_bar_set_orientation (GVC_LEVEL_BAR (self->priv->input_level_bar),
1974
GTK_ORIENTATION_HORIZONTAL);
1975
gvc_level_bar_set_scale (GVC_LEVEL_BAR (self->priv->input_level_bar),
1976
GVC_LEVEL_SCALE_LINEAR);
1978
gtk_box_pack_start (GTK_BOX (input_level_box),
1979
self->priv->input_level_bar,
1982
gtk_container_add (GTK_CONTAINER (box), self->priv->input_settings_box);
1985
self->priv->sound_effects_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1986
gtk_container_set_border_width (GTK_CONTAINER (self->priv->sound_effects_box), 12);
1987
label = gtk_label_new (_("Sound Effects"));
1988
gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
1989
self->priv->sound_effects_box,
1992
self->priv->effects_bar = create_bar (self, FALSE, TRUE);
1993
gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->effects_bar),
1994
_("_Alert volume:"));
1995
gtk_widget_set_sensitive (self->priv->effects_bar, FALSE);
1996
gtk_box_pack_start (GTK_BOX (self->priv->sound_effects_box),
1997
self->priv->effects_bar, FALSE, FALSE, 0);
1999
self->priv->sound_theme_chooser = gvc_sound_theme_chooser_new ();
2000
gtk_box_pack_start (GTK_BOX (self->priv->sound_effects_box),
2001
self->priv->sound_theme_chooser,
2005
self->priv->applications_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
2006
gtk_container_set_border_width (GTK_CONTAINER (self->priv->applications_box), 12);
2007
label = gtk_label_new (_("Applications"));
2008
gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
2009
self->priv->applications_box,
2011
self->priv->no_apps_label = gtk_label_new (_("No application is currently playing or recording audio."));
2012
gtk_box_pack_start (GTK_BOX (self->priv->applications_box),
2013
self->priv->no_apps_label,
2016
self->priv->output_stream_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
2017
alignment = gtk_alignment_new (0, 0, 1, 1);
2018
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 12, 0, 0, 0);
2019
gtk_container_add (GTK_CONTAINER (alignment), self->priv->output_stream_box);
2020
gtk_box_pack_start (GTK_BOX (main_vbox),
2024
self->priv->output_bar = create_bar (self, FALSE, TRUE);
2025
gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->output_bar),
2026
_("_Output volume:"));
2027
gtk_widget_set_sensitive (self->priv->output_bar, FALSE);
2028
gtk_widget_set_size_request (self->priv->output_bar, 460, -1);
2030
gtk_box_pack_start (GTK_BOX (self->priv->output_stream_box),
2031
self->priv->output_bar, TRUE, FALSE, 12);
2033
gtk_widget_show_all (main_vbox);
2035
g_signal_connect (self->priv->mixer_control,
2037
G_CALLBACK (on_control_stream_added),
2039
g_signal_connect (self->priv->mixer_control,
2041
G_CALLBACK (on_control_stream_removed),
2043
g_signal_connect (self->priv->mixer_control,
2045
G_CALLBACK (on_control_output_added),
2047
g_signal_connect (self->priv->mixer_control,
2049
G_CALLBACK (on_control_output_removed),
2051
g_signal_connect (self->priv->mixer_control,
2053
G_CALLBACK (on_control_input_added),
2055
g_signal_connect (self->priv->mixer_control,
2057
G_CALLBACK (on_control_input_removed),
2063
gvc_mixer_dialog_dispose (GObject *object)
2065
GvcMixerDialog *dialog = GVC_MIXER_DIALOG (object);
2067
g_clear_object (&dialog->priv->indicator_settings);
2069
if (dialog->priv->mixer_control != NULL) {
2070
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2071
on_control_output_added,
2073
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2074
on_control_output_removed,
2076
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2077
on_control_active_input_update,
2079
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2080
on_control_active_output_update,
2082
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2083
on_control_input_added,
2085
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2086
on_control_input_removed,
2088
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2089
on_control_stream_added,
2091
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2092
on_control_stream_removed,
2094
g_object_unref (dialog->priv->mixer_control);
2095
dialog->priv->mixer_control = NULL;
2098
if (dialog->priv->bars != NULL) {
2099
g_hash_table_destroy (dialog->priv->bars);
2100
dialog->priv->bars = NULL;
2103
G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->dispose (object);
2107
gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass)
2109
GObjectClass *object_class = G_OBJECT_CLASS (klass);
2111
object_class->constructor = gvc_mixer_dialog_constructor;
2112
object_class->dispose = gvc_mixer_dialog_dispose;
2113
object_class->finalize = gvc_mixer_dialog_finalize;
2114
object_class->set_property = gvc_mixer_dialog_set_property;
2115
object_class->get_property = gvc_mixer_dialog_get_property;
2117
g_object_class_install_property (object_class,
2119
g_param_spec_object ("mixer-control",
2122
GVC_TYPE_MIXER_CONTROL,
2123
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2125
g_type_class_add_private (klass, sizeof (GvcMixerDialogPrivate));
2130
gvc_mixer_dialog_init (GvcMixerDialog *dialog)
2132
dialog->priv = GVC_MIXER_DIALOG_GET_PRIVATE (dialog);
2133
dialog->priv->bars = g_hash_table_new (NULL, NULL);
2134
dialog->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
2138
gvc_mixer_dialog_finalize (GObject *object)
2140
GvcMixerDialog *mixer_dialog;
2142
g_return_if_fail (object != NULL);
2143
g_return_if_fail (GVC_IS_MIXER_DIALOG (object));
2145
mixer_dialog = GVC_MIXER_DIALOG (object);
2147
g_return_if_fail (mixer_dialog->priv != NULL);
2148
G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->finalize (object);
2152
gvc_mixer_dialog_new (GvcMixerControl *control)
2155
dialog = g_object_new (GVC_TYPE_MIXER_DIALOG,
2156
"mixer-control", control,
2158
return GVC_MIXER_DIALOG (dialog);
2170
gvc_mixer_dialog_set_page (GvcMixerDialog *self,
2175
g_return_val_if_fail (self != NULL, FALSE);
2179
else if (g_str_equal (page, "effects"))
2181
else if (g_str_equal (page, "input"))
2183
else if (g_str_equal (page, "output"))
2185
else if (g_str_equal (page, "applications"))
2186
num = PAGE_APPLICATIONS;
2190
gtk_notebook_set_current_page (GTK_NOTEBOOK (self->priv->notebook), num);