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_port_combo;
80
GtkWidget *input_treeview;
81
GtkWidget *input_settings_box;
82
GtkWidget *sound_theme_chooser;
83
GtkWidget *click_feedback_button;
84
GtkWidget *audible_bell_button;
85
GtkSizeGroup *size_group;
86
GtkWidget *selected_output_label;
87
GtkWidget *selected_input_label;
88
GtkWidget *test_output_button;
90
gdouble last_input_peak;
110
HW_PROFILE_HUMAN_COLUMN,
121
static void gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass);
122
static void gvc_mixer_dialog_init (GvcMixerDialog *mixer_dialog);
123
static void gvc_mixer_dialog_finalize (GObject *object);
125
static void bar_set_stream (GvcMixerDialog *dialog,
127
GvcMixerStream *stream);
129
static void on_adjustment_value_changed (GtkAdjustment *adjustment,
130
GvcMixerDialog *dialog);
131
static void on_control_output_added (GvcMixerControl *control,
133
GvcMixerDialog *dialog);
134
static void on_control_active_output_update (GvcMixerControl *control,
136
GvcMixerDialog *dialog);
138
static void on_control_active_input_update (GvcMixerControl *control,
140
GvcMixerDialog *dialog);
142
G_DEFINE_TYPE (GvcMixerDialog, gvc_mixer_dialog, GTK_TYPE_VBOX)
146
update_description (GvcMixerDialog *dialog,
149
GvcMixerStream *stream)
155
if (GVC_IS_MIXER_SOURCE (stream))
156
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
157
else if (GVC_IS_MIXER_SINK (stream))
158
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
160
g_assert_not_reached ();
161
gtk_tree_model_get_iter_first (model, &iter);
163
id = gvc_mixer_stream_get_id (stream);
167
gtk_tree_model_get (model, &iter,
168
ID_COLUMN, ¤t_id,
170
if (id != current_id)
173
gtk_list_store_set (GTK_LIST_STORE (model),
178
} while (gtk_tree_model_iter_next (model, &iter));
182
profile_selection_changed (GvcComboBox *combo_box,
184
GvcMixerDialog *dialog)
186
g_print ("profile_selection_changed - %s", profile);
187
GvcMixerUIDevice *out;
188
out = g_object_get_data (G_OBJECT (combo_box), "uidevice");
191
g_warning ("Could not find Output for profile combo box");
195
if (gvc_mixer_control_change_profile_on_selected_device (dialog->priv->mixer_control, out, profile) == FALSE) {
196
g_warning ("Could not change profile on device %s",
197
gvc_mixer_ui_device_get_description (out));
201
#define DECAY_STEP .15
204
update_input_peak (GvcMixerDialog *dialog,
209
if (dialog->priv->last_input_peak >= DECAY_STEP) {
210
if (v < dialog->priv->last_input_peak - DECAY_STEP) {
211
v = dialog->priv->last_input_peak - DECAY_STEP;
215
dialog->priv->last_input_peak = v;
217
adj = gvc_level_bar_get_peak_adjustment (GVC_LEVEL_BAR (dialog->priv->input_level_bar));
219
gtk_adjustment_set_value (adj, v);
221
gtk_adjustment_set_value (adj, 0.0);
226
update_input_meter (GvcMixerDialog *dialog,
227
uint32_t source_index,
228
uint32_t sink_input_idx,
231
update_input_peak (dialog, v);
235
on_monitor_suspended_callback (pa_stream *s,
238
GvcMixerDialog *dialog;
242
if (pa_stream_is_suspended (s)) {
243
g_debug ("Stream suspended");
244
update_input_meter (dialog,
245
pa_stream_get_device_index (s),
252
on_monitor_read_callback (pa_stream *s,
256
GvcMixerDialog *dialog;
262
if (pa_stream_peek (s, &data, &length) < 0) {
263
g_warning ("Failed to read data from stream");
268
assert (length % sizeof (float) == 0);
270
v = ((const float *) data)[length / sizeof (float) -1];
281
update_input_meter (dialog,
282
pa_stream_get_device_index (s),
283
pa_stream_get_monitor_stream (s),
288
create_monitor_stream_for_source (GvcMixerDialog *dialog,
289
GvcMixerStream *stream)
297
pa_proplist *proplist;
298
gboolean has_monitor;
300
if (stream == NULL) {
303
has_monitor = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (stream), "has-monitor"));
304
if (has_monitor != FALSE) {
308
g_debug ("Create monitor for %u",
309
gvc_mixer_stream_get_index (stream));
311
context = gvc_mixer_control_get_pa_context (dialog->priv->mixer_control);
313
if (pa_context_get_server_protocol_version (context) < 13) {
318
ss.format = PA_SAMPLE_FLOAT32;
321
memset (&attr, 0, sizeof (attr));
322
attr.fragsize = sizeof (float);
323
attr.maxlength = (uint32_t) -1;
325
snprintf (t, sizeof (t), "%u", gvc_mixer_stream_get_index (stream));
327
proplist = pa_proplist_new ();
328
pa_proplist_sets (proplist, PA_PROP_APPLICATION_ID, "org.gnome.VolumeControl");
329
s = pa_stream_new_with_proplist (context, _("Peak detect"), &ss, NULL, proplist);
330
pa_proplist_free (proplist);
332
g_warning ("Failed to create monitoring stream");
336
pa_stream_set_read_callback (s, on_monitor_read_callback, dialog);
337
pa_stream_set_suspended_callback (s, on_monitor_suspended_callback, dialog);
339
res = pa_stream_connect_record (s,
342
(pa_stream_flags_t) (PA_STREAM_DONT_MOVE
343
|PA_STREAM_PEAK_DETECT
344
|PA_STREAM_ADJUST_LATENCY));
346
g_warning ("Failed to connect monitoring stream");
349
g_object_set_data (G_OBJECT (stream), "has-monitor", GINT_TO_POINTER (TRUE));
350
g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream", s);
351
g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "stream", stream);
356
stop_monitor_stream_for_source (GvcMixerDialog *dialog)
361
GvcMixerStream *stream;
363
s = g_object_get_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream");
366
stream = g_object_get_data (G_OBJECT (dialog->priv->input_level_bar), "stream");
367
g_assert (stream != NULL);
369
g_debug ("Stopping monitor for %u", pa_stream_get_index (s));
371
context = gvc_mixer_control_get_pa_context (dialog->priv->mixer_control);
373
if (pa_context_get_server_protocol_version (context) < 13) {
377
res = pa_stream_disconnect (s);
379
g_object_set_data (G_OBJECT (stream), "has-monitor", GINT_TO_POINTER (FALSE));
380
g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream", NULL);
381
g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "stream", NULL);
385
gvc_mixer_dialog_set_mixer_control (GvcMixerDialog *dialog,
386
GvcMixerControl *control)
388
g_return_if_fail (GVC_MIXER_DIALOG (dialog));
389
g_return_if_fail (GVC_IS_MIXER_CONTROL (control));
391
g_object_ref (control);
393
if (dialog->priv->mixer_control != NULL) {
394
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
395
G_CALLBACK (on_control_active_output_update),
397
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
398
G_CALLBACK (on_control_active_input_update),
400
g_object_unref (dialog->priv->mixer_control);
403
dialog->priv->mixer_control = control;
405
g_signal_connect (dialog->priv->mixer_control,
406
"active-output-update",
407
G_CALLBACK (on_control_active_output_update),
409
g_signal_connect (dialog->priv->mixer_control,
410
"active-input-update",
411
G_CALLBACK (on_control_active_input_update),
414
g_object_notify (G_OBJECT (dialog), "mixer-control");
417
static GvcMixerControl *
418
gvc_mixer_dialog_get_mixer_control (GvcMixerDialog *dialog)
420
g_return_val_if_fail (GVC_IS_MIXER_DIALOG (dialog), NULL);
422
return dialog->priv->mixer_control;
426
gvc_mixer_dialog_set_property (GObject *object,
431
GvcMixerDialog *self = GVC_MIXER_DIALOG (object);
434
case PROP_MIXER_CONTROL:
435
gvc_mixer_dialog_set_mixer_control (self, g_value_get_object (value));
438
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
444
gvc_mixer_dialog_get_property (GObject *object,
449
GvcMixerDialog *self = GVC_MIXER_DIALOG (object);
452
case PROP_MIXER_CONTROL:
453
g_value_set_object (value, gvc_mixer_dialog_get_mixer_control (self));
456
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
462
on_adjustment_value_changed (GtkAdjustment *adjustment,
463
GvcMixerDialog *dialog)
465
GvcMixerStream *stream;
467
stream = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-stream");
468
if (stream != NULL) {
470
gdouble volume, rounded;
473
volume = gtk_adjustment_get_value (adjustment);
474
rounded = round (volume);
476
bar = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-bar");
477
g_object_get (bar, "name", &name, NULL);
478
g_debug ("Setting stream volume %lf (rounded: %lf) for bar '%s'", volume, rounded, name);
481
/* FIXME would need to do that in the balance bar really... */
482
/* Make sure we do not unmute muted streams, there's a button for that */
484
gvc_mixer_stream_set_is_muted (stream, TRUE);
485
/* Only push the volume if it's actually changed */
486
if (gvc_mixer_stream_set_volume(stream, (pa_volume_t) rounded) != FALSE)
487
gvc_mixer_stream_push_volume (stream);
492
on_bar_is_muted_notify (GObject *object,
494
GvcMixerDialog *dialog)
497
GvcMixerStream *stream;
499
is_muted = gvc_channel_bar_get_is_muted (GVC_CHANNEL_BAR (object));
501
stream = g_object_get_data (object, "gvc-mixer-dialog-stream");
502
if (stream != NULL) {
503
gvc_mixer_stream_change_is_muted (stream, is_muted);
506
g_object_get (object, "name", &name, NULL);
507
g_warning ("Unable to find stream for bar '%s'", name);
513
lookup_bar_for_stream (GvcMixerDialog *dialog,
514
GvcMixerStream *stream)
518
bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)));
525
// UI devices now pull description material mainly for the card ports.
526
// Therefore the need for stream description dynamic changes more than ever seems unneccessary.
528
on_stream_description_notify (GvcMixerStream *stream,
530
GvcMixerDialog *dialog)
532
update_description (dialog, NAME_COLUMN,
533
gvc_mixer_stream_get_description (stream),
538
on_stream_volume_notify (GObject *object,
540
GvcMixerDialog *dialog)
542
GvcMixerStream *stream;
545
stream = GVC_MIXER_STREAM (object);
547
bar = lookup_bar_for_stream (dialog, stream);
550
if (stream == gvc_mixer_control_get_default_sink(dialog->priv->mixer_control)) {
551
bar = dialog->priv->output_bar;
553
else if(stream == gvc_mixer_control_get_default_source(dialog->priv->mixer_control)) {
554
bar = dialog->priv->input_bar;
557
g_warning ("Unable to find bar for stream %s in on_stream_volume_notify()",
558
gvc_mixer_stream_get_name (stream));
563
adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
565
g_signal_handlers_block_by_func (adj,
566
on_adjustment_value_changed,
569
gtk_adjustment_set_value (adj,
570
gvc_mixer_stream_get_volume (stream));
572
g_signal_handlers_unblock_by_func (adj,
573
on_adjustment_value_changed,
578
on_stream_is_muted_notify (GObject *object,
580
GvcMixerDialog *dialog)
582
GvcMixerStream *stream;
586
stream = GVC_MIXER_STREAM (object);
588
bar = lookup_bar_for_stream (dialog, stream);
591
if (stream == gvc_mixer_control_get_default_sink(dialog->priv->mixer_control)) {
592
bar = dialog->priv->output_bar;
594
else if(stream == gvc_mixer_control_get_default_source(dialog->priv->mixer_control)) {
595
bar = dialog->priv->input_bar;
598
g_warning ("Unable to find bar for stream %s in on_stream_muted_notify()",
599
gvc_mixer_stream_get_name (stream));
605
is_muted = gvc_mixer_stream_get_is_muted (stream);
606
gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar),
609
if (stream == gvc_mixer_control_get_default_sink (dialog->priv->mixer_control)) {
610
gtk_widget_set_sensitive (dialog->priv->applications_box,
617
save_bar_for_stream (GvcMixerDialog *dialog,
618
GvcMixerStream *stream,
621
g_print ("\n saving bar for stream %s",
622
gvc_mixer_stream_get_name (stream));
623
g_hash_table_insert (dialog->priv->bars,
624
GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)),
629
create_bar (GvcMixerDialog *dialog,
630
gboolean add_to_size_group,
635
bar = gvc_channel_bar_new ();
636
gtk_widget_set_sensitive (bar, FALSE);
637
if (add_to_size_group && dialog->priv->size_group != NULL) {
638
gvc_channel_bar_set_size_group (GVC_CHANNEL_BAR (bar),
639
dialog->priv->size_group,
642
gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (bar),
643
GTK_ORIENTATION_HORIZONTAL);
644
gvc_channel_bar_set_show_mute (GVC_CHANNEL_BAR (bar),
646
g_signal_connect (bar,
648
G_CALLBACK (on_bar_is_muted_notify),
654
create_app_bar (GvcMixerDialog *dialog,
656
const char *icon_name)
660
bar = create_bar (dialog, FALSE, FALSE);
661
gvc_channel_bar_set_ellipsize (GVC_CHANNEL_BAR (bar), TRUE);
662
gvc_channel_bar_set_icon_name (GVC_CHANNEL_BAR (bar), icon_name);
663
if (name == NULL || strchr (name, '_') == NULL) {
664
gvc_channel_bar_set_name (GVC_CHANNEL_BAR (bar), name);
666
char **tokens, *escaped;
668
tokens = g_strsplit (name, "_", -1);
669
escaped = g_strjoinv ("__", tokens);
671
gvc_channel_bar_set_name (GVC_CHANNEL_BAR (bar), escaped);
678
/* active_input_update
679
* Handle input update change from the backend (control).
680
* Trust the backend whole-heartedly to deliver the correct input
684
active_input_update (GvcMixerDialog *dialog,
685
GvcMixerUIDevice *active_input)
687
g_print ("\n active_input_update %s \n", gvc_mixer_ui_device_get_description (active_input));
688
// First make sure the correct UI device is selected.
692
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
693
gtk_tree_model_get_iter_first (model, &iter);
696
gboolean is_selected = FALSE;
699
gtk_tree_model_get (model, &iter,
703
is_selected = id == gvc_mixer_ui_device_get_id (active_input);
705
gtk_list_store_set (GTK_LIST_STORE (model),
707
ACTIVE_COLUMN, is_selected,
711
GtkTreeSelection *selection;
712
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->input_treeview));
713
gtk_tree_selection_select_iter (selection, &iter);
716
}while (gtk_tree_model_iter_next (model, &iter));
718
stop_monitor_stream_for_source (dialog);
721
GvcMixerStream *stream;
722
const GvcChannelMap *map;
725
stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control,
728
if (stream == NULL) {
729
g_warning ("active_input_update - couldn't find a stream from the supposed active input");
730
gtk_widget_set_sensitive (dialog->priv->input_bar,
734
// Set the label accordingly
735
gtk_label_set_label (GTK_LABEL(dialog->priv->selected_input_label),
736
g_strdup_printf("Settings for %s",
737
gvc_mixer_ui_device_get_description (active_input)));
739
gvc_channel_bar_set_base_volume (GVC_CHANNEL_BAR (dialog->priv->input_bar),
740
gvc_mixer_stream_get_base_volume (stream));
741
gvc_channel_bar_set_is_amplified (GVC_CHANNEL_BAR (dialog->priv->input_bar),
742
gvc_mixer_stream_get_can_decibel (stream));
743
/* Update the adjustment in case the previous bar wasn't decibel
744
* capable, and we clipped it */
745
adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->input_bar)));
746
gtk_adjustment_set_value (adj,
747
gvc_mixer_stream_get_volume (stream));
749
create_monitor_stream_for_source (dialog, stream);
750
// remove any previous stream that might have been pointed at
751
// the static input bar and connect new signals from new stream.
752
bar_set_stream (dialog, dialog->priv->input_bar, stream);
755
/* active_output_update
756
* Handle output update change from the backend (control).
757
* Trust the backend whole heartedly to deliver the correct output
761
active_output_update (GvcMixerDialog *dialog,
762
GvcMixerUIDevice *active_output)
764
// First make sure the correct UI device is selected.
767
g_print ("\n\n active output update - device id = %i \n\n",
768
gvc_mixer_ui_device_get_id (active_output));
770
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
771
gtk_tree_model_get_iter_first (model, &iter);
774
gboolean is_selected;
777
gtk_tree_model_get (model, &iter,
779
ACTIVE_COLUMN, &is_selected,
782
if (is_selected && id == gvc_mixer_ui_device_get_id (active_output)) {
783
g_print ("\n\n unneccessary active output update unless it was a profile change on the same device ? \n\n");
787
is_selected = id == gvc_mixer_ui_device_get_id (active_output);
789
gtk_list_store_set (GTK_LIST_STORE (model),
791
ACTIVE_COLUMN, is_selected,
795
GtkTreeSelection *selection;
796
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->output_treeview));
797
gtk_tree_selection_select_iter (selection, &iter);
800
}while (gtk_tree_model_iter_next (model, &iter));
802
// Not ideal but for now destroy the combo and recreate below.
803
if (dialog->priv->output_port_combo != NULL) {
804
gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box),
805
dialog->priv->output_port_combo);
806
dialog->priv->output_port_combo = NULL;
809
GvcMixerStream *stream;
810
const GvcChannelMap *map;
813
stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control,
816
if (stream == NULL) {
817
g_warning ("active_output_update - couldn't find a stream from the supposed active output");
821
gboolean is_muted = gvc_mixer_stream_get_is_muted (stream);
822
gtk_widget_set_sensitive (dialog->priv->applications_box,
824
adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->output_bar)));
825
g_signal_handlers_disconnect_by_func(adj, on_adjustment_value_changed, dialog);
827
bar_set_stream (dialog, dialog->priv->output_bar, stream);
828
gvc_channel_bar_set_base_volume (GVC_CHANNEL_BAR (dialog->priv->output_bar),
829
gvc_mixer_stream_get_base_volume (stream));
830
gvc_channel_bar_set_is_amplified (GVC_CHANNEL_BAR (dialog->priv->output_bar),
831
gvc_mixer_stream_get_can_decibel (stream));
832
/* Update the adjustment in case the previous bar wasn't decibel
833
* capable, and we clipped it */
834
adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->output_bar)));
835
gtk_adjustment_set_value (adj,
836
gvc_mixer_stream_get_volume (stream));
838
map = gvc_mixer_stream_get_channel_map (stream);
841
g_warning ("Active output stream has no channel map");
842
gtk_widget_set_sensitive (dialog->priv->output_bar, FALSE);
843
gtk_widget_set_sensitive (dialog->priv->output_balance_bar, FALSE);
844
gtk_widget_set_sensitive (dialog->priv->output_lfe_bar, FALSE);
845
gtk_widget_set_sensitive (dialog->priv->output_fade_bar, FALSE);
850
// Swap bars to the active map
851
gvc_balance_bar_set_map (GVC_BALANCE_BAR (dialog->priv->output_balance_bar),
853
gvc_balance_bar_set_map (GVC_BALANCE_BAR (dialog->priv->output_fade_bar),
855
gvc_balance_bar_set_map (GVC_BALANCE_BAR (dialog->priv->output_lfe_bar),
858
// Set sensitivities accordingly.
859
gtk_widget_set_sensitive (dialog->priv->output_balance_bar,
860
gvc_channel_map_can_balance (map));
861
gtk_widget_set_sensitive (dialog->priv->output_fade_bar,
862
gvc_channel_map_can_fade (map));
863
gtk_widget_set_sensitive (dialog->priv->output_lfe_bar,
864
gvc_channel_map_has_lfe (map));
865
gtk_widget_set_sensitive (dialog->priv->output_bar,
867
// Set the label accordingly
868
gtk_label_set_label (GTK_LABEL(dialog->priv->selected_output_label),
869
g_strdup_printf("Settings for %s",
870
gvc_mixer_ui_device_get_description (active_output)));
871
g_print ("\n active_output_update %s \n", gvc_mixer_ui_device_get_description (active_output));
874
profiles = gvc_mixer_ui_device_get_profiles (active_output);
876
if (profiles != NULL) {
877
dialog->priv->output_port_combo = gvc_combo_box_new (_("Mode:"));
878
gvc_combo_box_set_profiles (GVC_COMBO_BOX (dialog->priv->output_port_combo),
882
disabled = gvc_mixer_ui_device_determine_profile_sensitivity (active_output);
886
GvcMixerCardProfile *p;
887
profs = gvc_mixer_ui_device_get_profiles (active_output);
888
// We can be sure that its just one profile in the list when it's disabled
889
p = g_list_last (profs)->data;
890
gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->output_port_combo),
894
gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->output_port_combo),
895
gvc_mixer_control_get_active_profile_from_ui_device (dialog->priv->mixer_control,
898
g_object_set_data (G_OBJECT (dialog->priv->output_port_combo),
901
g_signal_connect (G_OBJECT (dialog->priv->output_port_combo), "changed",
902
G_CALLBACK (profile_selection_changed), dialog);
904
gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box),
905
dialog->priv->output_port_combo,
908
if (dialog->priv->size_group != NULL) {
909
gvc_combo_box_set_size_group (GVC_COMBO_BOX (dialog->priv->output_port_combo),
910
dialog->priv->size_group, FALSE);
912
gtk_widget_show (dialog->priv->output_port_combo);
913
gtk_widget_set_sensitive (dialog->priv->output_port_combo,
920
bar_set_stream (GvcMixerDialog *dialog,
922
GvcMixerStream *stream)
925
GvcMixerStream *old_stream;
927
g_assert (bar != NULL);
930
old_stream = g_object_get_data (G_OBJECT (bar), "gvc-mixer-dialog-stream");
932
if (old_stream != NULL) {
935
/*g_object_get (bar, "name", &name, NULL);
936
g_print ("Disconnecting old stream '%s' from bar '%s'",
937
gvc_mixer_stream_get_name (old_stream), name);
940
g_signal_handlers_disconnect_by_func (old_stream, on_stream_is_muted_notify, dialog);
941
g_signal_handlers_disconnect_by_func (old_stream, on_stream_volume_notify, dialog);
946
gtk_widget_set_sensitive (bar, (stream != NULL));
948
adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
950
g_signal_handlers_disconnect_by_func (adj, on_adjustment_value_changed, dialog);
952
g_object_set_data (G_OBJECT (bar), "gvc-mixer-dialog-stream", stream);
953
g_object_set_data (G_OBJECT (adj), "gvc-mixer-dialog-stream", stream);
954
g_object_set_data (G_OBJECT (adj), "gvc-mixer-dialog-bar", bar);
956
if (stream != NULL) {
959
is_muted = gvc_mixer_stream_get_is_muted (stream);
960
gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar), is_muted);
962
gtk_adjustment_set_value (adj,
963
gvc_mixer_stream_get_volume (stream));
964
g_signal_connect (stream,
966
G_CALLBACK (on_stream_is_muted_notify),
968
g_signal_connect (stream,
970
G_CALLBACK (on_stream_volume_notify),
972
g_signal_connect (adj,
974
G_CALLBACK (on_adjustment_value_changed),
980
* This method handles all streams that are not an input or output
981
* i.e. effects streams and application streams
982
* TODO rename to truly reflect its usage.
985
add_stream (GvcMixerDialog *dialog,
986
GvcMixerStream *stream)
992
if (stream == gvc_mixer_control_get_event_sink_input (dialog->priv->mixer_control)) {
993
bar = dialog->priv->effects_bar;
994
g_debug ("Adding effects stream");
996
// Must be a sink/source input/output
998
name = gvc_mixer_stream_get_name (stream);
999
g_print ("\n Add bar for application stream : %s",
1002
bar = create_app_bar (dialog, name,
1003
gvc_mixer_stream_get_icon_name (stream));
1005
gtk_box_pack_start (GTK_BOX (dialog->priv->applications_box), bar, FALSE, FALSE, 12);
1006
dialog->priv->num_apps++;
1007
gtk_widget_hide (dialog->priv->no_apps_label);
1009
// We should have a bar by now.
1010
g_assert (bar != NULL);
1011
GvcMixerStream *old_stream;
1014
old_stream = g_object_get_data (G_OBJECT (bar), "gvc-mixer-dialog-stream");
1015
if (old_stream != NULL) {
1017
g_object_get (bar, "name", &name, NULL);
1018
g_debug ("Disconnecting old stream '%s' from bar '%s'",
1019
gvc_mixer_stream_get_name (old_stream), name);
1022
g_signal_handlers_disconnect_by_func (old_stream, on_stream_is_muted_notify, dialog);
1023
g_signal_handlers_disconnect_by_func (old_stream, on_stream_volume_notify, dialog);
1024
g_hash_table_remove (dialog->priv->bars, GUINT_TO_POINTER (gvc_mixer_stream_get_id (old_stream)));
1026
save_bar_for_stream (dialog, stream, bar);
1027
bar_set_stream (dialog, bar, stream);
1028
gtk_widget_show (bar);
1033
remove_stream (GvcMixerDialog *dialog,
1037
bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (id));
1039
g_hash_table_remove (dialog->priv->bars, GUINT_TO_POINTER (id));
1040
gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (bar)),
1042
dialog->priv->num_apps--;
1043
if (dialog->priv->num_apps == 0) {
1044
gtk_widget_show (dialog->priv->no_apps_label);
1051
on_control_stream_added (GvcMixerControl *control,
1053
GvcMixerDialog *dialog)
1055
GvcMixerStream *stream;
1056
stream = gvc_mixer_control_lookup_stream_id (control, id);
1062
app_id = gvc_mixer_stream_get_application_id (stream);
1064
if (stream == gvc_mixer_control_get_event_sink_input (dialog->priv->mixer_control) || (!GVC_IS_MIXER_SOURCE (stream) &&
1065
!GVC_IS_MIXER_SINK (stream)
1066
&& !gvc_mixer_stream_is_virtual (stream)
1067
&& g_strcmp0 (app_id, "org.gnome.VolumeControl") != 0
1068
&& g_strcmp0 (app_id, "org.PulseAudio.pavucontrol") != 0)) {
1072
bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (id));
1074
g_debug ("GvcMixerDialog: Stream %u already added", id);
1077
add_stream (dialog, stream);
1082
on_control_stream_removed (GvcMixerControl *control,
1084
GvcMixerDialog *dialog)
1086
remove_stream (dialog, id);
1090
find_item_by_id (GtkTreeModel *model,
1095
gboolean found_item;
1099
if (!gtk_tree_model_get_iter_first (model, iter)) {
1106
gtk_tree_model_get (model, iter,
1112
} while (!found_item && gtk_tree_model_iter_next (model, iter));
1118
add_input_ui_entry (GvcMixerDialog *dialog,
1119
GvcMixerUIDevice *input)
1121
g_print ("\n Add input ui entry with id : %u \n",
1122
gvc_mixer_ui_device_get_id (input));
1132
g_object_get (G_OBJECT (input),
1133
"stream-id", &stream_id,
1134
"card-id", &card_id,
1136
"description", &description,
1137
"port-name", &port_name,
1138
"port-available", &available,
1141
GtkTreeModel *model;
1143
const GvcChannelMap *map;
1146
if (card_id == GVC_MIXER_UI_DEVICE_INVALID) {
1147
GvcMixerStream *stream;
1148
g_print ("just detected a network source");
1149
stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control, input);
1150
if (stream == NULL) {
1151
g_warning ("tried to add the network source but the stream was null - fail ?!");
1154
g_free (description);
1157
icon = gvc_mixer_stream_get_gicon (stream);
1161
card = gvc_mixer_control_lookup_card_id (dialog->priv->mixer_control, card_id);
1162
icon = gvc_mixer_card_get_gicon (card);
1165
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
1166
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1168
gtk_list_store_set (GTK_LIST_STORE (model),
1170
NAME_COLUMN, description,
1171
DEVICE_COLUMN, origin,
1172
ACTIVE_COLUMN, FALSE,
1174
ID_COLUMN, gvc_mixer_ui_device_get_id (input),
1175
SPEAKERS_COLUMN,origin,
1179
g_object_unref (icon);
1182
/*g_signal_connect (output,
1183
"notify::description",
1184
G_CALLBACK (on_output_description_notify),
1189
g_free (description);
1193
add_output_ui_entry (GvcMixerDialog *dialog,
1194
GvcMixerUIDevice *output)
1196
g_print ("\n Add output ui entry with id : %u \n",
1197
gvc_mixer_ui_device_get_id (output));
1199
gchar *sink_port_name;
1205
gint sink_stream_id;
1207
g_object_get (G_OBJECT (output),
1208
"stream-id", &sink_stream_id,
1209
"card-id", &card_id,
1211
"description", &description,
1212
"port-name", &sink_port_name,
1213
"port-available", &available,
1216
GtkTreeModel *model;
1218
const GvcChannelMap *map;
1221
if (card_id == GVC_MIXER_UI_DEVICE_INVALID) {
1222
g_print ("just detected a network sink");
1224
GvcMixerStream *stream;
1225
stream = gvc_mixer_control_get_stream_from_device (dialog->priv->mixer_control, output);
1226
if (stream == NULL) {
1227
g_warning ("tried to add the network sink but the stream was null - fail ?!");
1228
g_free (sink_port_name);
1230
g_free (description);
1233
icon = gvc_mixer_stream_get_gicon (stream);
1237
card = gvc_mixer_control_lookup_card_id (dialog->priv->mixer_control, card_id);
1238
icon = gvc_mixer_card_get_gicon (card);
1241
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
1242
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1244
gtk_list_store_set (GTK_LIST_STORE (model),
1246
NAME_COLUMN, description,
1247
DEVICE_COLUMN, origin,
1248
ACTIVE_COLUMN, FALSE,
1250
ID_COLUMN, gvc_mixer_ui_device_get_id (output),
1251
SPEAKERS_COLUMN,origin,
1255
g_object_unref (icon);
1258
/*g_signal_connect (output,
1259
"notify::description",
1260
G_CALLBACK (on_output_description_notify),
1263
g_free (sink_port_name);
1265
g_free (description);
1269
on_control_output_added (GvcMixerControl *control,
1271
GvcMixerDialog *dialog)
1273
GvcMixerUIDevice* out = NULL;
1274
out = gvc_mixer_control_lookup_output_id (control, id);
1277
g_warning ("on_control_output_added - tried to fetch an output of id %u but got nothing", id);
1281
add_output_ui_entry (dialog, out);
1285
on_control_active_output_update (GvcMixerControl *control,
1287
GvcMixerDialog *dialog)
1289
GvcMixerUIDevice* out = NULL;
1290
out = gvc_mixer_control_lookup_output_id (control, id);
1293
g_warning ("\n on_control_active_output_update - tried to fetch an output of id %u but got nothing", id);
1296
active_output_update (dialog, out);
1300
on_control_active_input_update (GvcMixerControl *control,
1302
GvcMixerDialog *dialog)
1304
GvcMixerUIDevice* in = NULL;
1305
in = gvc_mixer_control_lookup_input_id (control, id);
1308
g_warning ("on_control_active_input_update - tried to fetch an input of id %u but got nothing", id);
1311
active_input_update (dialog, in);
1315
on_control_input_added (GvcMixerControl *control,
1317
GvcMixerDialog *dialog)
1319
GvcMixerUIDevice* in = NULL;
1320
in = gvc_mixer_control_lookup_input_id (control, id);
1323
g_warning ("on_control_input_added - tried to fetch an input of id %u but got nothing", id);
1326
add_input_ui_entry (dialog, in);
1330
on_control_output_removed (GvcMixerControl *control,
1332
GvcMixerDialog *dialog)
1337
GtkTreeModel *model;
1339
GvcMixerUIDevice* out = NULL;
1340
out = gvc_mixer_control_lookup_output_id (control, id);
1342
gint sink_stream_id;
1344
g_object_get (G_OBJECT (out),
1345
"stream-id", &sink_stream_id,
1348
g_print ("Remove output from dialog \n id : %u \n sink stream id : %i \n",
1352
/* remove from any models */
1353
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
1354
found = find_item_by_id (GTK_TREE_MODEL (model), id, ID_COLUMN, &iter);
1356
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
1363
on_control_input_removed (GvcMixerControl *control,
1365
GvcMixerDialog *dialog)
1370
GtkTreeModel *model;
1372
GvcMixerUIDevice* in = NULL;
1373
in = gvc_mixer_control_lookup_input_id (control, id);
1377
g_object_get (G_OBJECT (in),
1378
"stream-id", &stream_id,
1381
g_print ("Remove input from dialog \n id : %u \n stream id : %i \n",
1385
/* remove from any models */
1386
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
1387
found = find_item_by_id (GTK_TREE_MODEL (model), id, ID_COLUMN, &iter);
1389
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
1394
_gtk_label_make_bold (GtkLabel *label)
1396
PangoFontDescription *font_desc;
1398
font_desc = pango_font_description_new ();
1400
pango_font_description_set_weight (font_desc,
1403
/* This will only affect the weight of the font, the rest is
1404
* from the current state of the widget, which comes from the
1405
* theme or user prefs, since the font desc only has the
1406
* weight flag turned on.
1408
gtk_widget_modify_font (GTK_WIDGET (label), font_desc);
1410
pango_font_description_free (font_desc);
1415
on_input_selection_changed (GtkTreeSelection *selection,
1416
GvcMixerDialog *dialog)
1418
GtkTreeModel *model;
1423
if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) {
1424
g_debug ("Could not get default input from selection");
1428
gtk_tree_model_get (model, &iter,
1430
ACTIVE_COLUMN, &toggled,
1434
GvcMixerUIDevice *input;
1435
//g_print ("on_input_selection_changed - try swap to input with id %u", id);
1436
input = gvc_mixer_control_lookup_input_id (dialog->priv->mixer_control, id);
1438
if (input == NULL) {
1439
g_warning ("on_input_selection_changed - Unable to find input with id: %u", id);
1443
gvc_mixer_control_change_input (dialog->priv->mixer_control, input);
1446
GvcMixerStream *stream;
1448
g_debug ("Default input selected: %u", id);
1449
stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, id);
1450
if (stream == NULL) {
1451
g_warning ("Unable to find stream for id: %u", id);
1455
gvc_mixer_control_set_default_source (dialog->priv->mixer_control, stream);
1460
on_output_selection_changed (GtkTreeSelection *selection,
1461
GvcMixerDialog *dialog)
1463
GtkTreeModel *model;
1468
if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) {
1469
g_debug ("Could not get default output from selection");
1473
gtk_tree_model_get (model, &iter,
1475
ACTIVE_COLUMN, &active,
1478
g_print ("\n\n on_output_selection_changed - active %i \n\n", active);
1483
GvcMixerUIDevice *output;
1484
g_print ("\n on_output_selection_changed - try swap to output with id %u", id);
1485
output = gvc_mixer_control_lookup_output_id (dialog->priv->mixer_control, id);
1487
if (output == NULL) {
1488
g_warning ("on_output_selection_changed - Unable to find output with id: %u", id);
1492
gvc_mixer_control_change_output (dialog->priv->mixer_control, output);
1496
name_to_text (GtkTreeViewColumn *column,
1497
GtkCellRenderer *cell,
1498
GtkTreeModel *model,
1502
char *name, *mapping;
1504
gtk_tree_model_get(model, iter,
1506
SPEAKERS_COLUMN, &mapping,
1509
if (mapping == NULL) {
1510
g_object_set (cell, "text", name, NULL);
1514
str = g_strdup_printf ("%s\n<i>%s</i>",
1516
g_object_set (cell, "markup", str, NULL);
1525
create_stream_treeview (GvcMixerDialog *dialog,
1526
GCallback on_selection_changed)
1528
GtkWidget *treeview;
1529
GtkListStore *store;
1530
GtkCellRenderer *renderer;
1531
GtkTreeViewColumn *column;
1532
GtkTreeSelection *selection;
1534
treeview = gtk_tree_view_new ();
1535
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
1537
store = gtk_list_store_new (NUM_COLUMNS,
1544
gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
1545
GTK_TREE_MODEL (store));
1547
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
1548
gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1550
column = gtk_tree_view_column_new ();
1551
gtk_tree_view_column_set_title (column, _("Name"));
1552
renderer = gtk_cell_renderer_pixbuf_new ();
1553
gtk_tree_view_column_pack_start (column, renderer, FALSE);
1554
g_object_set (G_OBJECT (renderer), "stock-size", GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
1555
gtk_tree_view_column_set_attributes (column, renderer,
1556
"gicon", ICON_COLUMN,
1559
renderer = gtk_cell_renderer_text_new ();
1560
gtk_tree_view_column_pack_start (column, renderer, TRUE);
1561
gtk_tree_view_column_set_cell_data_func (column, renderer,
1562
name_to_text, NULL, NULL);
1563
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1565
g_signal_connect ( selection, "changed",
1566
on_selection_changed, dialog);
1568
renderer = gtk_cell_renderer_text_new ();
1569
column = gtk_tree_view_column_new_with_attributes (_("Device"),
1571
"text", DEVICE_COLUMN,
1573
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1579
on_profile_changed (GvcComboBox *widget,
1580
const char *profile,
1585
card = g_object_get_data (G_OBJECT (widget), "card");
1587
g_warning ("Could not find card for combobox");
1591
g_debug ("Profile changed to %s for card %s", profile,
1592
gvc_mixer_card_get_name (card));
1594
gvc_mixer_card_change_profile (card, profile);
1598
on_test_speakers_clicked (GtkButton *widget,
1601
GvcMixerDialog *dialog = GVC_MIXER_DIALOG (user_data);
1602
GtkTreeModel *model;
1604
gint active_output = GVC_MIXER_UI_DEVICE_INVALID;
1606
model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
1607
gtk_tree_model_get_iter_first (model, &iter);
1609
// Fetch the active output from the treeview (hmmm...)
1612
gboolean is_selected = FALSE ;
1615
gtk_tree_model_get (model, &iter,
1617
ACTIVE_COLUMN, &is_selected,
1625
}while (gtk_tree_model_iter_next (model, &iter));
1627
if (active_output == GVC_MIXER_UI_DEVICE_INVALID) {
1628
g_warning ("Cant find the active output from the UI");
1632
GvcMixerUIDevice *output;
1633
output = gvc_mixer_control_lookup_output_id (dialog->priv->mixer_control, (guint)active_output);
1634
gint stream_id = gvc_mixer_ui_device_get_stream_id(output);
1636
if (stream_id == GVC_MIXER_UI_DEVICE_INVALID)
1639
g_print ("Test the speakers on the %s", gvc_mixer_ui_device_get_description (output));
1641
GvcMixerStream *stream;
1642
GvcMixerCardProfile *profile;
1643
GtkWidget *d, *speaker_test, *container;
1646
stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, stream_id);
1647
if (stream == NULL) {
1648
g_print ("Stream/sink not found");
1651
/* card = gvc_mixer_control_lookup_card_id (dialog->priv->mixer_control, card_id);
1653
profile = gvc_mixer_card_get_profile (card);
1655
g_debug ("XXX Start speaker testing for profile '%s', card %s XXX",
1656
profile->profile, gvc_mixer_card_get_name (card));
1658
title = g_strdup_printf (_("Speaker Testing for %s"), gvc_mixer_ui_device_get_description (output));
1659
d = gtk_dialog_new_with_buttons (title,
1660
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget))),
1661
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1662
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
1664
gtk_window_set_has_resize_grip (GTK_WINDOW (d), FALSE);
1667
speaker_test = gvc_speaker_test_new (dialog->priv->mixer_control,
1669
gtk_widget_show (speaker_test);
1670
container = gtk_dialog_get_content_area (GTK_DIALOG (d));
1671
gtk_container_add (GTK_CONTAINER (container), speaker_test);
1673
gtk_dialog_run (GTK_DIALOG (d));
1674
gtk_widget_destroy (d);
1678
gvc_mixer_dialog_constructor (GType type,
1679
guint n_construct_properties,
1680
GObjectConstructParam *construct_params)
1683
GvcMixerDialog *self;
1684
GtkWidget *main_vbox;
1686
GtkWidget *alignment;
1690
GtkWidget *test_sound_box;
1694
GvcMixerStream *stream;
1696
GtkTreeSelection *selection;
1698
object = G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->constructor (type, n_construct_properties, construct_params);
1700
self = GVC_MIXER_DIALOG (object);
1702
main_vbox = GTK_WIDGET (self);
1703
gtk_box_set_spacing (GTK_BOX (main_vbox), 2);
1705
gtk_container_set_border_width (GTK_CONTAINER (self), 6);
1707
self->priv->output_stream_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1708
alignment = gtk_alignment_new (0, 0, 1, 1);
1709
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 12, 0, 0, 0);
1710
gtk_container_add (GTK_CONTAINER (alignment), self->priv->output_stream_box);
1711
gtk_box_pack_start (GTK_BOX (main_vbox),
1715
self->priv->notebook = gtk_notebook_new ();
1716
gtk_box_pack_start (GTK_BOX (main_vbox),
1717
self->priv->notebook,
1719
gtk_container_set_border_width (GTK_CONTAINER (self->priv->notebook), 5);
1722
self->priv->sound_effects_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1723
gtk_container_set_border_width (GTK_CONTAINER (self->priv->sound_effects_box), 12);
1724
label = gtk_label_new (_("Sound Effects"));
1725
gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
1726
self->priv->sound_effects_box,
1729
self->priv->effects_bar = create_bar (self, FALSE, TRUE);
1730
gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->effects_bar),
1731
_("_Alert volume:"));
1732
gtk_widget_set_sensitive (self->priv->effects_bar, FALSE);
1733
gtk_box_pack_start (GTK_BOX (self->priv->sound_effects_box),
1734
self->priv->effects_bar, FALSE, FALSE, 0);
1736
self->priv->sound_theme_chooser = gvc_sound_theme_chooser_new ();
1737
gtk_box_pack_start (GTK_BOX (self->priv->sound_effects_box),
1738
self->priv->sound_theme_chooser,
1742
self->priv->input_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1743
gtk_container_set_border_width (GTK_CONTAINER (self->priv->input_box), 12);
1744
label = gtk_label_new (_("Input"));
1745
gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
1746
self->priv->input_box,
1748
box = gtk_frame_new (_("Record sound from:"));
1749
gtk_widget_set_size_request (GTK_WIDGET (box), 325, -1);
1750
label = gtk_frame_get_label_widget (GTK_FRAME (box));
1751
_gtk_label_make_bold (GTK_LABEL (label));
1752
gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
1753
gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
1754
gtk_box_pack_start (GTK_BOX (self->priv->input_box), box, FALSE, TRUE, 0);
1756
alignment = gtk_alignment_new (0, 0, 1, 1);
1757
gtk_container_add (GTK_CONTAINER (box), alignment);
1758
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0);
1760
self->priv->input_treeview = create_stream_treeview (self,
1761
G_CALLBACK (on_input_selection_changed));
1762
gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->input_treeview);
1764
box = gtk_scrolled_window_new (NULL, NULL);
1765
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (box),
1767
GTK_POLICY_AUTOMATIC);
1768
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (box),
1770
gtk_container_add (GTK_CONTAINER (box), self->priv->input_treeview);
1771
gtk_container_add (GTK_CONTAINER (alignment), box);
1773
self->priv->selected_input_label = gtk_label_new (_("Settings for the selected device:"));
1774
box = gtk_frame_new ("");
1775
gtk_frame_set_label_widget (GTK_FRAME (box), self->priv->selected_input_label);
1777
label = gtk_frame_get_label_widget (GTK_FRAME (box));
1778
_gtk_label_make_bold (GTK_LABEL (label));
1779
gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
1780
gtk_box_pack_start (GTK_BOX (self->priv->input_box), box, FALSE, FALSE, 0);
1781
self->priv->input_settings_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1783
self->priv->input_bar = create_bar (self, FALSE, TRUE);
1784
gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->input_bar),
1785
_("_Input volume:"));
1786
gvc_channel_bar_set_low_icon_name (GVC_CHANNEL_BAR (self->priv->input_bar),
1787
"audio-input-microphone-low-symbolic");
1788
gvc_channel_bar_set_high_icon_name (GVC_CHANNEL_BAR (self->priv->input_bar),
1789
"audio-input-microphone-high-symbolic");
1790
gtk_widget_set_sensitive (self->priv->input_bar, FALSE);
1792
if (self->priv->size_group != NULL) {
1793
gvc_channel_bar_set_size_group (GVC_CHANNEL_BAR (self->priv->input_bar),
1794
self->priv->size_group,
1798
gtk_box_pack_start (GTK_BOX (self->priv->input_settings_box),
1799
self->priv->input_bar,
1801
gtk_widget_show (self->priv->input_bar);
1803
gtk_container_add (GTK_CONTAINER (box), self->priv->input_settings_box);
1807
/* Creating a box and try to deal using the same size group. */
1808
GtkWidget *input_level_box;
1809
input_level_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1810
gtk_box_pack_start (GTK_BOX (self->priv->input_settings_box),
1816
sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1817
gtk_box_pack_start (GTK_BOX (input_level_box),
1821
label = gtk_label_new (_("Input level:"));
1822
gtk_box_pack_start (GTK_BOX (sbox),
1825
if (self->priv->size_group != NULL)
1826
gtk_size_group_add_widget (self->priv->size_group, sbox);
1829
self->priv->input_level_bar = gvc_level_bar_new ();
1830
gvc_level_bar_set_orientation (GVC_LEVEL_BAR (self->priv->input_level_bar),
1831
GTK_ORIENTATION_HORIZONTAL);
1832
gvc_level_bar_set_scale (GVC_LEVEL_BAR (self->priv->input_level_bar),
1833
GVC_LEVEL_SCALE_LINEAR);
1835
gtk_box_pack_start (GTK_BOX (input_level_box),
1836
self->priv->input_level_bar,
1841
self->priv->output_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1842
gtk_container_set_border_width (GTK_CONTAINER (self->priv->output_box), 12);
1843
label = gtk_label_new (_("Output"));
1844
gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
1845
self->priv->output_box,
1848
box = gtk_frame_new (_("Play sound through:"));
1849
gtk_widget_set_size_request (GTK_WIDGET (box), 325, -1);
1850
label = gtk_frame_get_label_widget (GTK_FRAME (box));
1851
_gtk_label_make_bold (GTK_LABEL (label));
1852
gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
1853
gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
1854
gtk_box_pack_start (GTK_BOX (self->priv->output_box), box, FALSE, TRUE, 0);
1856
alignment = gtk_alignment_new (0, 0, 1, 1);
1857
gtk_container_add (GTK_CONTAINER (box), alignment);
1858
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0);
1860
self->priv->output_treeview = create_stream_treeview (self,
1861
G_CALLBACK (on_output_selection_changed));
1862
gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->output_treeview);
1864
box = gtk_scrolled_window_new (NULL, NULL);
1865
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (box),
1867
GTK_POLICY_AUTOMATIC);
1868
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (box),
1870
gtk_container_add (GTK_CONTAINER (box), self->priv->output_treeview);
1871
gtk_container_add (GTK_CONTAINER (alignment), box);
1873
self->priv->selected_output_label = gtk_label_new (_("Settings for the selected device:"));
1874
box = gtk_frame_new ("");
1875
gtk_frame_set_label_widget (GTK_FRAME (box), self->priv->selected_output_label);
1877
label = gtk_frame_get_label_widget (GTK_FRAME (box));
1878
_gtk_label_make_bold (GTK_LABEL (label));
1879
gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
1881
gtk_box_pack_start (GTK_BOX (self->priv->output_box), box, FALSE, FALSE, 0);
1882
self->priv->output_settings_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1885
self->priv->output_balance_bar = gvc_balance_bar_new (BALANCE_TYPE_RL);
1886
if (self->priv->size_group != NULL) {
1887
gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (self->priv->output_balance_bar),
1888
self->priv->size_group,
1891
gtk_box_pack_start (GTK_BOX (self->priv->output_settings_box),
1892
self->priv->output_balance_bar,
1894
gtk_widget_show (self->priv->output_balance_bar);
1896
self->priv->output_fade_bar = gvc_balance_bar_new (BALANCE_TYPE_FR);
1897
if (self->priv->size_group != NULL) {
1898
gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (self->priv->output_fade_bar),
1899
self->priv->size_group,
1902
gtk_box_pack_start (GTK_BOX (self->priv->output_settings_box),
1903
self->priv->output_fade_bar,
1905
gtk_widget_show (self->priv->output_fade_bar);
1907
self->priv->output_lfe_bar = gvc_balance_bar_new (BALANCE_TYPE_LFE);
1908
if (self->priv->size_group != NULL) {
1909
gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (self->priv->output_lfe_bar),
1910
self->priv->size_group,
1913
gtk_box_pack_start (GTK_BOX (self->priv->output_settings_box),
1914
self->priv->output_lfe_bar,
1916
gtk_widget_show (self->priv->output_lfe_bar);
1919
self->priv->output_port_combo = gvc_combo_box_new (_("Modes:"));
1920
g_signal_connect (G_OBJECT (self->priv->output_port_combo), "changed",
1921
G_CALLBACK (profile_selection_changed), self);
1922
gtk_box_pack_start (GTK_BOX (self->priv->output_settings_box),
1923
self->priv->output_port_combo,
1926
if (self->priv->size_group != NULL) {
1927
gvc_combo_box_set_size_group (GVC_COMBO_BOX (self->priv->output_port_combo),
1928
self->priv->size_group, FALSE);
1930
gtk_widget_show (self->priv->output_port_combo);
1932
/* Creating a box and try to deal using the same size group. */
1933
test_sound_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1934
gtk_box_pack_end (GTK_BOX (self->priv->output_settings_box),
1940
sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1941
gtk_box_pack_start (GTK_BOX (test_sound_box),
1945
label = gtk_label_new (_("Test:"));
1946
gtk_box_pack_start (GTK_BOX (sbox),
1949
if (self->priv->size_group != NULL)
1950
gtk_size_group_add_widget (self->priv->size_group, sbox);
1952
self->priv->test_output_button = gtk_button_new_with_label ("Test Sound");
1954
/* FIXME: I am getting mental with all these hardcoded padding values,
1955
* Here 8 works fine, not sure why. */
1956
gtk_box_pack_start (GTK_BOX (test_sound_box),
1957
self->priv->test_output_button,
1960
/* Is this needed */
1961
if (self->priv->size_group != NULL)
1962
gtk_size_group_add_widget (self->priv->size_group, self->priv->test_output_button);
1964
gtk_widget_show (test_sound_box);
1966
gtk_container_add (GTK_CONTAINER (box), self->priv->output_settings_box);
1967
g_signal_connect (self->priv->test_output_button,
1969
G_CALLBACK (on_test_speakers_clicked),
1973
self->priv->applications_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1974
gtk_container_set_border_width (GTK_CONTAINER (self->priv->applications_box), 12);
1975
label = gtk_label_new (_("Applications"));
1976
gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
1977
self->priv->applications_box,
1979
self->priv->no_apps_label = gtk_label_new (_("No application is currently playing or recording audio."));
1980
gtk_box_pack_start (GTK_BOX (self->priv->applications_box),
1981
self->priv->no_apps_label,
1984
self->priv->output_stream_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1985
alignment = gtk_alignment_new (0, 0, 1, 1);
1986
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 12, 0, 0, 0);
1987
gtk_container_add (GTK_CONTAINER (alignment), self->priv->output_stream_box);
1988
gtk_box_pack_start (GTK_BOX (main_vbox),
1992
self->priv->output_bar = create_bar (self, FALSE, TRUE);
1993
gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->output_bar),
1994
_("_Output volume:"));
1995
gtk_widget_set_sensitive (self->priv->output_bar, FALSE);
1996
gtk_widget_set_size_request (self->priv->output_bar, 460, -1);
1998
gtk_box_pack_start (GTK_BOX (self->priv->output_stream_box),
1999
self->priv->output_bar, TRUE, FALSE, 12);
2001
gtk_widget_show_all (main_vbox);
2003
g_signal_connect (self->priv->mixer_control,
2005
G_CALLBACK (on_control_stream_added),
2007
g_signal_connect (self->priv->mixer_control,
2009
G_CALLBACK (on_control_stream_removed),
2011
g_signal_connect (self->priv->mixer_control,
2013
G_CALLBACK (on_control_output_added),
2015
g_signal_connect (self->priv->mixer_control,
2017
G_CALLBACK (on_control_output_removed),
2019
/*g_signal_connect (self->priv->mixer_control,
2020
"active-output-update",
2021
G_CALLBACK (on_control_active_output_update),
2023
g_signal_connect (self->priv->mixer_control,
2025
G_CALLBACK (on_control_input_added),
2027
g_signal_connect (self->priv->mixer_control,
2029
G_CALLBACK (on_control_input_removed),
2031
/*g_signal_connect (self->priv->mixer_control,
2032
"active-input-update",
2033
G_CALLBACK (on_control_active_input_update),
2036
//// The below code is redundant, for some reason no cards or sinks
2037
//// are returned at this point.
2042
//streams = gvc_mixer_control_get_streams (self->priv->mixer_control);
2043
//for (l = streams; l != NULL; l = l->next) {
2044
//////stream = l->data;
2045
////add_stream (self, stream);
2047
////g_slist_free (streams);
2049
////cards = gvc_mixer_control_get_cards (self->priv->mixer_control);
2051
////for (l = cards; l != NULL; l = l->next) {
2053
////add_card (self, card);
2054
////g_print ("about to add a card");
2056
////g_slist_free (cards);
2062
gvc_mixer_dialog_dispose (GObject *object)
2064
GvcMixerDialog *dialog = GVC_MIXER_DIALOG (object);
2066
if (dialog->priv->mixer_control != NULL) {
2067
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2068
on_control_output_added,
2070
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2071
on_control_output_removed,
2073
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2074
on_control_active_input_update,
2076
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2077
on_control_active_output_update,
2079
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2080
on_control_input_added,
2082
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2083
on_control_input_removed,
2085
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2086
on_control_stream_added,
2088
g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2089
on_control_stream_removed,
2091
g_object_unref (dialog->priv->mixer_control);
2092
dialog->priv->mixer_control = NULL;
2095
if (dialog->priv->bars != NULL) {
2096
g_hash_table_destroy (dialog->priv->bars);
2097
dialog->priv->bars = NULL;
2100
G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->dispose (object);
2104
gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass)
2106
GObjectClass *object_class = G_OBJECT_CLASS (klass);
2108
object_class->constructor = gvc_mixer_dialog_constructor;
2109
object_class->dispose = gvc_mixer_dialog_dispose;
2110
object_class->finalize = gvc_mixer_dialog_finalize;
2111
object_class->set_property = gvc_mixer_dialog_set_property;
2112
object_class->get_property = gvc_mixer_dialog_get_property;
2114
g_object_class_install_property (object_class,
2116
g_param_spec_object ("mixer-control",
2119
GVC_TYPE_MIXER_CONTROL,
2120
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2122
g_type_class_add_private (klass, sizeof (GvcMixerDialogPrivate));
2127
gvc_mixer_dialog_init (GvcMixerDialog *dialog)
2129
dialog->priv = GVC_MIXER_DIALOG_GET_PRIVATE (dialog);
2130
dialog->priv->bars = g_hash_table_new (NULL, NULL);
2131
dialog->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
2135
gvc_mixer_dialog_finalize (GObject *object)
2137
GvcMixerDialog *mixer_dialog;
2139
g_return_if_fail (object != NULL);
2140
g_return_if_fail (GVC_IS_MIXER_DIALOG (object));
2142
mixer_dialog = GVC_MIXER_DIALOG (object);
2144
g_return_if_fail (mixer_dialog->priv != NULL);
2145
G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->finalize (object);
2149
gvc_mixer_dialog_new (GvcMixerControl *control)
2152
dialog = g_object_new (GVC_TYPE_MIXER_DIALOG,
2153
"mixer-control", control,
2155
return GVC_MIXER_DIALOG (dialog);
2167
gvc_mixer_dialog_set_page (GvcMixerDialog *self,
2172
g_return_val_if_fail (self != NULL, FALSE);
2176
else if (g_str_equal (page, "effects"))
2178
else if (g_str_equal (page, "input"))
2180
else if (g_str_equal (page, "output"))
2182
else if (g_str_equal (page, "applications"))
2183
num = PAGE_APPLICATIONS;
2187
gtk_notebook_set_current_page (GTK_NOTEBOOK (self->priv->notebook), num);