~ubuntu-branches/ubuntu/precise/gnome-control-center/precise-updates

« back to all changes in this revision

Viewing changes to .pc/90_git_sound_tab_order.patch/panels/sound/gvc-mixer-dialog.c

  • Committer: Package Import Robot
  • Author(s): Sebastien Bacher, Jeremy Bicha, Ken VanDine
  • Date: 2012-02-15 23:16:31 UTC
  • mfrom: (1.1.56)
  • Revision ID: package-import@ubuntu.com-20120215231631-vk7me0mhofpsq0hp
Tags: 1:3.3.5-0ubuntu1
* Upload the new serie, that will bring in quite some fixes, we revert
  some problematic or risky changes as well
* The new version includes those fixes:
  - "Change Password in User Accounts panel focuses "New password" field, 
     skipping "Current password"" (lp: #821759)
  - The dialog to add online accounts should have a title 
    (lp: #822380)
  - "Remove Profile" button clickable in Color panel when 
     no profile selected (lp: #869603)
  - Move Removable Media into System Info (lp: #835880)
  - Sound preferences: mouse scrolling balance only works for right.
    (lp: #918017)
  - gnome-control-center SIGSEGV in actualize_printers_list() 
    (lp: #903009)
  - selecting preffered applications is not an info (lp: #890143)
  - Add a keyboard shortcut by default for take screenshot of a selection"
    (lp: #625518)
* debian/patches/revert_git_datetime_port.patch:
  - revert use of datetimed, we don't use systemd and ubuntu-system-service 
    doesn't support it yet
* debian/patches/revert_git_drop_library.patch:
  - consolidate "01_allow_external_panels.patch", don't drop the library
    we use it from other components on ubuntu, the patch will be improved
    later to not use a copy of files like it does in that version
* debian/patches/revert_git_stop_using_gconf.patch,
  debian/patches/revert_ua_gsettings.patch,
  debian/patches/revert_git_keyboard_gsettings.patch:
  - revert keyboard porting to gsettings, compiz still use gconf and we
    didn't update gnome-shell to the new serie (yet)

[ Jeremy Bicha ]
* New upstream release (Thanks Rico Tzchichholz!)
* debian/control.in:
  - Bump minimum dependency versions and add libwacom dependency
* debian/rules: Build without -Wl,-z,defs
* debian/watch: Watch for unstable releases
* Refreshed patches:
  - 01_allow_external_panels.patch
  - 04_add_theme_selection.patch
  - 50_ubuntu_systemwide_prefs.patch
  - 58_ubuntu_icon_views_redesign.patch
  - 59_install_gcm_components_on_demand.patch
  - 91_configure_cheese.patch
* Dropped upstream patches:
  - 00git_handle_media_dialog_close.patch
  - 03_show_wacom_under_unity.patch
  - 90_git_sound_tab_order.patch
  - 91_git_build_use_fontconfig.patch
  - 92_git_minimal_output_height.patch
  - 93_change_window_role_on_panel_change.patch
  - 94_git_adding_shortcuts.patch
  - 95_git_ctrlw_shortcut.patch
  - git_extra_keywords.patch

[ Ken VanDine ]
* debian/patches/96_sound_nua_panel.patch
  - refreshed with latest changes from ronoc

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2
 
 *
3
 
 * Copyright (C) 2008 William Jon McCann
4
 
 *
5
 
 * This program is free software; you can redistribute it and/or modify
6
 
 * it under the terms of the GNU General Public License as published by
7
 
 * the Free Software Foundation; either version 2 of the License, or
8
 
 * (at your option) any later version.
9
 
 *
10
 
 * This program is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 * GNU General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU General Public License
16
 
 * along with this program; if not, write to the Free Software
17
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
 
 *
19
 
 */
20
 
 
21
 
#include "config.h"
22
 
 
23
 
#include <stdlib.h>
24
 
#include <stdio.h>
25
 
#include <unistd.h>
26
 
 
27
 
#include <glib.h>
28
 
#include <glib/gi18n-lib.h>
29
 
#include <gdk/gdkkeysyms.h>
30
 
#include <gtk/gtk.h>
31
 
#include <pulse/pulseaudio.h>
32
 
 
33
 
#include "gvc-channel-bar.h"
34
 
#include "gvc-balance-bar.h"
35
 
#include "gvc-combo-box.h"
36
 
#include "gvc-mixer-control.h"
37
 
#include "gvc-mixer-card.h"
38
 
#include "gvc-mixer-sink.h"
39
 
#include "gvc-mixer-source.h"
40
 
#include "gvc-mixer-source-output.h"
41
 
#include "gvc-mixer-dialog.h"
42
 
#include "gvc-sound-theme-chooser.h"
43
 
#include "gvc-level-bar.h"
44
 
#include "gvc-speaker-test.h"
45
 
#include "gvc-mixer-control-private.h"
46
 
 
47
 
#define SCALE_SIZE 128
48
 
 
49
 
#define GVC_MIXER_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_DIALOG, GvcMixerDialogPrivate))
50
 
 
51
 
struct GvcMixerDialogPrivate
52
 
{
53
 
        GvcMixerControl *mixer_control;
54
 
        GHashTable      *bars;
55
 
        GtkWidget       *notebook;
56
 
        GtkWidget       *output_bar;
57
 
        GtkWidget       *input_bar;
58
 
        GtkWidget       *input_level_bar;
59
 
        GtkWidget       *effects_bar;
60
 
        GtkWidget       *output_stream_box;
61
 
        GtkWidget       *sound_effects_box;
62
 
        GtkWidget       *hw_box;
63
 
        GtkWidget       *hw_treeview;
64
 
        GtkWidget       *hw_settings_box;
65
 
        GtkWidget       *hw_profile_combo;
66
 
        GtkWidget       *input_box;
67
 
        GtkWidget       *output_box;
68
 
        GtkWidget       *applications_box;
69
 
        GtkWidget       *no_apps_label;
70
 
        GtkWidget       *output_treeview;
71
 
        GtkWidget       *output_settings_box;
72
 
        GtkWidget       *output_balance_bar;
73
 
        GtkWidget       *output_fade_bar;
74
 
        GtkWidget       *output_lfe_bar;
75
 
        GtkWidget       *output_port_combo;
76
 
        GtkWidget       *input_treeview;
77
 
        GtkWidget       *input_port_combo;
78
 
        GtkWidget       *input_settings_box;
79
 
        GtkWidget       *sound_theme_chooser;
80
 
        GtkWidget       *click_feedback_button;
81
 
        GtkWidget       *audible_bell_button;
82
 
        GtkSizeGroup    *size_group;
83
 
 
84
 
        gdouble          last_input_peak;
85
 
        guint            num_apps;
86
 
};
87
 
 
88
 
enum {
89
 
        NAME_COLUMN,
90
 
        DEVICE_COLUMN,
91
 
        ACTIVE_COLUMN,
92
 
        ID_COLUMN,
93
 
        SPEAKERS_COLUMN,
94
 
        ICON_COLUMN,
95
 
        NUM_COLUMNS
96
 
};
97
 
 
98
 
enum {
99
 
        HW_ID_COLUMN,
100
 
        HW_ICON_COLUMN,
101
 
        HW_NAME_COLUMN,
102
 
        HW_STATUS_COLUMN,
103
 
        HW_PROFILE_COLUMN,
104
 
        HW_PROFILE_HUMAN_COLUMN,
105
 
        HW_SENSITIVE_COLUMN,
106
 
        HW_NUM_COLUMNS
107
 
};
108
 
 
109
 
enum
110
 
{
111
 
        PROP_0,
112
 
        PROP_MIXER_CONTROL
113
 
};
114
 
 
115
 
static void     gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass);
116
 
static void     gvc_mixer_dialog_init       (GvcMixerDialog      *mixer_dialog);
117
 
static void     gvc_mixer_dialog_finalize   (GObject             *object);
118
 
 
119
 
static void     bar_set_stream              (GvcMixerDialog      *dialog,
120
 
                                             GtkWidget           *bar,
121
 
                                             GvcMixerStream      *stream);
122
 
 
123
 
static void     on_adjustment_value_changed (GtkAdjustment  *adjustment,
124
 
                                             GvcMixerDialog *dialog);
125
 
 
126
 
G_DEFINE_TYPE (GvcMixerDialog, gvc_mixer_dialog, GTK_TYPE_VBOX)
127
 
 
128
 
static void
129
 
update_default_input (GvcMixerDialog *dialog)
130
 
{
131
 
        GtkTreeModel *model;
132
 
        GtkTreeIter   iter;
133
 
        gboolean      ret;
134
 
 
135
 
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
136
 
        ret = gtk_tree_model_get_iter_first (model, &iter);
137
 
        if (ret == FALSE) {
138
 
                g_debug ("No default input selected or available");
139
 
                return;
140
 
        }
141
 
        do {
142
 
                gboolean        toggled;
143
 
                gboolean        is_default;
144
 
                guint           id;
145
 
                GvcMixerStream *stream;
146
 
 
147
 
                gtk_tree_model_get (model, &iter,
148
 
                                    ID_COLUMN, &id,
149
 
                                    ACTIVE_COLUMN, &toggled,
150
 
                                    -1);
151
 
 
152
 
                stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, id);
153
 
                if (stream == NULL) {
154
 
                        g_warning ("Unable to find stream for id: %u", id);
155
 
                        continue;
156
 
                }
157
 
 
158
 
                is_default = FALSE;
159
 
                if (stream == gvc_mixer_control_get_default_source (dialog->priv->mixer_control)) {
160
 
                        is_default = TRUE;
161
 
                }
162
 
 
163
 
                gtk_list_store_set (GTK_LIST_STORE (model),
164
 
                                    &iter,
165
 
                                    ACTIVE_COLUMN, is_default,
166
 
                                    -1);
167
 
                if (is_default) {
168
 
                        GtkTreeSelection *selection;
169
 
 
170
 
                        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->input_treeview));
171
 
                        gtk_tree_selection_select_iter (selection, &iter);
172
 
                }
173
 
        } while (gtk_tree_model_iter_next (model, &iter));
174
 
}
175
 
 
176
 
static void
177
 
update_description (GvcMixerDialog *dialog,
178
 
                    guint column,
179
 
                    const char *value,
180
 
                    GvcMixerStream *stream)
181
 
{
182
 
        GtkTreeModel *model;
183
 
        GtkTreeIter   iter;
184
 
        guint         id;
185
 
 
186
 
        if (GVC_IS_MIXER_SOURCE (stream))
187
 
                model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
188
 
        else if (GVC_IS_MIXER_SINK (stream))
189
 
                model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
190
 
        else
191
 
                g_assert_not_reached ();
192
 
        gtk_tree_model_get_iter_first (model, &iter);
193
 
 
194
 
        id = gvc_mixer_stream_get_id (stream);
195
 
        do {
196
 
                guint       current_id;
197
 
 
198
 
                gtk_tree_model_get (model, &iter,
199
 
                                    ID_COLUMN, &current_id,
200
 
                                    -1);
201
 
                if (id != current_id)
202
 
                        continue;
203
 
 
204
 
                gtk_list_store_set (GTK_LIST_STORE (model),
205
 
                                    &iter,
206
 
                                    column, value,
207
 
                                    -1);
208
 
                break;
209
 
        } while (gtk_tree_model_iter_next (model, &iter));
210
 
}
211
 
 
212
 
static void
213
 
port_selection_changed (GvcComboBox *combo_box,
214
 
                        const char  *port,
215
 
                        GvcMixerDialog *dialog)
216
 
{
217
 
        GvcMixerStream *stream;
218
 
 
219
 
        stream = g_object_get_data (G_OBJECT (combo_box), "stream");
220
 
        if (stream == NULL) {
221
 
                g_warning ("Could not find stream for port combo box");
222
 
                return;
223
 
        }
224
 
        if (gvc_mixer_stream_change_port (stream, port) == FALSE) {
225
 
                g_warning ("Could not change port for stream");
226
 
        }
227
 
}
228
 
 
229
 
static void
230
 
update_output_settings (GvcMixerDialog *dialog)
231
 
{
232
 
        GvcMixerStream      *stream;
233
 
        const GvcChannelMap *map;
234
 
        const GList         *ports;
235
 
        GtkAdjustment       *adj;
236
 
 
237
 
        g_debug ("Updating output settings");
238
 
        if (dialog->priv->output_balance_bar != NULL) {
239
 
                gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box),
240
 
                                      dialog->priv->output_balance_bar);
241
 
                dialog->priv->output_balance_bar = NULL;
242
 
        }
243
 
        if (dialog->priv->output_fade_bar != NULL) {
244
 
                gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box),
245
 
                                      dialog->priv->output_fade_bar);
246
 
                dialog->priv->output_fade_bar = NULL;
247
 
        }
248
 
        if (dialog->priv->output_lfe_bar != NULL) {
249
 
                gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box),
250
 
                                      dialog->priv->output_lfe_bar);
251
 
                dialog->priv->output_lfe_bar = NULL;
252
 
        }
253
 
        if (dialog->priv->output_port_combo != NULL) {
254
 
                gtk_container_remove (GTK_CONTAINER (dialog->priv->output_settings_box),
255
 
                                      dialog->priv->output_port_combo);
256
 
                dialog->priv->output_port_combo = NULL;
257
 
        }
258
 
 
259
 
        stream = gvc_mixer_control_get_default_sink (dialog->priv->mixer_control);
260
 
        if (stream == NULL) {
261
 
                g_warning ("Default sink stream not found");
262
 
                return;
263
 
        }
264
 
 
265
 
        gvc_channel_bar_set_base_volume (GVC_CHANNEL_BAR (dialog->priv->output_bar),
266
 
                                         gvc_mixer_stream_get_base_volume (stream));
267
 
        gvc_channel_bar_set_is_amplified (GVC_CHANNEL_BAR (dialog->priv->output_bar),
268
 
                                          gvc_mixer_stream_get_can_decibel (stream));
269
 
 
270
 
        /* Update the adjustment in case the previous bar wasn't decibel
271
 
         * capable, and we clipped it */
272
 
        adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->output_bar)));
273
 
        gtk_adjustment_set_value (adj,
274
 
                                  gvc_mixer_stream_get_volume (stream));
275
 
 
276
 
        map = gvc_mixer_stream_get_channel_map (stream);
277
 
        if (map == NULL) {
278
 
                g_warning ("Default sink stream has no channel map");
279
 
                return;
280
 
        }
281
 
 
282
 
        dialog->priv->output_balance_bar = gvc_balance_bar_new (map, BALANCE_TYPE_RL);
283
 
        if (dialog->priv->size_group != NULL) {
284
 
                gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (dialog->priv->output_balance_bar),
285
 
                                                dialog->priv->size_group,
286
 
                                                TRUE);
287
 
        }
288
 
        gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box),
289
 
                            dialog->priv->output_balance_bar,
290
 
                            FALSE, FALSE, 6);
291
 
        gtk_widget_show (dialog->priv->output_balance_bar);
292
 
 
293
 
        if (gvc_channel_map_can_fade (map)) {
294
 
                dialog->priv->output_fade_bar = gvc_balance_bar_new (map, BALANCE_TYPE_FR);
295
 
                if (dialog->priv->size_group != NULL) {
296
 
                        gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (dialog->priv->output_fade_bar),
297
 
                                                        dialog->priv->size_group,
298
 
                                                        TRUE);
299
 
                }
300
 
                gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box),
301
 
                                    dialog->priv->output_fade_bar,
302
 
                                    FALSE, FALSE, 6);
303
 
                gtk_widget_show (dialog->priv->output_fade_bar);
304
 
        }
305
 
 
306
 
        if (gvc_channel_map_has_lfe (map)) {
307
 
                dialog->priv->output_lfe_bar = gvc_balance_bar_new (map, BALANCE_TYPE_LFE);
308
 
                if (dialog->priv->size_group != NULL) {
309
 
                        gvc_balance_bar_set_size_group (GVC_BALANCE_BAR (dialog->priv->output_lfe_bar),
310
 
                                                        dialog->priv->size_group,
311
 
                                                        TRUE);
312
 
                }
313
 
                gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box),
314
 
                                    dialog->priv->output_lfe_bar,
315
 
                                    FALSE, FALSE, 6);
316
 
                gtk_widget_show (dialog->priv->output_lfe_bar);
317
 
        }
318
 
 
319
 
        ports = gvc_mixer_stream_get_ports (stream);
320
 
        if (ports != NULL) {
321
 
                const GvcMixerStreamPort *port;
322
 
                port = gvc_mixer_stream_get_port (stream);
323
 
 
324
 
                dialog->priv->output_port_combo = gvc_combo_box_new (_("Co_nnector:"));
325
 
                gvc_combo_box_set_ports (GVC_COMBO_BOX (dialog->priv->output_port_combo),
326
 
                                         ports);
327
 
                gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->output_port_combo), port->port);
328
 
                g_object_set_data (G_OBJECT (dialog->priv->output_port_combo), "stream", stream);
329
 
                g_signal_connect (G_OBJECT (dialog->priv->output_port_combo), "changed",
330
 
                                  G_CALLBACK (port_selection_changed), dialog);
331
 
 
332
 
                gtk_box_pack_start (GTK_BOX (dialog->priv->output_settings_box),
333
 
                                    dialog->priv->output_port_combo,
334
 
                                    TRUE, FALSE, 6);
335
 
 
336
 
                if (dialog->priv->size_group != NULL) {
337
 
                        gvc_combo_box_set_size_group (GVC_COMBO_BOX (dialog->priv->output_port_combo),
338
 
                                                      dialog->priv->size_group, FALSE);
339
 
                }
340
 
 
341
 
                gtk_widget_show (dialog->priv->output_port_combo);
342
 
        }
343
 
 
344
 
        /* FIXME: We could make this into a "No settings" label instead */
345
 
        gtk_widget_set_sensitive (dialog->priv->output_balance_bar, gvc_channel_map_can_balance (map));
346
 
}
347
 
 
348
 
static void
349
 
update_default_output (GvcMixerDialog *dialog)
350
 
{
351
 
        GtkTreeModel *model;
352
 
        GtkTreeIter   iter;
353
 
 
354
 
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
355
 
        gtk_tree_model_get_iter_first (model, &iter);
356
 
        do {
357
 
                gboolean        toggled;
358
 
                gboolean        is_default;
359
 
                guint           id;
360
 
                GvcMixerStream *stream;
361
 
 
362
 
                gtk_tree_model_get (model, &iter,
363
 
                                    ID_COLUMN, &id,
364
 
                                    ACTIVE_COLUMN, &toggled,
365
 
                                    -1);
366
 
 
367
 
                stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, id);
368
 
                if (stream == NULL) {
369
 
                        g_warning ("Unable to find stream for id: %u", id);
370
 
                        continue;
371
 
                }
372
 
 
373
 
                is_default = FALSE;
374
 
                if (stream == gvc_mixer_control_get_default_sink (dialog->priv->mixer_control)) {
375
 
                        is_default = TRUE;
376
 
                }
377
 
 
378
 
                gtk_list_store_set (GTK_LIST_STORE (model),
379
 
                                    &iter,
380
 
                                    ACTIVE_COLUMN, is_default,
381
 
                                    -1);
382
 
                if (is_default) {
383
 
                        GtkTreeSelection *selection;
384
 
 
385
 
                        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->output_treeview));
386
 
                        gtk_tree_selection_select_iter (selection, &iter);
387
 
                }
388
 
        } while (gtk_tree_model_iter_next (model, &iter));
389
 
}
390
 
 
391
 
static void
392
 
on_mixer_control_default_sink_changed (GvcMixerControl *control,
393
 
                                       guint            id,
394
 
                                       GvcMixerDialog  *dialog)
395
 
{
396
 
        GvcMixerStream *stream;
397
 
 
398
 
        g_debug ("GvcMixerDialog: default sink changed: %u", id);
399
 
 
400
 
        if (id == PA_INVALID_INDEX)
401
 
                stream = NULL;
402
 
        else
403
 
                stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control,
404
 
                                                             id);
405
 
        bar_set_stream (dialog, dialog->priv->output_bar, stream);
406
 
 
407
 
        update_output_settings (dialog);
408
 
 
409
 
        update_default_output (dialog);
410
 
}
411
 
 
412
 
 
413
 
#define DECAY_STEP .15
414
 
 
415
 
static void
416
 
update_input_peak (GvcMixerDialog *dialog,
417
 
                   gdouble         v)
418
 
{
419
 
        GtkAdjustment *adj;
420
 
 
421
 
        if (dialog->priv->last_input_peak >= DECAY_STEP) {
422
 
                if (v < dialog->priv->last_input_peak - DECAY_STEP) {
423
 
                        v = dialog->priv->last_input_peak - DECAY_STEP;
424
 
                }
425
 
        }
426
 
 
427
 
        dialog->priv->last_input_peak = v;
428
 
 
429
 
        adj = gvc_level_bar_get_peak_adjustment (GVC_LEVEL_BAR (dialog->priv->input_level_bar));
430
 
        if (v >= 0) {
431
 
                gtk_adjustment_set_value (adj, v);
432
 
        } else {
433
 
                gtk_adjustment_set_value (adj, 0.0);
434
 
        }
435
 
}
436
 
 
437
 
static void
438
 
update_input_meter (GvcMixerDialog *dialog,
439
 
                    uint32_t        source_index,
440
 
                    uint32_t        sink_input_idx,
441
 
                    double          v)
442
 
{
443
 
        update_input_peak (dialog, v);
444
 
}
445
 
 
446
 
static void
447
 
on_monitor_suspended_callback (pa_stream *s,
448
 
                               void      *userdata)
449
 
{
450
 
        GvcMixerDialog *dialog;
451
 
 
452
 
        dialog = userdata;
453
 
 
454
 
        if (pa_stream_is_suspended (s)) {
455
 
                g_debug ("Stream suspended");
456
 
                update_input_meter (dialog,
457
 
                                    pa_stream_get_device_index (s),
458
 
                                    PA_INVALID_INDEX,
459
 
                                    -1);
460
 
        }
461
 
}
462
 
 
463
 
static void
464
 
on_monitor_read_callback (pa_stream *s,
465
 
                          size_t     length,
466
 
                          void      *userdata)
467
 
{
468
 
        GvcMixerDialog *dialog;
469
 
        const void     *data;
470
 
        double          v;
471
 
 
472
 
        dialog = userdata;
473
 
 
474
 
        if (pa_stream_peek (s, &data, &length) < 0) {
475
 
                g_warning ("Failed to read data from stream");
476
 
                return;
477
 
        }
478
 
 
479
 
        assert (length > 0);
480
 
        assert (length % sizeof (float) == 0);
481
 
 
482
 
        v = ((const float *) data)[length / sizeof (float) -1];
483
 
 
484
 
        pa_stream_drop (s);
485
 
 
486
 
        if (v < 0) {
487
 
                v = 0;
488
 
        }
489
 
        if (v > 1) {
490
 
                v = 1;
491
 
        }
492
 
 
493
 
        update_input_meter (dialog,
494
 
                            pa_stream_get_device_index (s),
495
 
                            pa_stream_get_monitor_stream (s),
496
 
                            v);
497
 
}
498
 
 
499
 
static void
500
 
create_monitor_stream_for_source (GvcMixerDialog *dialog,
501
 
                                  GvcMixerStream *stream)
502
 
{
503
 
        pa_stream     *s;
504
 
        char           t[16];
505
 
        pa_buffer_attr attr;
506
 
        pa_sample_spec ss;
507
 
        pa_context    *context;
508
 
        int            res;
509
 
        pa_proplist   *proplist;
510
 
        gboolean       has_monitor;
511
 
 
512
 
        if (stream == NULL) {
513
 
                return;
514
 
        }
515
 
        has_monitor = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (stream), "has-monitor"));
516
 
        if (has_monitor != FALSE) {
517
 
                return;
518
 
        }
519
 
 
520
 
        g_debug ("Create monitor for %u",
521
 
                 gvc_mixer_stream_get_index (stream));
522
 
 
523
 
        context = gvc_mixer_control_get_pa_context (dialog->priv->mixer_control);
524
 
 
525
 
        if (pa_context_get_server_protocol_version (context) < 13) {
526
 
                return;
527
 
        }
528
 
 
529
 
        ss.channels = 1;
530
 
        ss.format = PA_SAMPLE_FLOAT32;
531
 
        ss.rate = 25;
532
 
 
533
 
        memset (&attr, 0, sizeof (attr));
534
 
        attr.fragsize = sizeof (float);
535
 
        attr.maxlength = (uint32_t) -1;
536
 
 
537
 
        snprintf (t, sizeof (t), "%u", gvc_mixer_stream_get_index (stream));
538
 
 
539
 
        proplist = pa_proplist_new ();
540
 
        pa_proplist_sets (proplist, PA_PROP_APPLICATION_ID, "org.gnome.VolumeControl");
541
 
        s = pa_stream_new_with_proplist (context, _("Peak detect"), &ss, NULL, proplist);
542
 
        pa_proplist_free (proplist);
543
 
        if (s == NULL) {
544
 
                g_warning ("Failed to create monitoring stream");
545
 
                return;
546
 
        }
547
 
 
548
 
        pa_stream_set_read_callback (s, on_monitor_read_callback, dialog);
549
 
        pa_stream_set_suspended_callback (s, on_monitor_suspended_callback, dialog);
550
 
 
551
 
        res = pa_stream_connect_record (s,
552
 
                                        t,
553
 
                                        &attr,
554
 
                                        (pa_stream_flags_t) (PA_STREAM_DONT_MOVE
555
 
                                                             |PA_STREAM_PEAK_DETECT
556
 
                                                             |PA_STREAM_ADJUST_LATENCY));
557
 
        if (res < 0) {
558
 
                g_warning ("Failed to connect monitoring stream");
559
 
                pa_stream_unref (s);
560
 
        } else {
561
 
                g_object_set_data (G_OBJECT (stream), "has-monitor", GINT_TO_POINTER (TRUE));
562
 
                g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream", s);
563
 
                g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "stream", stream);
564
 
        }
565
 
}
566
 
 
567
 
static void
568
 
stop_monitor_stream_for_source (GvcMixerDialog *dialog)
569
 
{
570
 
        pa_stream      *s;
571
 
        pa_context     *context;
572
 
        int             res;
573
 
        GvcMixerStream *stream;
574
 
 
575
 
        s = g_object_get_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream");
576
 
        if (s == NULL)
577
 
                return;
578
 
        stream = g_object_get_data (G_OBJECT (dialog->priv->input_level_bar), "stream");
579
 
        g_assert (stream != NULL);
580
 
 
581
 
        g_debug ("Stopping monitor for %u", pa_stream_get_index (s));
582
 
 
583
 
        context = gvc_mixer_control_get_pa_context (dialog->priv->mixer_control);
584
 
 
585
 
        if (pa_context_get_server_protocol_version (context) < 13) {
586
 
                return;
587
 
        }
588
 
 
589
 
        res = pa_stream_disconnect (s);
590
 
        if (res == 0)
591
 
                g_object_set_data (G_OBJECT (stream), "has-monitor", GINT_TO_POINTER (FALSE));
592
 
        g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "pa_stream", NULL);
593
 
        g_object_set_data (G_OBJECT (dialog->priv->input_level_bar), "stream", NULL);
594
 
}
595
 
 
596
 
static void
597
 
update_input_settings (GvcMixerDialog *dialog)
598
 
{
599
 
        const GList    *ports;
600
 
        GvcMixerStream *stream;
601
 
        GtkAdjustment  *adj;
602
 
 
603
 
        g_debug ("Updating input settings");
604
 
 
605
 
        stop_monitor_stream_for_source (dialog);
606
 
 
607
 
        if (dialog->priv->input_port_combo != NULL) {
608
 
                gtk_container_remove (GTK_CONTAINER (dialog->priv->input_settings_box),
609
 
                                      dialog->priv->input_port_combo);
610
 
                dialog->priv->input_port_combo = NULL;
611
 
        }
612
 
 
613
 
        stream = gvc_mixer_control_get_default_source (dialog->priv->mixer_control);
614
 
        if (stream == NULL) {
615
 
                g_debug ("Default source stream not found");
616
 
                return;
617
 
        }
618
 
 
619
 
        gvc_channel_bar_set_base_volume (GVC_CHANNEL_BAR (dialog->priv->input_bar),
620
 
                                         gvc_mixer_stream_get_base_volume (stream));
621
 
        gvc_channel_bar_set_is_amplified (GVC_CHANNEL_BAR (dialog->priv->input_bar),
622
 
                                          gvc_mixer_stream_get_can_decibel (stream));
623
 
 
624
 
        /* Update the adjustment in case the previous bar wasn't decibel
625
 
         * capable, and we clipped it */
626
 
        adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->input_bar)));
627
 
        gtk_adjustment_set_value (adj,
628
 
                                  gvc_mixer_stream_get_volume (stream));
629
 
 
630
 
        ports = gvc_mixer_stream_get_ports (stream);
631
 
        if (ports != NULL) {
632
 
                const GvcMixerStreamPort *port;
633
 
                port = gvc_mixer_stream_get_port (stream);
634
 
 
635
 
                dialog->priv->input_port_combo = gvc_combo_box_new (_("Co_nnector:"));
636
 
                gvc_combo_box_set_ports (GVC_COMBO_BOX (dialog->priv->input_port_combo),
637
 
                                         ports);
638
 
                gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->input_port_combo), port->port);
639
 
                g_object_set_data (G_OBJECT (dialog->priv->input_port_combo), "stream", stream);
640
 
                g_signal_connect (G_OBJECT (dialog->priv->input_port_combo), "changed",
641
 
                                  G_CALLBACK (port_selection_changed), dialog);
642
 
 
643
 
                if (dialog->priv->size_group != NULL) {
644
 
                        gvc_combo_box_set_size_group (GVC_COMBO_BOX (dialog->priv->input_port_combo),
645
 
                                                      dialog->priv->size_group, FALSE);
646
 
                }
647
 
                gtk_box_pack_start (GTK_BOX (dialog->priv->input_settings_box),
648
 
                                    dialog->priv->input_port_combo,
649
 
                                    TRUE, TRUE, 0);
650
 
                gtk_widget_show (dialog->priv->input_port_combo);
651
 
        }
652
 
 
653
 
        create_monitor_stream_for_source (dialog, stream);
654
 
}
655
 
 
656
 
static void
657
 
on_mixer_control_default_source_changed (GvcMixerControl *control,
658
 
                                         guint            id,
659
 
                                         GvcMixerDialog  *dialog)
660
 
{
661
 
        GvcMixerStream *stream;
662
 
        GtkAdjustment *adj;
663
 
 
664
 
        g_debug ("GvcMixerDialog: default source changed: %u", id);
665
 
 
666
 
        if (id == PA_INVALID_INDEX)
667
 
                stream = NULL;
668
 
        else
669
 
                stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, id);
670
 
 
671
 
        /* Disconnect the adj, otherwise it might change if is_amplified changes */
672
 
        adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (dialog->priv->input_bar)));
673
 
        g_signal_handlers_disconnect_by_func(adj, on_adjustment_value_changed, dialog);
674
 
 
675
 
        bar_set_stream (dialog, dialog->priv->input_bar, stream);
676
 
        update_input_settings (dialog);
677
 
 
678
 
        g_signal_connect (adj,
679
 
                          "value-changed",
680
 
                          G_CALLBACK (on_adjustment_value_changed),
681
 
                          dialog);
682
 
 
683
 
        update_default_input (dialog);
684
 
}
685
 
 
686
 
static void
687
 
gvc_mixer_dialog_set_mixer_control (GvcMixerDialog  *dialog,
688
 
                                    GvcMixerControl *control)
689
 
{
690
 
        g_return_if_fail (GVC_MIXER_DIALOG (dialog));
691
 
        g_return_if_fail (GVC_IS_MIXER_CONTROL (control));
692
 
 
693
 
        g_object_ref (control);
694
 
 
695
 
        if (dialog->priv->mixer_control != NULL) {
696
 
                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
697
 
                                                      G_CALLBACK (on_mixer_control_default_sink_changed),
698
 
                                                      dialog);
699
 
                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
700
 
                                                      G_CALLBACK (on_mixer_control_default_source_changed),
701
 
                                                      dialog);
702
 
                g_object_unref (dialog->priv->mixer_control);
703
 
        }
704
 
 
705
 
        dialog->priv->mixer_control = control;
706
 
 
707
 
        g_signal_connect (dialog->priv->mixer_control,
708
 
                          "default-sink-changed",
709
 
                          G_CALLBACK (on_mixer_control_default_sink_changed),
710
 
                          dialog);
711
 
        g_signal_connect (dialog->priv->mixer_control,
712
 
                          "default-source-changed",
713
 
                          G_CALLBACK (on_mixer_control_default_source_changed),
714
 
                          dialog);
715
 
 
716
 
        g_object_notify (G_OBJECT (dialog), "mixer-control");
717
 
}
718
 
 
719
 
static GvcMixerControl *
720
 
gvc_mixer_dialog_get_mixer_control (GvcMixerDialog *dialog)
721
 
{
722
 
        g_return_val_if_fail (GVC_IS_MIXER_DIALOG (dialog), NULL);
723
 
 
724
 
        return dialog->priv->mixer_control;
725
 
}
726
 
 
727
 
static void
728
 
gvc_mixer_dialog_set_property (GObject       *object,
729
 
                               guint          prop_id,
730
 
                               const GValue  *value,
731
 
                               GParamSpec    *pspec)
732
 
{
733
 
        GvcMixerDialog *self = GVC_MIXER_DIALOG (object);
734
 
 
735
 
        switch (prop_id) {
736
 
        case PROP_MIXER_CONTROL:
737
 
                gvc_mixer_dialog_set_mixer_control (self, g_value_get_object (value));
738
 
                break;
739
 
        default:
740
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
741
 
                break;
742
 
        }
743
 
}
744
 
 
745
 
static void
746
 
gvc_mixer_dialog_get_property (GObject     *object,
747
 
                               guint        prop_id,
748
 
                               GValue      *value,
749
 
                               GParamSpec  *pspec)
750
 
{
751
 
        GvcMixerDialog *self = GVC_MIXER_DIALOG (object);
752
 
 
753
 
        switch (prop_id) {
754
 
        case PROP_MIXER_CONTROL:
755
 
                g_value_set_object (value, gvc_mixer_dialog_get_mixer_control (self));
756
 
                break;
757
 
        default:
758
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
759
 
                break;
760
 
        }
761
 
}
762
 
 
763
 
static void
764
 
on_adjustment_value_changed (GtkAdjustment  *adjustment,
765
 
                             GvcMixerDialog *dialog)
766
 
{
767
 
        GvcMixerStream *stream;
768
 
 
769
 
        stream = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-stream");
770
 
        if (stream != NULL) {
771
 
                GObject *bar;
772
 
                gdouble volume, rounded;
773
 
                char *name;
774
 
 
775
 
                volume = gtk_adjustment_get_value (adjustment);
776
 
                rounded = round (volume);
777
 
 
778
 
                bar = g_object_get_data (G_OBJECT (adjustment), "gvc-mixer-dialog-bar");
779
 
                g_object_get (bar, "name", &name, NULL);
780
 
                g_debug ("Setting stream volume %lf (rounded: %lf) for bar '%s'", volume, rounded, name);
781
 
                g_free (name);
782
 
 
783
 
                /* FIXME would need to do that in the balance bar really... */
784
 
                /* Make sure we do not unmute muted streams, there's a button for that */
785
 
                if (volume == 0.0)
786
 
                        gvc_mixer_stream_set_is_muted (stream, TRUE);
787
 
                /* Only push the volume if it's actually changed */
788
 
                if (gvc_mixer_stream_set_volume(stream, (pa_volume_t) rounded) != FALSE)
789
 
                        gvc_mixer_stream_push_volume (stream);
790
 
        }
791
 
}
792
 
 
793
 
static void
794
 
on_bar_is_muted_notify (GObject        *object,
795
 
                        GParamSpec     *pspec,
796
 
                        GvcMixerDialog *dialog)
797
 
{
798
 
        gboolean        is_muted;
799
 
        GvcMixerStream *stream;
800
 
 
801
 
        is_muted = gvc_channel_bar_get_is_muted (GVC_CHANNEL_BAR (object));
802
 
 
803
 
        stream = g_object_get_data (object, "gvc-mixer-dialog-stream");
804
 
        if (stream != NULL) {
805
 
                gvc_mixer_stream_change_is_muted (stream, is_muted);
806
 
        } else {
807
 
                char *name;
808
 
                g_object_get (object, "name", &name, NULL);
809
 
                g_warning ("Unable to find stream for bar '%s'", name);
810
 
                g_free (name);
811
 
        }
812
 
}
813
 
 
814
 
static GtkWidget *
815
 
lookup_bar_for_stream (GvcMixerDialog *dialog,
816
 
                       GvcMixerStream *stream)
817
 
{
818
 
        GtkWidget *bar;
819
 
 
820
 
        bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)));
821
 
 
822
 
        return bar;
823
 
}
824
 
 
825
 
static GtkWidget *
826
 
lookup_combo_box_for_stream (GvcMixerDialog *dialog,
827
 
                             GvcMixerStream *stream)
828
 
{
829
 
        GvcMixerStream *combo_stream;
830
 
        guint id;
831
 
 
832
 
        id = gvc_mixer_stream_get_id (stream);
833
 
 
834
 
        if (dialog->priv->output_port_combo != NULL) {
835
 
                combo_stream = g_object_get_data (G_OBJECT (dialog->priv->output_port_combo),
836
 
                                                  "stream");
837
 
                if (combo_stream != NULL) {
838
 
                        if (id == gvc_mixer_stream_get_id (combo_stream))
839
 
                                return dialog->priv->output_port_combo;
840
 
                }
841
 
        }
842
 
 
843
 
        if (dialog->priv->input_port_combo != NULL) {
844
 
                combo_stream = g_object_get_data (G_OBJECT (dialog->priv->input_port_combo),
845
 
                                                  "stream");
846
 
                if (combo_stream != NULL) {
847
 
                        if (id == gvc_mixer_stream_get_id (combo_stream))
848
 
                                return dialog->priv->input_port_combo;
849
 
                }
850
 
        }
851
 
 
852
 
        return NULL;
853
 
}
854
 
 
855
 
static void
856
 
on_stream_description_notify (GvcMixerStream *stream,
857
 
                              GParamSpec     *pspec,
858
 
                              GvcMixerDialog *dialog)
859
 
{
860
 
        update_description (dialog, NAME_COLUMN,
861
 
                            gvc_mixer_stream_get_description (stream),
862
 
                            stream);
863
 
}
864
 
 
865
 
static void
866
 
on_stream_port_notify (GObject        *object,
867
 
                       GParamSpec     *pspec,
868
 
                       GvcMixerDialog *dialog)
869
 
{
870
 
        GvcComboBox *combo_box;
871
 
        char *port;
872
 
 
873
 
        combo_box = GVC_COMBO_BOX (lookup_combo_box_for_stream (dialog, GVC_MIXER_STREAM (object)));
874
 
        if (combo_box == NULL)
875
 
                return;
876
 
 
877
 
        g_signal_handlers_block_by_func (G_OBJECT (combo_box),
878
 
                                         port_selection_changed,
879
 
                                         dialog);
880
 
 
881
 
        g_object_get (object, "port", &port, NULL);
882
 
        gvc_combo_box_set_active (GVC_COMBO_BOX (combo_box), port);
883
 
 
884
 
        g_signal_handlers_unblock_by_func (G_OBJECT (combo_box),
885
 
                                         port_selection_changed,
886
 
                                         dialog);
887
 
}
888
 
 
889
 
static void
890
 
on_stream_volume_notify (GObject        *object,
891
 
                         GParamSpec     *pspec,
892
 
                         GvcMixerDialog *dialog)
893
 
{
894
 
        GvcMixerStream *stream;
895
 
        GtkWidget      *bar;
896
 
        GtkAdjustment  *adj;
897
 
 
898
 
        stream = GVC_MIXER_STREAM (object);
899
 
 
900
 
        bar = lookup_bar_for_stream (dialog, stream);
901
 
 
902
 
        if (bar == NULL) {
903
 
                g_warning ("Unable to find bar for stream %s in on_stream_volume_notify()",
904
 
                           gvc_mixer_stream_get_name (stream));
905
 
                return;
906
 
        }
907
 
 
908
 
        adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
909
 
 
910
 
        g_signal_handlers_block_by_func (adj,
911
 
                                         on_adjustment_value_changed,
912
 
                                         dialog);
913
 
 
914
 
        gtk_adjustment_set_value (adj,
915
 
                                  gvc_mixer_stream_get_volume (stream));
916
 
 
917
 
        g_signal_handlers_unblock_by_func (adj,
918
 
                                           on_adjustment_value_changed,
919
 
                                           dialog);
920
 
}
921
 
 
922
 
static void
923
 
on_stream_is_muted_notify (GObject        *object,
924
 
                           GParamSpec     *pspec,
925
 
                           GvcMixerDialog *dialog)
926
 
{
927
 
        GvcMixerStream *stream;
928
 
        GtkWidget      *bar;
929
 
        gboolean        is_muted;
930
 
 
931
 
        stream = GVC_MIXER_STREAM (object);
932
 
        bar = lookup_bar_for_stream (dialog, stream);
933
 
 
934
 
        if (bar == NULL) {
935
 
                g_warning ("Unable to find bar for stream %s in on_stream_is_muted_notify()",
936
 
                           gvc_mixer_stream_get_name (stream));
937
 
                return;
938
 
        }
939
 
 
940
 
        is_muted = gvc_mixer_stream_get_is_muted (stream);
941
 
        gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar),
942
 
                                      is_muted);
943
 
 
944
 
        if (stream == gvc_mixer_control_get_default_sink (dialog->priv->mixer_control)) {
945
 
                gtk_widget_set_sensitive (dialog->priv->applications_box,
946
 
                                          !is_muted);
947
 
        }
948
 
 
949
 
}
950
 
 
951
 
static void
952
 
save_bar_for_stream (GvcMixerDialog *dialog,
953
 
                     GvcMixerStream *stream,
954
 
                     GtkWidget      *bar)
955
 
{
956
 
        g_hash_table_insert (dialog->priv->bars,
957
 
                             GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)),
958
 
                             bar);
959
 
}
960
 
 
961
 
static GtkWidget *
962
 
create_bar (GvcMixerDialog *dialog,
963
 
            gboolean        add_to_size_group,
964
 
            gboolean        symmetric)
965
 
{
966
 
        GtkWidget *bar;
967
 
 
968
 
        bar = gvc_channel_bar_new ();
969
 
        gtk_widget_set_sensitive (bar, FALSE);
970
 
        if (add_to_size_group && dialog->priv->size_group != NULL) {
971
 
                gvc_channel_bar_set_size_group (GVC_CHANNEL_BAR (bar),
972
 
                                                dialog->priv->size_group,
973
 
                                                symmetric);
974
 
        }
975
 
        gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (bar),
976
 
                                         GTK_ORIENTATION_HORIZONTAL);
977
 
        gvc_channel_bar_set_show_mute (GVC_CHANNEL_BAR (bar),
978
 
                                       TRUE);
979
 
        g_signal_connect (bar,
980
 
                          "notify::is-muted",
981
 
                          G_CALLBACK (on_bar_is_muted_notify),
982
 
                          dialog);
983
 
        return bar;
984
 
}
985
 
 
986
 
static GtkWidget *
987
 
create_app_bar (GvcMixerDialog *dialog,
988
 
                const char     *name,
989
 
                const char     *icon_name)
990
 
{
991
 
        GtkWidget *bar;
992
 
 
993
 
        bar = create_bar (dialog, FALSE, FALSE);
994
 
        gvc_channel_bar_set_ellipsize (GVC_CHANNEL_BAR (bar), TRUE);
995
 
        gvc_channel_bar_set_icon_name (GVC_CHANNEL_BAR (bar), icon_name);
996
 
        if (name == NULL || strchr (name, '_') == NULL) {
997
 
                gvc_channel_bar_set_name (GVC_CHANNEL_BAR (bar), name);
998
 
        } else {
999
 
                char **tokens, *escaped;
1000
 
 
1001
 
                tokens = g_strsplit (name, "_", -1);
1002
 
                escaped = g_strjoinv ("__", tokens);
1003
 
                g_strfreev (tokens);
1004
 
                gvc_channel_bar_set_name (GVC_CHANNEL_BAR (bar), escaped);
1005
 
                g_free (escaped);
1006
 
        }
1007
 
 
1008
 
        return bar;
1009
 
}
1010
 
 
1011
 
static void
1012
 
bar_set_stream (GvcMixerDialog *dialog,
1013
 
                GtkWidget      *bar,
1014
 
                GvcMixerStream *stream)
1015
 
{
1016
 
        GtkAdjustment  *adj;
1017
 
        GvcMixerStream *old_stream;
1018
 
 
1019
 
        g_assert (bar != NULL);
1020
 
 
1021
 
        old_stream = g_object_get_data (G_OBJECT (bar), "gvc-mixer-dialog-stream");
1022
 
        if (old_stream != NULL) {
1023
 
                char *name;
1024
 
 
1025
 
                g_object_get (bar, "name", &name, NULL);
1026
 
                g_debug ("Disconnecting old stream '%s' from bar '%s'",
1027
 
                         gvc_mixer_stream_get_name (old_stream), name);
1028
 
                g_free (name);
1029
 
 
1030
 
                g_signal_handlers_disconnect_by_func (old_stream, on_stream_is_muted_notify, dialog);
1031
 
                g_signal_handlers_disconnect_by_func (old_stream, on_stream_volume_notify, dialog);
1032
 
                g_signal_handlers_disconnect_by_func (old_stream, on_stream_port_notify, dialog);
1033
 
                g_hash_table_remove (dialog->priv->bars, GUINT_TO_POINTER (gvc_mixer_stream_get_id (old_stream)));
1034
 
        }
1035
 
 
1036
 
        gtk_widget_set_sensitive (bar, (stream != NULL));
1037
 
 
1038
 
        adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
1039
 
 
1040
 
        g_signal_handlers_disconnect_by_func (adj, on_adjustment_value_changed, dialog);
1041
 
 
1042
 
        g_object_set_data (G_OBJECT (bar), "gvc-mixer-dialog-stream", stream);
1043
 
        g_object_set_data (G_OBJECT (adj), "gvc-mixer-dialog-stream", stream);
1044
 
        g_object_set_data (G_OBJECT (adj), "gvc-mixer-dialog-bar", bar);
1045
 
 
1046
 
        if (stream != NULL) {
1047
 
                gboolean is_muted;
1048
 
 
1049
 
                is_muted = gvc_mixer_stream_get_is_muted (stream);
1050
 
                gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (bar), is_muted);
1051
 
 
1052
 
                save_bar_for_stream (dialog, stream, bar);
1053
 
 
1054
 
                gtk_adjustment_set_value (adj,
1055
 
                                          gvc_mixer_stream_get_volume (stream));
1056
 
 
1057
 
                g_signal_connect (stream,
1058
 
                                  "notify::is-muted",
1059
 
                                  G_CALLBACK (on_stream_is_muted_notify),
1060
 
                                  dialog);
1061
 
                g_signal_connect (stream,
1062
 
                                  "notify::volume",
1063
 
                                  G_CALLBACK (on_stream_volume_notify),
1064
 
                                  dialog);
1065
 
                g_signal_connect (stream,
1066
 
                                  "notify::port",
1067
 
                                  G_CALLBACK (on_stream_port_notify),
1068
 
                                  dialog);
1069
 
                g_signal_connect (adj,
1070
 
                                  "value-changed",
1071
 
                                  G_CALLBACK (on_adjustment_value_changed),
1072
 
                                  dialog);
1073
 
        }
1074
 
}
1075
 
 
1076
 
static void
1077
 
add_stream (GvcMixerDialog *dialog,
1078
 
            GvcMixerStream *stream)
1079
 
{
1080
 
        GtkWidget     *bar;
1081
 
        gboolean       is_muted;
1082
 
        gboolean       is_default;
1083
 
        GtkAdjustment *adj;
1084
 
        const char    *id;
1085
 
 
1086
 
        g_assert (stream != NULL);
1087
 
 
1088
 
        if (gvc_mixer_stream_is_event_stream (stream) != FALSE)
1089
 
                return;
1090
 
 
1091
 
        bar = NULL;
1092
 
        is_default = FALSE;
1093
 
        id = gvc_mixer_stream_get_application_id (stream);
1094
 
 
1095
 
        if (stream == gvc_mixer_control_get_default_sink (dialog->priv->mixer_control)) {
1096
 
                bar = dialog->priv->output_bar;
1097
 
                is_muted = gvc_mixer_stream_get_is_muted (stream);
1098
 
                is_default = TRUE;
1099
 
                gtk_widget_set_sensitive (dialog->priv->applications_box,
1100
 
                                          !is_muted);
1101
 
                adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
1102
 
                g_signal_handlers_disconnect_by_func(adj, on_adjustment_value_changed, dialog);
1103
 
                update_output_settings (dialog);
1104
 
        } else if (stream == gvc_mixer_control_get_default_source (dialog->priv->mixer_control)) {
1105
 
                bar = dialog->priv->input_bar;
1106
 
                adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (bar)));
1107
 
                g_signal_handlers_disconnect_by_func(adj, on_adjustment_value_changed, dialog);
1108
 
                update_input_settings (dialog);
1109
 
                is_default = TRUE;
1110
 
        } else if (stream == gvc_mixer_control_get_event_sink_input (dialog->priv->mixer_control)) {
1111
 
                bar = dialog->priv->effects_bar;
1112
 
                g_debug ("Adding effects stream");
1113
 
        } else if (! GVC_IS_MIXER_SOURCE (stream)
1114
 
                   && !GVC_IS_MIXER_SINK (stream)
1115
 
                   && !gvc_mixer_stream_is_virtual (stream)
1116
 
                   && g_strcmp0 (id, "org.gnome.VolumeControl") != 0
1117
 
                   && g_strcmp0 (id, "org.PulseAudio.pavucontrol") != 0) {
1118
 
                const char *name;
1119
 
 
1120
 
                name = gvc_mixer_stream_get_name (stream);
1121
 
                bar = create_app_bar (dialog, name,
1122
 
                                      gvc_mixer_stream_get_icon_name (stream));
1123
 
 
1124
 
                gtk_box_pack_start (GTK_BOX (dialog->priv->applications_box), bar, FALSE, FALSE, 12);
1125
 
                dialog->priv->num_apps++;
1126
 
                gtk_widget_hide (dialog->priv->no_apps_label);
1127
 
        }
1128
 
 
1129
 
        if (GVC_IS_MIXER_SOURCE (stream)) {
1130
 
                GtkTreeModel *model;
1131
 
                GtkTreeIter   iter;
1132
 
                GIcon        *icon;
1133
 
 
1134
 
                model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
1135
 
                gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1136
 
 
1137
 
                icon = gvc_mixer_stream_get_gicon (stream);
1138
 
                gtk_list_store_set (GTK_LIST_STORE (model),
1139
 
                                    &iter,
1140
 
                                    NAME_COLUMN, gvc_mixer_stream_get_description (stream),
1141
 
                                    DEVICE_COLUMN, "",
1142
 
                                    ACTIVE_COLUMN, is_default,
1143
 
                                    ICON_COLUMN, icon,
1144
 
                                    ID_COLUMN, gvc_mixer_stream_get_id (stream),
1145
 
                                    -1);
1146
 
                if (icon != NULL)
1147
 
                        g_object_unref (icon);
1148
 
 
1149
 
                if (is_default) {
1150
 
                        GtkTreeSelection *selection;
1151
 
 
1152
 
                        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->input_treeview));
1153
 
                        gtk_tree_selection_select_iter (selection, &iter);
1154
 
                }
1155
 
 
1156
 
                g_signal_connect (stream,
1157
 
                                  "notify::description",
1158
 
                                  G_CALLBACK (on_stream_description_notify),
1159
 
                                  dialog);
1160
 
        } else if (GVC_IS_MIXER_SINK (stream)) {
1161
 
                GtkTreeModel        *model;
1162
 
                GtkTreeIter          iter;
1163
 
                const GvcChannelMap *map;
1164
 
                GIcon               *icon;
1165
 
 
1166
 
                model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
1167
 
                gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1168
 
 
1169
 
                map = gvc_mixer_stream_get_channel_map (stream);
1170
 
                icon = gvc_mixer_stream_get_gicon (stream);
1171
 
                gtk_list_store_set (GTK_LIST_STORE (model),
1172
 
                                    &iter,
1173
 
                                    NAME_COLUMN, gvc_mixer_stream_get_description (stream),
1174
 
                                    DEVICE_COLUMN, "",
1175
 
                                    ACTIVE_COLUMN, is_default,
1176
 
                                    ICON_COLUMN, icon,
1177
 
                                    ID_COLUMN, gvc_mixer_stream_get_id (stream),
1178
 
                                    SPEAKERS_COLUMN, gvc_channel_map_get_mapping (map),
1179
 
                                    -1);
1180
 
                if (icon != NULL)
1181
 
                        g_object_unref (icon);
1182
 
 
1183
 
                if (is_default) {
1184
 
                        GtkTreeSelection *selection;
1185
 
 
1186
 
                        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->output_treeview));
1187
 
                        gtk_tree_selection_select_iter (selection, &iter);
1188
 
                }
1189
 
 
1190
 
                g_signal_connect (stream,
1191
 
                                  "notify::description",
1192
 
                                  G_CALLBACK (on_stream_description_notify),
1193
 
                                  dialog);
1194
 
        }
1195
 
 
1196
 
        if (bar != NULL) {
1197
 
                bar_set_stream (dialog, bar, stream);
1198
 
                gtk_widget_show (bar);
1199
 
        }
1200
 
}
1201
 
 
1202
 
static void
1203
 
on_control_stream_added (GvcMixerControl *control,
1204
 
                         guint            id,
1205
 
                         GvcMixerDialog  *dialog)
1206
 
{
1207
 
        GvcMixerStream *stream;
1208
 
        GtkWidget      *bar;
1209
 
 
1210
 
        bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (id));
1211
 
        if (bar != NULL) {
1212
 
                g_debug ("GvcMixerDialog: Stream %u already added", id);
1213
 
                return;
1214
 
        }
1215
 
 
1216
 
        stream = gvc_mixer_control_lookup_stream_id (control, id);
1217
 
        if (stream != NULL) {
1218
 
                add_stream (dialog, stream);
1219
 
        }
1220
 
}
1221
 
 
1222
 
static gboolean
1223
 
find_item_by_id (GtkTreeModel *model,
1224
 
                   guint         id,
1225
 
                   guint         column,
1226
 
                   GtkTreeIter  *iter)
1227
 
{
1228
 
        gboolean found_item;
1229
 
 
1230
 
        found_item = FALSE;
1231
 
 
1232
 
        if (!gtk_tree_model_get_iter_first (model, iter)) {
1233
 
                return FALSE;
1234
 
        }
1235
 
 
1236
 
        do {
1237
 
                guint t_id;
1238
 
 
1239
 
                gtk_tree_model_get (model, iter,
1240
 
                                    column, &t_id, -1);
1241
 
 
1242
 
                if (id == t_id) {
1243
 
                        found_item = TRUE;
1244
 
                }
1245
 
        } while (!found_item && gtk_tree_model_iter_next (model, iter));
1246
 
 
1247
 
        return found_item;
1248
 
}
1249
 
 
1250
 
static void
1251
 
remove_stream (GvcMixerDialog  *dialog,
1252
 
               guint            id)
1253
 
{
1254
 
        GtkWidget    *bar;
1255
 
        gboolean      found;
1256
 
        GtkTreeIter   iter;
1257
 
        GtkTreeModel *model;
1258
 
 
1259
 
        /* remove bars for applications and reset fixed bars */
1260
 
        bar = g_hash_table_lookup (dialog->priv->bars, GUINT_TO_POINTER (id));
1261
 
        if (bar == dialog->priv->output_bar
1262
 
            || bar == dialog->priv->input_bar
1263
 
            || bar == dialog->priv->effects_bar) {
1264
 
                char *name;
1265
 
                g_object_get (bar, "name", &name, NULL);
1266
 
                g_debug ("Removing stream for bar '%s'", name);
1267
 
                g_free (name);
1268
 
                bar_set_stream (dialog, bar, NULL);
1269
 
        } else if (bar != NULL) {
1270
 
                g_hash_table_remove (dialog->priv->bars, GUINT_TO_POINTER (id));
1271
 
                gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (bar)),
1272
 
                                      bar);
1273
 
                dialog->priv->num_apps--;
1274
 
                if (dialog->priv->num_apps == 0) {
1275
 
                        gtk_widget_show (dialog->priv->no_apps_label);
1276
 
                }
1277
 
        }
1278
 
 
1279
 
        /* remove from any models */
1280
 
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->output_treeview));
1281
 
        found = find_item_by_id (GTK_TREE_MODEL (model), id, ID_COLUMN, &iter);
1282
 
        if (found) {
1283
 
                gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
1284
 
        }
1285
 
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->input_treeview));
1286
 
        found = find_item_by_id (GTK_TREE_MODEL (model), id, ID_COLUMN, &iter);
1287
 
        if (found) {
1288
 
                gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
1289
 
        }
1290
 
}
1291
 
 
1292
 
static void
1293
 
on_control_stream_removed (GvcMixerControl *control,
1294
 
                           guint            id,
1295
 
                           GvcMixerDialog  *dialog)
1296
 
{
1297
 
        remove_stream (dialog, id);
1298
 
}
1299
 
 
1300
 
static void
1301
 
add_card (GvcMixerDialog *dialog,
1302
 
          GvcMixerCard   *card)
1303
 
{
1304
 
        GtkTreeModel        *model;
1305
 
        GtkTreeIter          iter;
1306
 
        GtkTreeSelection    *selection;
1307
 
        GvcMixerCardProfile *profile;
1308
 
        GIcon               *icon;
1309
 
        guint                index;
1310
 
 
1311
 
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->hw_treeview));
1312
 
        index = gvc_mixer_card_get_index (card);
1313
 
        if (find_item_by_id (GTK_TREE_MODEL (model), index, HW_ID_COLUMN, &iter) == FALSE)
1314
 
                gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1315
 
        profile = gvc_mixer_card_get_profile (card);
1316
 
        g_assert (profile != NULL);
1317
 
        icon = g_themed_icon_new_with_default_fallbacks (gvc_mixer_card_get_icon_name (card));
1318
 
        //FIXME we need the status (default for a profile?) here
1319
 
        gtk_list_store_set (GTK_LIST_STORE (model),
1320
 
                            &iter,
1321
 
                            HW_NAME_COLUMN, gvc_mixer_card_get_name (card),
1322
 
                            HW_ID_COLUMN, index,
1323
 
                            HW_ICON_COLUMN, icon,
1324
 
                            HW_PROFILE_COLUMN, profile->profile,
1325
 
                            HW_PROFILE_HUMAN_COLUMN, profile->human_profile,
1326
 
                            HW_STATUS_COLUMN, profile->status,
1327
 
                            HW_SENSITIVE_COLUMN, g_strcmp0 (profile->profile, "off") != 0,
1328
 
                            -1);
1329
 
        if (icon != NULL)
1330
 
                g_object_unref (icon);
1331
 
 
1332
 
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->hw_treeview));
1333
 
        if (gtk_tree_selection_get_selected (selection, NULL, NULL) == FALSE) {
1334
 
                gtk_tree_selection_select_iter (selection, &iter);
1335
 
        } else if (dialog->priv->hw_profile_combo != NULL) {
1336
 
                GvcMixerCard *selected;
1337
 
 
1338
 
                /* Set the current profile if it changed for the selected card */
1339
 
                selected = g_object_get_data (G_OBJECT (dialog->priv->hw_profile_combo), "card");
1340
 
                if (gvc_mixer_card_get_index (selected) == gvc_mixer_card_get_index (card)) {
1341
 
                        gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->hw_profile_combo),
1342
 
                                                  profile->profile);
1343
 
                        g_object_set (G_OBJECT (dialog->priv->hw_profile_combo),
1344
 
                                      "show-button", profile->n_sinks == 1,
1345
 
                                      NULL);
1346
 
                }
1347
 
        }
1348
 
}
1349
 
 
1350
 
static void
1351
 
on_control_card_added (GvcMixerControl *control,
1352
 
                       guint            id,
1353
 
                       GvcMixerDialog  *dialog)
1354
 
{
1355
 
        GvcMixerCard *card;
1356
 
 
1357
 
        card = gvc_mixer_control_lookup_card_id (control, id);
1358
 
        if (card != NULL) {
1359
 
                add_card (dialog, card);
1360
 
        }
1361
 
}
1362
 
 
1363
 
static void
1364
 
remove_card (GvcMixerDialog  *dialog,
1365
 
             guint            id)
1366
 
{
1367
 
        gboolean      found;
1368
 
        GtkTreeIter   iter;
1369
 
        GtkTreeModel *model;
1370
 
 
1371
 
        /* remove from any models */
1372
 
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->hw_treeview));
1373
 
        found = find_item_by_id (GTK_TREE_MODEL (model), id, HW_ID_COLUMN, &iter);
1374
 
        if (found) {
1375
 
                gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
1376
 
        }
1377
 
}
1378
 
static void
1379
 
on_control_card_removed (GvcMixerControl *control,
1380
 
                         guint            id,
1381
 
                         GvcMixerDialog  *dialog)
1382
 
{
1383
 
        remove_card (dialog, id);
1384
 
}
1385
 
 
1386
 
static void
1387
 
_gtk_label_make_bold (GtkLabel *label)
1388
 
{
1389
 
        PangoFontDescription *font_desc;
1390
 
 
1391
 
        font_desc = pango_font_description_new ();
1392
 
 
1393
 
        pango_font_description_set_weight (font_desc,
1394
 
                                           PANGO_WEIGHT_BOLD);
1395
 
 
1396
 
        /* This will only affect the weight of the font, the rest is
1397
 
         * from the current state of the widget, which comes from the
1398
 
         * theme or user prefs, since the font desc only has the
1399
 
         * weight flag turned on.
1400
 
         */
1401
 
        gtk_widget_modify_font (GTK_WIDGET (label), font_desc);
1402
 
 
1403
 
        pango_font_description_free (font_desc);
1404
 
}
1405
 
 
1406
 
static void
1407
 
on_input_selection_changed (GtkTreeSelection *selection,
1408
 
                            GvcMixerDialog   *dialog)
1409
 
{
1410
 
        GtkTreeModel *model;
1411
 
        GtkTreeIter   iter;
1412
 
        gboolean      toggled;
1413
 
        guint         id;
1414
 
 
1415
 
        if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) {
1416
 
                g_debug ("Could not get default input from selection");
1417
 
                return;
1418
 
        }
1419
 
 
1420
 
        gtk_tree_model_get (model, &iter,
1421
 
                            ID_COLUMN, &id,
1422
 
                            ACTIVE_COLUMN, &toggled,
1423
 
                            -1);
1424
 
 
1425
 
        toggled ^= 1;
1426
 
        if (toggled) {
1427
 
                GvcMixerStream *stream;
1428
 
 
1429
 
                g_debug ("Default input selected: %u", id);
1430
 
                stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, id);
1431
 
                if (stream == NULL) {
1432
 
                        g_warning ("Unable to find stream for id: %u", id);
1433
 
                        return;
1434
 
                }
1435
 
 
1436
 
                gvc_mixer_control_set_default_source (dialog->priv->mixer_control, stream);
1437
 
        }
1438
 
}
1439
 
 
1440
 
static void
1441
 
on_output_selection_changed (GtkTreeSelection *selection,
1442
 
                             GvcMixerDialog   *dialog)
1443
 
{
1444
 
        GtkTreeModel *model;
1445
 
        GtkTreeIter   iter;
1446
 
        gboolean      toggled;
1447
 
        guint         id;
1448
 
 
1449
 
        if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) {
1450
 
                g_debug ("Could not get default output from selection");
1451
 
                return;
1452
 
        }
1453
 
 
1454
 
        gtk_tree_model_get (model, &iter,
1455
 
                            ID_COLUMN, &id,
1456
 
                            ACTIVE_COLUMN, &toggled,
1457
 
                            -1);
1458
 
 
1459
 
        toggled ^= 1;
1460
 
        if (toggled) {
1461
 
                GvcMixerStream *stream;
1462
 
 
1463
 
                g_debug ("Default output selected: %u", id);
1464
 
                stream = gvc_mixer_control_lookup_stream_id (dialog->priv->mixer_control, id);
1465
 
                if (stream == NULL) {
1466
 
                        g_warning ("Unable to find stream for id: %u", id);
1467
 
                        return;
1468
 
                }
1469
 
 
1470
 
                gvc_mixer_control_set_default_sink (dialog->priv->mixer_control, stream);
1471
 
        }
1472
 
}
1473
 
 
1474
 
static void
1475
 
name_to_text (GtkTreeViewColumn *column,
1476
 
              GtkCellRenderer *cell,
1477
 
              GtkTreeModel *model,
1478
 
              GtkTreeIter *iter,
1479
 
              gpointer user_data)
1480
 
{
1481
 
        char *name, *mapping;
1482
 
 
1483
 
        gtk_tree_model_get(model, iter,
1484
 
                           NAME_COLUMN, &name,
1485
 
                           SPEAKERS_COLUMN, &mapping,
1486
 
                           -1);
1487
 
 
1488
 
        if (mapping == NULL) {
1489
 
                g_object_set (cell, "text", name, NULL);
1490
 
        } else {
1491
 
                char *str;
1492
 
 
1493
 
                str = g_strdup_printf ("%s\n<i>%s</i>",
1494
 
                                       name, mapping);
1495
 
                g_object_set (cell, "markup", str, NULL);
1496
 
                g_free (str);
1497
 
        }
1498
 
 
1499
 
        g_free (name);
1500
 
        g_free (mapping);
1501
 
}
1502
 
 
1503
 
static GtkWidget *
1504
 
create_stream_treeview (GvcMixerDialog *dialog,
1505
 
                        GCallback       on_selection_changed)
1506
 
{
1507
 
        GtkWidget         *treeview;
1508
 
        GtkListStore      *store;
1509
 
        GtkCellRenderer   *renderer;
1510
 
        GtkTreeViewColumn *column;
1511
 
        GtkTreeSelection  *selection;
1512
 
 
1513
 
        treeview = gtk_tree_view_new ();
1514
 
        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
1515
 
 
1516
 
        store = gtk_list_store_new (NUM_COLUMNS,
1517
 
                                    G_TYPE_STRING,
1518
 
                                    G_TYPE_STRING,
1519
 
                                    G_TYPE_BOOLEAN,
1520
 
                                    G_TYPE_UINT,
1521
 
                                    G_TYPE_STRING,
1522
 
                                    G_TYPE_ICON);
1523
 
        gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
1524
 
                                 GTK_TREE_MODEL (store));
1525
 
 
1526
 
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
1527
 
        gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1528
 
 
1529
 
        column = gtk_tree_view_column_new ();
1530
 
        gtk_tree_view_column_set_title (column, _("Name"));
1531
 
        renderer = gtk_cell_renderer_pixbuf_new ();
1532
 
        gtk_tree_view_column_pack_start (column, renderer, FALSE);
1533
 
        g_object_set (G_OBJECT (renderer), "stock-size", GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
1534
 
        gtk_tree_view_column_set_attributes (column, renderer,
1535
 
                                             "gicon", ICON_COLUMN,
1536
 
                                             NULL);
1537
 
 
1538
 
        renderer = gtk_cell_renderer_text_new ();
1539
 
        gtk_tree_view_column_pack_start (column, renderer, TRUE);
1540
 
        gtk_tree_view_column_set_cell_data_func (column, renderer,
1541
 
                                                 name_to_text, NULL, NULL);
1542
 
        gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1543
 
 
1544
 
        g_signal_connect (G_OBJECT (selection), "changed",
1545
 
                          on_selection_changed, dialog);
1546
 
#if 0
1547
 
        renderer = gtk_cell_renderer_text_new ();
1548
 
        column = gtk_tree_view_column_new_with_attributes (_("Device"),
1549
 
                                                           renderer,
1550
 
                                                           "text", DEVICE_COLUMN,
1551
 
                                                           NULL);
1552
 
        gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1553
 
#endif
1554
 
        return treeview;
1555
 
}
1556
 
 
1557
 
static void
1558
 
on_profile_changed (GvcComboBox *widget,
1559
 
                    const char  *profile,
1560
 
                    gpointer     user_data)
1561
 
{
1562
 
        GvcMixerCard        *card;
1563
 
 
1564
 
        card = g_object_get_data (G_OBJECT (widget), "card");
1565
 
        if (card == NULL) {
1566
 
                g_warning ("Could not find card for combobox");
1567
 
                return;
1568
 
        }
1569
 
 
1570
 
        g_debug ("Profile changed to %s for card %s", profile,
1571
 
                 gvc_mixer_card_get_name (card));
1572
 
 
1573
 
        gvc_mixer_card_change_profile (card, profile);
1574
 
}
1575
 
 
1576
 
static void
1577
 
on_test_speakers_clicked (GvcComboBox *widget,
1578
 
                          gpointer     user_data)
1579
 
{
1580
 
        GvcMixerDialog      *dialog = GVC_MIXER_DIALOG (user_data);
1581
 
        GvcMixerCard        *card;
1582
 
        GvcMixerCardProfile *profile;
1583
 
        GtkWidget           *d, *speaker_test, *container;
1584
 
        char                *title;
1585
 
 
1586
 
        card = g_object_get_data (G_OBJECT (widget), "card");
1587
 
        if (card == NULL) {
1588
 
                g_warning ("Could not find card for combobox");
1589
 
                return;
1590
 
        }
1591
 
        profile = gvc_mixer_card_get_profile (card);
1592
 
 
1593
 
        g_debug ("XXX Start speaker testing for profile '%s', card %s XXX",
1594
 
                 profile->profile, gvc_mixer_card_get_name (card));
1595
 
 
1596
 
        title = g_strdup_printf (_("Speaker Testing for %s"), gvc_mixer_card_get_name (card));
1597
 
        d = gtk_dialog_new_with_buttons (title,
1598
 
                                         GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget))),
1599
 
                                         GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1600
 
                                         GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
1601
 
                                         NULL);
1602
 
        /* FIXME: this should not be necessary */
1603
 
        gtk_window_set_has_resize_grip (GTK_WINDOW (d), FALSE);
1604
 
 
1605
 
        g_free (title);
1606
 
        speaker_test = gvc_speaker_test_new (dialog->priv->mixer_control,
1607
 
                                             card);
1608
 
        gtk_widget_show (speaker_test);
1609
 
        container = gtk_dialog_get_content_area (GTK_DIALOG (d));
1610
 
        gtk_container_add (GTK_CONTAINER (container), speaker_test);
1611
 
 
1612
 
        gtk_dialog_run (GTK_DIALOG (d));
1613
 
        gtk_widget_destroy (d);
1614
 
}
1615
 
 
1616
 
static void
1617
 
on_card_selection_changed (GtkTreeSelection *selection,
1618
 
                           gpointer          user_data)
1619
 
{
1620
 
        GvcMixerDialog      *dialog = GVC_MIXER_DIALOG (user_data);
1621
 
        GtkTreeModel        *model;
1622
 
        GtkTreeIter          iter;
1623
 
        const GList         *profiles;
1624
 
        guint                id;
1625
 
        GvcMixerCard        *card;
1626
 
        GvcMixerCardProfile *current_profile;
1627
 
 
1628
 
        g_debug ("Card selection changed");
1629
 
 
1630
 
        if (dialog->priv->hw_profile_combo != NULL) {
1631
 
                gtk_container_remove (GTK_CONTAINER (dialog->priv->hw_settings_box),
1632
 
                                      dialog->priv->hw_profile_combo);
1633
 
                dialog->priv->hw_profile_combo = NULL;
1634
 
        }
1635
 
 
1636
 
        if (gtk_tree_selection_get_selected (selection,
1637
 
                                             NULL,
1638
 
                                             &iter) == FALSE) {
1639
 
                return;
1640
 
        }
1641
 
 
1642
 
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->priv->hw_treeview));
1643
 
        gtk_tree_model_get (model, &iter,
1644
 
                            HW_ID_COLUMN, &id,
1645
 
                            -1);
1646
 
        card = gvc_mixer_control_lookup_card_id (dialog->priv->mixer_control, id);
1647
 
        if (card == NULL) {
1648
 
                g_warning ("Unable to find card for id: %u", id);
1649
 
                return;
1650
 
        }
1651
 
 
1652
 
        current_profile = gvc_mixer_card_get_profile (card);
1653
 
        profiles = gvc_mixer_card_get_profiles (card);
1654
 
        dialog->priv->hw_profile_combo = gvc_combo_box_new (_("_Profile:"));
1655
 
        g_object_set (G_OBJECT (dialog->priv->hw_profile_combo), "button-label", _("_Test Speakers"), NULL);
1656
 
        gvc_combo_box_set_profiles (GVC_COMBO_BOX (dialog->priv->hw_profile_combo), profiles);
1657
 
        gvc_combo_box_set_active (GVC_COMBO_BOX (dialog->priv->hw_profile_combo), current_profile->profile);
1658
 
 
1659
 
        gtk_box_pack_start (GTK_BOX (dialog->priv->hw_settings_box),
1660
 
                            dialog->priv->hw_profile_combo,
1661
 
                            TRUE, TRUE, 6);
1662
 
        g_object_set (G_OBJECT (dialog->priv->hw_profile_combo),
1663
 
                      "show-button", current_profile->n_sinks == 1,
1664
 
                      NULL);
1665
 
        gtk_widget_show (dialog->priv->hw_profile_combo);
1666
 
 
1667
 
        g_object_set_data (G_OBJECT (dialog->priv->hw_profile_combo), "card", card);
1668
 
        g_signal_connect (G_OBJECT (dialog->priv->hw_profile_combo), "changed",
1669
 
                          G_CALLBACK (on_profile_changed), dialog);
1670
 
        g_signal_connect (G_OBJECT (dialog->priv->hw_profile_combo), "button-clicked",
1671
 
                          G_CALLBACK (on_test_speakers_clicked), dialog);
1672
 
}
1673
 
 
1674
 
static void
1675
 
card_to_text (GtkTreeViewColumn *column,
1676
 
              GtkCellRenderer *cell,
1677
 
              GtkTreeModel *model,
1678
 
              GtkTreeIter *iter,
1679
 
              gpointer user_data)
1680
 
{
1681
 
        char *name, *status, *profile, *str;
1682
 
        gboolean sensitive;
1683
 
 
1684
 
        gtk_tree_model_get(model, iter,
1685
 
                           HW_NAME_COLUMN, &name,
1686
 
                           HW_STATUS_COLUMN, &status,
1687
 
                           HW_PROFILE_HUMAN_COLUMN, &profile,
1688
 
                           HW_SENSITIVE_COLUMN, &sensitive,
1689
 
                           -1);
1690
 
 
1691
 
        str = g_strdup_printf ("%s\n<i>%s</i>\n<i>%s</i>",
1692
 
                               name, status, profile);
1693
 
        g_object_set (cell,
1694
 
                      "markup", str,
1695
 
                      "sensitive", sensitive,
1696
 
                      NULL);
1697
 
        g_free (str);
1698
 
 
1699
 
        g_free (name);
1700
 
        g_free (status);
1701
 
        g_free (profile);
1702
 
}
1703
 
 
1704
 
static GtkWidget *
1705
 
create_cards_treeview (GvcMixerDialog *dialog,
1706
 
                       GCallback       on_changed)
1707
 
{
1708
 
        GtkWidget         *treeview;
1709
 
        GtkListStore      *store;
1710
 
        GtkCellRenderer   *renderer;
1711
 
        GtkTreeViewColumn *column;
1712
 
        GtkTreeSelection  *selection;
1713
 
 
1714
 
        treeview = gtk_tree_view_new ();
1715
 
        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
1716
 
 
1717
 
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
1718
 
        g_signal_connect (G_OBJECT (selection), "changed",
1719
 
                          on_changed, dialog);
1720
 
 
1721
 
        store = gtk_list_store_new (HW_NUM_COLUMNS,
1722
 
                                    G_TYPE_UINT,
1723
 
                                    G_TYPE_ICON,
1724
 
                                    G_TYPE_STRING,
1725
 
                                    G_TYPE_STRING,
1726
 
                                    G_TYPE_STRING,
1727
 
                                    G_TYPE_STRING,
1728
 
                                    G_TYPE_BOOLEAN);
1729
 
        gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
1730
 
                                 GTK_TREE_MODEL (store));
1731
 
 
1732
 
        renderer = gtk_cell_renderer_pixbuf_new ();
1733
 
        g_object_set (G_OBJECT (renderer), "stock-size", GTK_ICON_SIZE_DIALOG, NULL);
1734
 
        column = gtk_tree_view_column_new_with_attributes (NULL,
1735
 
                                                           renderer,
1736
 
                                                           "gicon", HW_ICON_COLUMN,
1737
 
                                                           "sensitive", HW_SENSITIVE_COLUMN,
1738
 
                                                           NULL);
1739
 
        gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1740
 
 
1741
 
        gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (treeview), -1,
1742
 
                                                    _("Name"), gtk_cell_renderer_text_new (),
1743
 
                                                    card_to_text, NULL, NULL);
1744
 
 
1745
 
        return treeview;
1746
 
}
1747
 
 
1748
 
static GObject *
1749
 
gvc_mixer_dialog_constructor (GType                  type,
1750
 
                              guint                  n_construct_properties,
1751
 
                              GObjectConstructParam *construct_params)
1752
 
{
1753
 
        GObject          *object;
1754
 
        GvcMixerDialog   *self;
1755
 
        GtkWidget        *main_vbox;
1756
 
        GtkWidget        *label;
1757
 
        GtkWidget        *alignment;
1758
 
        GtkWidget        *box;
1759
 
        GtkWidget        *sbox;
1760
 
        GtkWidget        *ebox;
1761
 
        GSList           *streams;
1762
 
        GSList           *cards;
1763
 
        GSList           *l;
1764
 
        GvcMixerStream   *stream;
1765
 
        GvcMixerCard     *card;
1766
 
        GtkTreeSelection *selection;
1767
 
 
1768
 
        object = G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->constructor (type, n_construct_properties, construct_params);
1769
 
 
1770
 
        self = GVC_MIXER_DIALOG (object);
1771
 
 
1772
 
        main_vbox = GTK_WIDGET (self);
1773
 
        gtk_box_set_spacing (GTK_BOX (main_vbox), 2);
1774
 
 
1775
 
        gtk_container_set_border_width (GTK_CONTAINER (self), 6);
1776
 
 
1777
 
        self->priv->output_stream_box = gtk_hbox_new (FALSE, 12);
1778
 
        alignment = gtk_alignment_new (0, 0, 1, 1);
1779
 
        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 12, 0, 0, 0);
1780
 
        gtk_container_add (GTK_CONTAINER (alignment), self->priv->output_stream_box);
1781
 
        gtk_box_pack_start (GTK_BOX (main_vbox),
1782
 
                            alignment,
1783
 
                            FALSE, FALSE, 0);
1784
 
        self->priv->output_bar = create_bar (self, TRUE, TRUE);
1785
 
        gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->output_bar),
1786
 
                                  _("_Output volume:"));
1787
 
        gtk_widget_set_sensitive (self->priv->output_bar, FALSE);
1788
 
        gtk_box_pack_start (GTK_BOX (self->priv->output_stream_box),
1789
 
                            self->priv->output_bar, TRUE, TRUE, 12);
1790
 
 
1791
 
        self->priv->notebook = gtk_notebook_new ();
1792
 
        gtk_box_pack_start (GTK_BOX (main_vbox),
1793
 
                            self->priv->notebook,
1794
 
                            TRUE, TRUE, 0);
1795
 
        gtk_container_set_border_width (GTK_CONTAINER (self->priv->notebook), 5);
1796
 
 
1797
 
        /* Effects page */
1798
 
        self->priv->sound_effects_box = gtk_vbox_new (FALSE, 6);
1799
 
        gtk_container_set_border_width (GTK_CONTAINER (self->priv->sound_effects_box), 12);
1800
 
        label = gtk_label_new (_("Sound Effects"));
1801
 
        gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
1802
 
                                  self->priv->sound_effects_box,
1803
 
                                  label);
1804
 
 
1805
 
        self->priv->effects_bar = create_bar (self, TRUE, TRUE);
1806
 
        gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->effects_bar),
1807
 
                                  _("_Alert volume:"));
1808
 
        gtk_widget_set_sensitive (self->priv->effects_bar, FALSE);
1809
 
        gtk_box_pack_start (GTK_BOX (self->priv->sound_effects_box),
1810
 
                            self->priv->effects_bar, FALSE, FALSE, 0);
1811
 
 
1812
 
        self->priv->sound_theme_chooser = gvc_sound_theme_chooser_new ();
1813
 
        gtk_box_pack_start (GTK_BOX (self->priv->sound_effects_box),
1814
 
                            self->priv->sound_theme_chooser,
1815
 
                            TRUE, TRUE, 6);
1816
 
 
1817
 
        /* Hardware page */
1818
 
        self->priv->hw_box = gtk_vbox_new (FALSE, 12);
1819
 
        gtk_container_set_border_width (GTK_CONTAINER (self->priv->hw_box), 12);
1820
 
        label = gtk_label_new (_("Hardware"));
1821
 
        gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
1822
 
                                  self->priv->hw_box,
1823
 
                                  label);
1824
 
 
1825
 
        box = gtk_frame_new (_("C_hoose a device to configure:"));
1826
 
        label = gtk_frame_get_label_widget (GTK_FRAME (box));
1827
 
        _gtk_label_make_bold (GTK_LABEL (label));
1828
 
        gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
1829
 
        gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
1830
 
        gtk_box_pack_start (GTK_BOX (self->priv->hw_box), box, TRUE, TRUE, 0);
1831
 
 
1832
 
        alignment = gtk_alignment_new (0, 0, 1, 1);
1833
 
        gtk_container_add (GTK_CONTAINER (box), alignment);
1834
 
        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0);
1835
 
 
1836
 
        self->priv->hw_treeview = create_cards_treeview (self,
1837
 
                                                         G_CALLBACK (on_card_selection_changed));
1838
 
        gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->hw_treeview);
1839
 
 
1840
 
        box = gtk_scrolled_window_new (NULL, NULL);
1841
 
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (box),
1842
 
                                        GTK_POLICY_NEVER,
1843
 
                                        GTK_POLICY_AUTOMATIC);
1844
 
        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (box),
1845
 
                                             GTK_SHADOW_IN);
1846
 
        gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (box), 150);
1847
 
        gtk_container_add (GTK_CONTAINER (box), self->priv->hw_treeview);
1848
 
        gtk_container_add (GTK_CONTAINER (alignment), box);
1849
 
 
1850
 
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->hw_treeview));
1851
 
        gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1852
 
 
1853
 
        box = gtk_frame_new (_("Settings for the selected device:"));
1854
 
        label = gtk_frame_get_label_widget (GTK_FRAME (box));
1855
 
        _gtk_label_make_bold (GTK_LABEL (label));
1856
 
        gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
1857
 
        gtk_box_pack_start (GTK_BOX (self->priv->hw_box), box, FALSE, TRUE, 12);
1858
 
        self->priv->hw_settings_box = gtk_vbox_new (FALSE, 12);
1859
 
        gtk_container_add (GTK_CONTAINER (box), self->priv->hw_settings_box);
1860
 
 
1861
 
        /* Input page */
1862
 
        self->priv->input_box = gtk_vbox_new (FALSE, 12);
1863
 
        gtk_container_set_border_width (GTK_CONTAINER (self->priv->input_box), 12);
1864
 
        label = gtk_label_new (_("Input"));
1865
 
        gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
1866
 
                                  self->priv->input_box,
1867
 
                                  label);
1868
 
 
1869
 
        self->priv->input_bar = create_bar (self, TRUE, TRUE);
1870
 
        gvc_channel_bar_set_name (GVC_CHANNEL_BAR (self->priv->input_bar),
1871
 
                                  _("_Input volume:"));
1872
 
        gvc_channel_bar_set_low_icon_name (GVC_CHANNEL_BAR (self->priv->input_bar),
1873
 
                                           "audio-input-microphone-low-symbolic");
1874
 
        gvc_channel_bar_set_high_icon_name (GVC_CHANNEL_BAR (self->priv->input_bar),
1875
 
                                            "audio-input-microphone-high-symbolic");
1876
 
        gtk_widget_set_sensitive (self->priv->input_bar, FALSE);
1877
 
        alignment = gtk_alignment_new (0, 0, 1, 1);
1878
 
        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0);
1879
 
        gtk_container_add (GTK_CONTAINER (alignment), self->priv->input_bar);
1880
 
        gtk_box_pack_start (GTK_BOX (self->priv->input_box),
1881
 
                            alignment,
1882
 
                            FALSE, FALSE, 0);
1883
 
 
1884
 
        box = gtk_hbox_new (FALSE, 6);
1885
 
        gtk_box_pack_start (GTK_BOX (self->priv->input_box),
1886
 
                            box,
1887
 
                            FALSE, FALSE, 6);
1888
 
 
1889
 
        sbox = gtk_hbox_new (FALSE, 6);
1890
 
        gtk_box_pack_start (GTK_BOX (box),
1891
 
                            sbox,
1892
 
                            FALSE, FALSE, 0);
1893
 
 
1894
 
        label = gtk_label_new (_("Input level:"));
1895
 
        gtk_box_pack_start (GTK_BOX (sbox),
1896
 
                            label,
1897
 
                            FALSE, FALSE, 0);
1898
 
        if (self->priv->size_group != NULL)
1899
 
                gtk_size_group_add_widget (self->priv->size_group, sbox);
1900
 
 
1901
 
        self->priv->input_level_bar = gvc_level_bar_new ();
1902
 
        gvc_level_bar_set_orientation (GVC_LEVEL_BAR (self->priv->input_level_bar),
1903
 
                                       GTK_ORIENTATION_HORIZONTAL);
1904
 
        gvc_level_bar_set_scale (GVC_LEVEL_BAR (self->priv->input_level_bar),
1905
 
                                 GVC_LEVEL_SCALE_LINEAR);
1906
 
        gtk_box_pack_start (GTK_BOX (box),
1907
 
                            self->priv->input_level_bar,
1908
 
                            TRUE, TRUE, 6);
1909
 
 
1910
 
        ebox = gtk_hbox_new (FALSE, 6);
1911
 
        gtk_box_pack_start (GTK_BOX (box),
1912
 
                            ebox,
1913
 
                            FALSE, FALSE, 0);
1914
 
        if (self->priv->size_group != NULL)
1915
 
                gtk_size_group_add_widget (self->priv->size_group, ebox);
1916
 
 
1917
 
        self->priv->input_settings_box = gtk_hbox_new (FALSE, 6);
1918
 
        gtk_box_pack_start (GTK_BOX (self->priv->input_box),
1919
 
                            self->priv->input_settings_box,
1920
 
                            FALSE, FALSE, 0);
1921
 
 
1922
 
        box = gtk_frame_new (_("C_hoose a device for sound input:"));
1923
 
        label = gtk_frame_get_label_widget (GTK_FRAME (box));
1924
 
        _gtk_label_make_bold (GTK_LABEL (label));
1925
 
        gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
1926
 
        gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
1927
 
        gtk_box_pack_start (GTK_BOX (self->priv->input_box), box, TRUE, TRUE, 0);
1928
 
 
1929
 
        alignment = gtk_alignment_new (0, 0, 1, 1);
1930
 
        gtk_container_add (GTK_CONTAINER (box), alignment);
1931
 
        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0);
1932
 
 
1933
 
        self->priv->input_treeview = create_stream_treeview (self,
1934
 
                                                             G_CALLBACK (on_input_selection_changed));
1935
 
        gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->input_treeview);
1936
 
 
1937
 
        box = gtk_scrolled_window_new (NULL, NULL);
1938
 
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (box),
1939
 
                                        GTK_POLICY_NEVER,
1940
 
                                        GTK_POLICY_AUTOMATIC);
1941
 
        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (box),
1942
 
                                             GTK_SHADOW_IN);
1943
 
        gtk_container_add (GTK_CONTAINER (box), self->priv->input_treeview);
1944
 
        gtk_container_add (GTK_CONTAINER (alignment), box);
1945
 
 
1946
 
        /* Output page */
1947
 
        self->priv->output_box = gtk_vbox_new (FALSE, 12);
1948
 
        gtk_container_set_border_width (GTK_CONTAINER (self->priv->output_box), 12);
1949
 
        label = gtk_label_new (_("Output"));
1950
 
        gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
1951
 
                                  self->priv->output_box,
1952
 
                                  label);
1953
 
 
1954
 
        box = gtk_frame_new (_("C_hoose a device for sound output:"));
1955
 
        label = gtk_frame_get_label_widget (GTK_FRAME (box));
1956
 
        _gtk_label_make_bold (GTK_LABEL (label));
1957
 
        gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
1958
 
        gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
1959
 
        gtk_box_pack_start (GTK_BOX (self->priv->output_box), box, TRUE, TRUE, 0);
1960
 
 
1961
 
        alignment = gtk_alignment_new (0, 0, 1, 1);
1962
 
        gtk_container_add (GTK_CONTAINER (box), alignment);
1963
 
        gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0);
1964
 
 
1965
 
        self->priv->output_treeview = create_stream_treeview (self,
1966
 
                                                              G_CALLBACK (on_output_selection_changed));
1967
 
        gtk_label_set_mnemonic_widget (GTK_LABEL (label), self->priv->output_treeview);
1968
 
 
1969
 
        box = gtk_scrolled_window_new (NULL, NULL);
1970
 
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (box),
1971
 
                                        GTK_POLICY_NEVER,
1972
 
                                        GTK_POLICY_AUTOMATIC);
1973
 
        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (box),
1974
 
                                             GTK_SHADOW_IN);
1975
 
        gtk_container_add (GTK_CONTAINER (box), self->priv->output_treeview);
1976
 
        gtk_container_add (GTK_CONTAINER (alignment), box);
1977
 
 
1978
 
        box = gtk_frame_new (_("Settings for the selected device:"));
1979
 
        label = gtk_frame_get_label_widget (GTK_FRAME (box));
1980
 
        _gtk_label_make_bold (GTK_LABEL (label));
1981
 
        gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE);
1982
 
        gtk_box_pack_start (GTK_BOX (self->priv->output_box), box, FALSE, FALSE, 12);
1983
 
        self->priv->output_settings_box = gtk_vbox_new (FALSE, 0);
1984
 
        gtk_container_add (GTK_CONTAINER (box), self->priv->output_settings_box);
1985
 
 
1986
 
        /* Applications */
1987
 
        self->priv->applications_box = gtk_vbox_new (FALSE, 12);
1988
 
        gtk_container_set_border_width (GTK_CONTAINER (self->priv->applications_box), 12);
1989
 
        label = gtk_label_new (_("Applications"));
1990
 
        gtk_notebook_append_page (GTK_NOTEBOOK (self->priv->notebook),
1991
 
                                  self->priv->applications_box,
1992
 
                                  label);
1993
 
        self->priv->no_apps_label = gtk_label_new (_("No application is currently playing or recording audio."));
1994
 
        gtk_box_pack_start (GTK_BOX (self->priv->applications_box),
1995
 
                            self->priv->no_apps_label,
1996
 
                            TRUE, TRUE, 0);
1997
 
 
1998
 
        g_signal_connect (self->priv->mixer_control,
1999
 
                          "stream-added",
2000
 
                          G_CALLBACK (on_control_stream_added),
2001
 
                          self);
2002
 
        g_signal_connect (self->priv->mixer_control,
2003
 
                          "stream-removed",
2004
 
                          G_CALLBACK (on_control_stream_removed),
2005
 
                          self);
2006
 
        g_signal_connect (self->priv->mixer_control,
2007
 
                          "card-added",
2008
 
                          G_CALLBACK (on_control_card_added),
2009
 
                          self);
2010
 
        g_signal_connect (self->priv->mixer_control,
2011
 
                          "card-removed",
2012
 
                          G_CALLBACK (on_control_card_removed),
2013
 
                          self);
2014
 
 
2015
 
        gtk_widget_show_all (main_vbox);
2016
 
 
2017
 
        streams = gvc_mixer_control_get_streams (self->priv->mixer_control);
2018
 
        for (l = streams; l != NULL; l = l->next) {
2019
 
                stream = l->data;
2020
 
                add_stream (self, stream);
2021
 
        }
2022
 
        g_slist_free (streams);
2023
 
 
2024
 
        cards = gvc_mixer_control_get_cards (self->priv->mixer_control);
2025
 
        for (l = cards; l != NULL; l = l->next) {
2026
 
                card = l->data;
2027
 
                add_card (self, card);
2028
 
        }
2029
 
        g_slist_free (cards);
2030
 
 
2031
 
        return object;
2032
 
}
2033
 
 
2034
 
static void
2035
 
gvc_mixer_dialog_dispose (GObject *object)
2036
 
{
2037
 
        GvcMixerDialog *dialog = GVC_MIXER_DIALOG (object);
2038
 
 
2039
 
        if (dialog->priv->mixer_control != NULL) {
2040
 
                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2041
 
                                                      on_control_stream_added,
2042
 
                                                      dialog);
2043
 
                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2044
 
                                                      on_control_stream_removed,
2045
 
                                                      dialog);
2046
 
                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2047
 
                                                      on_control_card_added,
2048
 
                                                      dialog);
2049
 
                g_signal_handlers_disconnect_by_func (dialog->priv->mixer_control,
2050
 
                                                      on_control_card_removed,
2051
 
                                                      dialog);
2052
 
 
2053
 
                g_object_unref (dialog->priv->mixer_control);
2054
 
                dialog->priv->mixer_control = NULL;
2055
 
        }
2056
 
 
2057
 
        if (dialog->priv->bars != NULL) {
2058
 
                g_hash_table_destroy (dialog->priv->bars);
2059
 
                dialog->priv->bars = NULL;
2060
 
        }
2061
 
 
2062
 
        G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->dispose (object);
2063
 
}
2064
 
 
2065
 
static void
2066
 
gvc_mixer_dialog_class_init (GvcMixerDialogClass *klass)
2067
 
{
2068
 
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
2069
 
 
2070
 
        object_class->constructor = gvc_mixer_dialog_constructor;
2071
 
        object_class->dispose = gvc_mixer_dialog_dispose;
2072
 
        object_class->finalize = gvc_mixer_dialog_finalize;
2073
 
        object_class->set_property = gvc_mixer_dialog_set_property;
2074
 
        object_class->get_property = gvc_mixer_dialog_get_property;
2075
 
 
2076
 
        g_object_class_install_property (object_class,
2077
 
                                         PROP_MIXER_CONTROL,
2078
 
                                         g_param_spec_object ("mixer-control",
2079
 
                                                              "mixer control",
2080
 
                                                              "mixer control",
2081
 
                                                              GVC_TYPE_MIXER_CONTROL,
2082
 
                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
2083
 
 
2084
 
        g_type_class_add_private (klass, sizeof (GvcMixerDialogPrivate));
2085
 
}
2086
 
 
2087
 
 
2088
 
static void
2089
 
gvc_mixer_dialog_init (GvcMixerDialog *dialog)
2090
 
{
2091
 
        dialog->priv = GVC_MIXER_DIALOG_GET_PRIVATE (dialog);
2092
 
        dialog->priv->bars = g_hash_table_new (NULL, NULL);
2093
 
        dialog->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
2094
 
}
2095
 
 
2096
 
static void
2097
 
gvc_mixer_dialog_finalize (GObject *object)
2098
 
{
2099
 
        GvcMixerDialog *mixer_dialog;
2100
 
 
2101
 
        g_return_if_fail (object != NULL);
2102
 
        g_return_if_fail (GVC_IS_MIXER_DIALOG (object));
2103
 
 
2104
 
        mixer_dialog = GVC_MIXER_DIALOG (object);
2105
 
 
2106
 
        g_return_if_fail (mixer_dialog->priv != NULL);
2107
 
        G_OBJECT_CLASS (gvc_mixer_dialog_parent_class)->finalize (object);
2108
 
}
2109
 
 
2110
 
GvcMixerDialog *
2111
 
gvc_mixer_dialog_new (GvcMixerControl *control)
2112
 
{
2113
 
        GObject *dialog;
2114
 
        dialog = g_object_new (GVC_TYPE_MIXER_DIALOG,
2115
 
                               "mixer-control", control,
2116
 
                               NULL);
2117
 
        return GVC_MIXER_DIALOG (dialog);
2118
 
}
2119
 
 
2120
 
enum {
2121
 
        PAGE_EVENTS,
2122
 
        PAGE_HARDWARE,
2123
 
        PAGE_INPUT,
2124
 
        PAGE_OUTPUT,
2125
 
        PAGE_APPLICATIONS
2126
 
};
2127
 
 
2128
 
gboolean
2129
 
gvc_mixer_dialog_set_page (GvcMixerDialog *self,
2130
 
                           const char     *page)
2131
 
{
2132
 
        guint num;
2133
 
 
2134
 
        g_return_val_if_fail (self != NULL, FALSE);
2135
 
 
2136
 
        if (page == NULL)
2137
 
                num = 0;
2138
 
        else if (g_str_equal (page, "effects"))
2139
 
                num = PAGE_EVENTS;
2140
 
        else if (g_str_equal (page, "hardware"))
2141
 
                num = PAGE_HARDWARE;
2142
 
        else if (g_str_equal (page, "input"))
2143
 
                num = PAGE_INPUT;
2144
 
        else if (g_str_equal (page, "output"))
2145
 
                num = PAGE_OUTPUT;
2146
 
        else if (g_str_equal (page, "applications"))
2147
 
                num = PAGE_APPLICATIONS;
2148
 
        else
2149
 
                num = 0;
2150
 
 
2151
 
        gtk_notebook_set_current_page (GTK_NOTEBOOK (self->priv->notebook), num);
2152
 
 
2153
 
        return TRUE;
2154
 
}