~elementary-os/elementaryos/os-patch-gnome-control-center-precise

« back to all changes in this revision

Viewing changes to panels/sound/gvc-channel-bar.c

  • Committer: Sergey "Shnatsel" Davidoff
  • Date: 2012-05-18 13:02:50 UTC
  • Revision ID: shnatsel@gmail.com-20120518130250-2u99ldq61a42rbt7
Initial import, version 1:3.4.1-0ubuntu2

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 <pulse/pulseaudio.h>
 
28
 
 
29
#include <glib.h>
 
30
#include <glib/gi18n-lib.h>
 
31
#include <gtk/gtk.h>
 
32
#include <canberra-gtk.h>
 
33
 
 
34
#include "gvc-channel-bar.h"
 
35
#include "gvc-mixer-control.h"
 
36
 
 
37
#define SCALE_SIZE 128
 
38
#define ADJUSTMENT_MAX_NORMAL gvc_mixer_control_get_vol_max_norm(NULL)
 
39
#define ADJUSTMENT_MAX_AMPLIFIED gvc_mixer_control_get_vol_max_amplified(NULL)
 
40
#define ADJUSTMENT_MAX (bar->priv->is_amplified ? ADJUSTMENT_MAX_AMPLIFIED : ADJUSTMENT_MAX_NORMAL)
 
41
#define SCROLLSTEP (ADJUSTMENT_MAX / 100.0 * 5.0)
 
42
 
 
43
#define GVC_CHANNEL_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_CHANNEL_BAR, GvcChannelBarPrivate))
 
44
 
 
45
struct GvcChannelBarPrivate
 
46
{
 
47
        GtkOrientation orientation;
 
48
        GtkWidget     *scale_box;
 
49
        GtkWidget     *start_box;
 
50
        GtkWidget     *end_box;
 
51
        GtkWidget     *image;
 
52
        GtkWidget     *label;
 
53
        GtkWidget     *low_image;
 
54
        GtkWidget     *scale;
 
55
        GtkWidget     *high_image;
 
56
        GtkWidget     *mute_box;
 
57
        GtkWidget     *mute_switch;
 
58
        GtkAdjustment *adjustment;
 
59
        GtkAdjustment *zero_adjustment;
 
60
        gboolean       show_mute;
 
61
        gboolean       is_muted;
 
62
        char          *name;
 
63
        char          *icon_name;
 
64
        char          *low_icon_name;
 
65
        char          *high_icon_name;
 
66
        GtkSizeGroup  *size_group;
 
67
        gboolean       symmetric;
 
68
        gboolean       click_lock;
 
69
        gboolean       is_amplified;
 
70
        guint32        base_volume;
 
71
};
 
72
 
 
73
enum
 
74
{
 
75
        PROP_0,
 
76
        PROP_ORIENTATION,
 
77
        PROP_SHOW_MUTE,
 
78
        PROP_IS_MUTED,
 
79
        PROP_ADJUSTMENT,
 
80
        PROP_NAME,
 
81
        PROP_ICON_NAME,
 
82
        PROP_LOW_ICON_NAME,
 
83
        PROP_HIGH_ICON_NAME,
 
84
        PROP_IS_AMPLIFIED,
 
85
        PROP_ELLIPSIZE
 
86
};
 
87
 
 
88
static void     gvc_channel_bar_class_init    (GvcChannelBarClass *klass);
 
89
static void     gvc_channel_bar_init          (GvcChannelBar      *channel_bar);
 
90
static void     gvc_channel_bar_finalize      (GObject            *object);
 
91
 
 
92
static gboolean on_scale_button_press_event   (GtkWidget      *widget,
 
93
                                               GdkEventButton *event,
 
94
                                               GvcChannelBar  *bar);
 
95
static gboolean on_scale_button_release_event (GtkWidget      *widget,
 
96
                                               GdkEventButton *event,
 
97
                                               GvcChannelBar  *bar);
 
98
static gboolean on_scale_scroll_event         (GtkWidget      *widget,
 
99
                                               GdkEventScroll *event,
 
100
                                               GvcChannelBar  *bar);
 
101
 
 
102
G_DEFINE_TYPE (GvcChannelBar, gvc_channel_bar, GTK_TYPE_HBOX)
 
103
 
 
104
static GtkWidget *
 
105
_scale_box_new (GvcChannelBar *bar)
 
106
{
 
107
        GvcChannelBarPrivate *priv = bar->priv;
 
108
        GtkWidget            *box;
 
109
        GtkWidget            *sbox;
 
110
        GtkWidget            *ebox;
 
111
 
 
112
        if (priv->orientation == GTK_ORIENTATION_VERTICAL) {
 
113
                bar->priv->scale_box = box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
 
114
 
 
115
                priv->scale = gtk_vscale_new (priv->adjustment);
 
116
 
 
117
                gtk_widget_set_size_request (priv->scale, -1, SCALE_SIZE);
 
118
                gtk_range_set_inverted (GTK_RANGE (priv->scale), TRUE);
 
119
 
 
120
                bar->priv->start_box = sbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
 
121
                gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0);
 
122
 
 
123
                gtk_box_pack_start (GTK_BOX (sbox), priv->image, FALSE, FALSE, 0);
 
124
                gtk_box_pack_start (GTK_BOX (sbox), priv->label, FALSE, FALSE, 0);
 
125
 
 
126
                gtk_box_pack_start (GTK_BOX (sbox), priv->high_image, FALSE, FALSE, 0);
 
127
                gtk_widget_hide (priv->high_image);
 
128
                gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, TRUE, 0);
 
129
 
 
130
                bar->priv->end_box = ebox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
 
131
                gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0);
 
132
 
 
133
                gtk_box_pack_start (GTK_BOX (ebox), priv->low_image, FALSE, FALSE, 0);
 
134
                gtk_widget_hide (priv->low_image);
 
135
 
 
136
                gtk_box_pack_start (GTK_BOX (ebox), priv->mute_box, FALSE, FALSE, 0);
 
137
        } else {
 
138
                bar->priv->scale_box = box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
 
139
                gtk_box_pack_start (GTK_BOX (box), priv->image, FALSE, FALSE, 0);
 
140
 
 
141
                priv->scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, priv->adjustment);
 
142
 
 
143
                gtk_widget_set_size_request (priv->scale, SCALE_SIZE, -1);
 
144
 
 
145
                bar->priv->start_box = sbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
 
146
                gtk_box_pack_start (GTK_BOX (box), sbox, FALSE, FALSE, 0);
 
147
 
 
148
                gtk_box_pack_end (GTK_BOX (sbox), priv->low_image, FALSE, FALSE, 0);
 
149
                gtk_widget_show (priv->low_image);
 
150
 
 
151
                gtk_box_pack_start (GTK_BOX (sbox), priv->label, TRUE, TRUE, 0);
 
152
                gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, TRUE, 0);
 
153
 
 
154
                bar->priv->end_box = ebox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
 
155
                gtk_box_pack_start (GTK_BOX (box), ebox, FALSE, FALSE, 0);
 
156
 
 
157
                gtk_box_pack_start (GTK_BOX (ebox), priv->high_image, FALSE, FALSE, 0);
 
158
                gtk_widget_show (priv->high_image);
 
159
                gtk_box_pack_start (GTK_BOX (ebox), priv->mute_box, FALSE, FALSE, 0);
 
160
        }
 
161
 
 
162
        ca_gtk_widget_disable_sounds (bar->priv->scale, FALSE);
 
163
        gtk_widget_add_events (bar->priv->scale, GDK_SCROLL_MASK);
 
164
 
 
165
        g_signal_connect (G_OBJECT (bar->priv->scale), "button-press-event",
 
166
                          G_CALLBACK (on_scale_button_press_event), bar);
 
167
        g_signal_connect (G_OBJECT (bar->priv->scale), "button-release-event",
 
168
                          G_CALLBACK (on_scale_button_release_event), bar);
 
169
        g_signal_connect (G_OBJECT (bar->priv->scale), "scroll-event",
 
170
                          G_CALLBACK (on_scale_scroll_event), bar);
 
171
 
 
172
        if (bar->priv->size_group != NULL) {
 
173
                gtk_size_group_add_widget (bar->priv->size_group, sbox);
 
174
 
 
175
                if (bar->priv->symmetric) {
 
176
                        gtk_size_group_add_widget (bar->priv->size_group, ebox);
 
177
                }
 
178
        }
 
179
 
 
180
        gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE);
 
181
 
 
182
        return box;
 
183
}
 
184
 
 
185
static void
 
186
update_image (GvcChannelBar *bar)
 
187
{
 
188
        gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->image),
 
189
                                      bar->priv->icon_name,
 
190
                                      GTK_ICON_SIZE_DIALOG);
 
191
 
 
192
        if (bar->priv->icon_name != NULL) {
 
193
                gtk_widget_show (bar->priv->image);
 
194
        } else {
 
195
                gtk_widget_hide (bar->priv->image);
 
196
        }
 
197
}
 
198
 
 
199
static void
 
200
update_label (GvcChannelBar *bar)
 
201
{
 
202
        if (bar->priv->name != NULL) {
 
203
                gtk_label_set_text_with_mnemonic (GTK_LABEL (bar->priv->label),
 
204
                                                  bar->priv->name);
 
205
                gtk_label_set_mnemonic_widget (GTK_LABEL (bar->priv->label),
 
206
                                               bar->priv->scale);
 
207
                gtk_widget_show (bar->priv->label);
 
208
        } else {
 
209
                gtk_label_set_text (GTK_LABEL (bar->priv->label), NULL);
 
210
                gtk_widget_hide (bar->priv->label);
 
211
        }
 
212
}
 
213
 
 
214
static void
 
215
update_layout (GvcChannelBar *bar)
 
216
{
 
217
        GtkWidget *box;
 
218
        GtkWidget *frame;
 
219
 
 
220
        if (bar->priv->scale == NULL) {
 
221
                return;
 
222
        }
 
223
 
 
224
        box = bar->priv->scale_box;
 
225
        frame = gtk_widget_get_parent (box);
 
226
 
 
227
        g_object_ref (bar->priv->image);
 
228
        g_object_ref (bar->priv->label);
 
229
        g_object_ref (bar->priv->mute_box);
 
230
        g_object_ref (bar->priv->low_image);
 
231
        g_object_ref (bar->priv->high_image);
 
232
 
 
233
        gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->image);
 
234
        gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->label);
 
235
        gtk_container_remove (GTK_CONTAINER (bar->priv->end_box), bar->priv->mute_box);
 
236
 
 
237
        if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
 
238
                gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->low_image);
 
239
                gtk_container_remove (GTK_CONTAINER (bar->priv->end_box), bar->priv->high_image);
 
240
        } else {
 
241
                gtk_container_remove (GTK_CONTAINER (bar->priv->end_box), bar->priv->low_image);
 
242
                gtk_container_remove (GTK_CONTAINER (bar->priv->start_box), bar->priv->high_image);
 
243
        }
 
244
 
 
245
        gtk_container_remove (GTK_CONTAINER (box), bar->priv->start_box);
 
246
        gtk_container_remove (GTK_CONTAINER (box), bar->priv->scale);
 
247
        gtk_container_remove (GTK_CONTAINER (box), bar->priv->end_box);
 
248
        gtk_container_remove (GTK_CONTAINER (frame), box);
 
249
 
 
250
        bar->priv->scale_box = _scale_box_new (bar);
 
251
        gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box);
 
252
 
 
253
        g_object_unref (bar->priv->image);
 
254
        g_object_unref (bar->priv->label);
 
255
        g_object_unref (bar->priv->mute_box);
 
256
        g_object_unref (bar->priv->low_image);
 
257
        g_object_unref (bar->priv->high_image);
 
258
 
 
259
        gtk_widget_show_all (frame);
 
260
}
 
261
 
 
262
void
 
263
gvc_channel_bar_set_size_group (GvcChannelBar *bar,
 
264
                                GtkSizeGroup  *group,
 
265
                                gboolean       symmetric)
 
266
{
 
267
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
268
 
 
269
        bar->priv->size_group = group;
 
270
        bar->priv->symmetric = symmetric;
 
271
 
 
272
        if (bar->priv->size_group != NULL) {
 
273
                gtk_size_group_add_widget (bar->priv->size_group,
 
274
                                           bar->priv->start_box);
 
275
 
 
276
                if (bar->priv->symmetric) {
 
277
                        gtk_size_group_add_widget (bar->priv->size_group,
 
278
                                                   bar->priv->end_box);
 
279
                }
 
280
        }
 
281
        gtk_widget_queue_draw (GTK_WIDGET (bar));
 
282
}
 
283
 
 
284
void
 
285
gvc_channel_bar_set_name (GvcChannelBar  *bar,
 
286
                          const char     *name)
 
287
{
 
288
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
289
 
 
290
        g_free (bar->priv->name);
 
291
        bar->priv->name = g_strdup (name);
 
292
        update_label (bar);
 
293
        g_object_notify (G_OBJECT (bar), "name");
 
294
}
 
295
 
 
296
void
 
297
gvc_channel_bar_set_icon_name (GvcChannelBar  *bar,
 
298
                               const char     *name)
 
299
{
 
300
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
301
 
 
302
        g_free (bar->priv->icon_name);
 
303
        bar->priv->icon_name = g_strdup (name);
 
304
        update_image (bar);
 
305
        g_object_notify (G_OBJECT (bar), "icon-name");
 
306
}
 
307
 
 
308
void
 
309
gvc_channel_bar_set_low_icon_name   (GvcChannelBar *bar,
 
310
                                     const char    *name)
 
311
{
 
312
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
313
 
 
314
        if (name != NULL && strcmp (bar->priv->low_icon_name, name) != 0) {
 
315
                g_free (bar->priv->low_icon_name);
 
316
                bar->priv->low_icon_name = g_strdup (name);
 
317
                gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->low_image),
 
318
                                              bar->priv->low_icon_name,
 
319
                                              GTK_ICON_SIZE_MENU);
 
320
                g_object_notify (G_OBJECT (bar), "low-icon-name");
 
321
        }
 
322
}
 
323
 
 
324
void
 
325
gvc_channel_bar_set_high_icon_name  (GvcChannelBar *bar,
 
326
                                     const char    *name)
 
327
{
 
328
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
329
 
 
330
        if (name != NULL && strcmp (bar->priv->high_icon_name, name) != 0) {
 
331
                g_free (bar->priv->high_icon_name);
 
332
                bar->priv->high_icon_name = g_strdup (name);
 
333
                gtk_image_set_from_icon_name (GTK_IMAGE (bar->priv->high_image),
 
334
                                              bar->priv->high_icon_name,
 
335
                                              GTK_ICON_SIZE_MENU);
 
336
                g_object_notify (G_OBJECT (bar), "high-icon-name");
 
337
        }
 
338
}
 
339
 
 
340
void
 
341
gvc_channel_bar_set_orientation (GvcChannelBar  *bar,
 
342
                                 GtkOrientation  orientation)
 
343
{
 
344
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
345
 
 
346
        if (orientation != bar->priv->orientation) {
 
347
                bar->priv->orientation = orientation;
 
348
                update_layout (bar);
 
349
                g_object_notify (G_OBJECT (bar), "orientation");
 
350
        }
 
351
}
 
352
 
 
353
static void
 
354
gvc_channel_bar_set_adjustment (GvcChannelBar *bar,
 
355
                                GtkAdjustment *adjustment)
 
356
{
 
357
        g_return_if_fail (GVC_CHANNEL_BAR (bar));
 
358
        g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
 
359
 
 
360
        if (bar->priv->adjustment != NULL) {
 
361
                g_object_unref (bar->priv->adjustment);
 
362
        }
 
363
        bar->priv->adjustment = g_object_ref_sink (adjustment);
 
364
 
 
365
        if (bar->priv->scale != NULL) {
 
366
                gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale), adjustment);
 
367
        }
 
368
 
 
369
        g_object_notify (G_OBJECT (bar), "adjustment");
 
370
}
 
371
 
 
372
GtkAdjustment *
 
373
gvc_channel_bar_get_adjustment (GvcChannelBar *bar)
 
374
{
 
375
        g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), NULL);
 
376
 
 
377
        return bar->priv->adjustment;
 
378
}
 
379
 
 
380
static gboolean
 
381
on_scale_button_press_event (GtkWidget      *widget,
 
382
                             GdkEventButton *event,
 
383
                             GvcChannelBar  *bar)
 
384
{
 
385
        /* HACK: we want the behaviour you get with the middle button, so we
 
386
         * mangle the event.  clicking with other buttons moves the slider in
 
387
         * step increments, clicking with the middle button moves the slider to
 
388
         * the location of the click.
 
389
         */
 
390
        if (event->button == 1)
 
391
                event->button = 2;
 
392
 
 
393
        bar->priv->click_lock = TRUE;
 
394
 
 
395
        return FALSE;
 
396
}
 
397
 
 
398
static gboolean
 
399
on_scale_button_release_event (GtkWidget      *widget,
 
400
                               GdkEventButton *event,
 
401
                               GvcChannelBar  *bar)
 
402
{
 
403
        GtkAdjustment *adj;
 
404
        gdouble value;
 
405
 
 
406
        /* HACK: see on_scale_button_press_event() */
 
407
        if (event->button == 1)
 
408
                event->button = 2;
 
409
 
 
410
        bar->priv->click_lock = FALSE;
 
411
 
 
412
        adj = gtk_range_get_adjustment (GTK_RANGE (widget));
 
413
 
 
414
        value = gtk_adjustment_get_value (adj);
 
415
 
 
416
        /* this means the adjustment moved away from zero and
 
417
         * therefore we should unmute and set the volume. */
 
418
        gvc_channel_bar_set_is_muted (bar, (value == 0.0));
 
419
 
 
420
        /* Play a sound! */
 
421
        ca_gtk_play_for_widget (GTK_WIDGET (bar), 0,
 
422
                                CA_PROP_EVENT_ID, "audio-volume-change",
 
423
                                CA_PROP_EVENT_DESCRIPTION, "foobar event happened",
 
424
                                CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl",
 
425
                                NULL);
 
426
 
 
427
        return FALSE;
 
428
}
 
429
 
 
430
gboolean
 
431
gvc_channel_bar_scroll (GvcChannelBar *bar, GdkScrollDirection direction)
 
432
{
 
433
        GtkAdjustment *adj;
 
434
        gdouble value;
 
435
 
 
436
        g_return_val_if_fail (bar != NULL, FALSE);
 
437
        g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
 
438
 
 
439
        if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
 
440
                if (direction != GDK_SCROLL_UP && direction != GDK_SCROLL_DOWN)
 
441
                        return FALSE;
 
442
        } else {
 
443
                /* Switch direction for RTL */
 
444
                if (gtk_widget_get_direction (GTK_WIDGET (bar)) == GTK_TEXT_DIR_RTL) {
 
445
                        if (direction == GDK_SCROLL_RIGHT)
 
446
                                direction = GDK_SCROLL_LEFT;
 
447
                        else if (direction == GDK_SCROLL_LEFT)
 
448
                                direction = GDK_SCROLL_RIGHT;
 
449
                }
 
450
                /* Switch side scroll to vertical */
 
451
                if (direction == GDK_SCROLL_RIGHT)
 
452
                        direction = GDK_SCROLL_UP;
 
453
                else if (direction == GDK_SCROLL_LEFT)
 
454
                        direction = GDK_SCROLL_DOWN;
 
455
        }
 
456
 
 
457
        adj = gtk_range_get_adjustment (GTK_RANGE (bar->priv->scale));
 
458
        if (adj == bar->priv->zero_adjustment) {
 
459
                if (direction == GDK_SCROLL_UP)
 
460
                        gvc_channel_bar_set_is_muted (bar, FALSE);
 
461
                return TRUE;
 
462
        }
 
463
 
 
464
        value = gtk_adjustment_get_value (adj);
 
465
 
 
466
        if (direction == GDK_SCROLL_UP) {
 
467
                if (value + SCROLLSTEP > ADJUSTMENT_MAX)
 
468
                        value = ADJUSTMENT_MAX;
 
469
                else
 
470
                        value = value + SCROLLSTEP;
 
471
        } else if (direction == GDK_SCROLL_DOWN) {
 
472
                if (value - SCROLLSTEP < 0)
 
473
                        value = 0.0;
 
474
                else
 
475
                        value = value - SCROLLSTEP;
 
476
        }
 
477
 
 
478
        gvc_channel_bar_set_is_muted (bar, (value == 0.0));
 
479
        adj = gtk_range_get_adjustment (GTK_RANGE (bar->priv->scale));
 
480
        gtk_adjustment_set_value (adj, value);
 
481
 
 
482
        return TRUE;
 
483
}
 
484
 
 
485
static gboolean
 
486
on_scale_scroll_event (GtkWidget      *widget,
 
487
                       GdkEventScroll *event,
 
488
                       GvcChannelBar  *bar)
 
489
{
 
490
        return gvc_channel_bar_scroll (bar, event->direction);
 
491
}
 
492
 
 
493
static void
 
494
on_zero_adjustment_value_changed (GtkAdjustment *adjustment,
 
495
                                  GvcChannelBar *bar)
 
496
{
 
497
        gdouble value;
 
498
 
 
499
        if (bar->priv->click_lock != FALSE) {
 
500
                return;
 
501
        }
 
502
 
 
503
        value = gtk_adjustment_get_value (bar->priv->zero_adjustment);
 
504
        gtk_adjustment_set_value (bar->priv->adjustment, value);
 
505
 
 
506
 
 
507
        if (bar->priv->show_mute == FALSE) {
 
508
                /* this means the adjustment moved away from zero and
 
509
                 * therefore we should unmute and set the volume. */
 
510
                gvc_channel_bar_set_is_muted (bar, value > 0.0);
 
511
        }
 
512
}
 
513
 
 
514
static void
 
515
update_mute_switch (GvcChannelBar *bar)
 
516
{
 
517
        if (bar->priv->show_mute) {
 
518
                gtk_widget_show (bar->priv->mute_switch);
 
519
                gtk_switch_set_active (GTK_SWITCH (bar->priv->mute_switch),
 
520
                                       !bar->priv->is_muted);
 
521
        } else {
 
522
                gtk_widget_hide (bar->priv->mute_switch);
 
523
        }
 
524
 
 
525
        if (bar->priv->is_muted) {
 
526
                /* If we aren't showing the mute button then
 
527
                 * move slider to the zero.  But we don't want to
 
528
                 * change the adjustment.  */
 
529
                g_signal_handlers_block_by_func (bar->priv->zero_adjustment,
 
530
                                                 on_zero_adjustment_value_changed,
 
531
                                                 bar);
 
532
                gtk_adjustment_set_value (bar->priv->zero_adjustment, 0);
 
533
                g_signal_handlers_unblock_by_func (bar->priv->zero_adjustment,
 
534
                                                   on_zero_adjustment_value_changed,
 
535
                                                   bar);
 
536
                gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale),
 
537
                                          bar->priv->zero_adjustment);
 
538
        } else {
 
539
                /* no longer muted so restore the original adjustment
 
540
                 * and tell the front-end that the value changed */
 
541
                gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale),
 
542
                                          bar->priv->adjustment);
 
543
                gtk_adjustment_value_changed (bar->priv->adjustment);
 
544
        }
 
545
}
 
546
 
 
547
void
 
548
gvc_channel_bar_set_is_muted (GvcChannelBar *bar,
 
549
                              gboolean       is_muted)
 
550
{
 
551
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
552
 
 
553
        if (is_muted != bar->priv->is_muted) {
 
554
                /* Update our internal state before telling the
 
555
                 * front-end about our changes */
 
556
                bar->priv->is_muted = is_muted;
 
557
                update_mute_switch (bar);
 
558
                g_object_notify (G_OBJECT (bar), "is-muted");
 
559
        }
 
560
}
 
561
 
 
562
gboolean
 
563
gvc_channel_bar_get_is_muted  (GvcChannelBar *bar)
 
564
{
 
565
        g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
 
566
        return bar->priv->is_muted;
 
567
}
 
568
 
 
569
void
 
570
gvc_channel_bar_set_show_mute (GvcChannelBar *bar,
 
571
                               gboolean       show_mute)
 
572
{
 
573
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
574
 
 
575
        if (show_mute != bar->priv->show_mute) {
 
576
                bar->priv->show_mute = show_mute;
 
577
                g_object_notify (G_OBJECT (bar), "show-mute");
 
578
                update_mute_switch (bar);
 
579
        }
 
580
}
 
581
 
 
582
gboolean
 
583
gvc_channel_bar_get_show_mute (GvcChannelBar *bar)
 
584
{
 
585
        g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
 
586
        return bar->priv->show_mute;
 
587
}
 
588
 
 
589
void
 
590
gvc_channel_bar_set_is_amplified (GvcChannelBar *bar, gboolean amplified)
 
591
{
 
592
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
593
 
 
594
        bar->priv->is_amplified = amplified;
 
595
        gtk_adjustment_set_upper (bar->priv->adjustment, ADJUSTMENT_MAX);
 
596
        gtk_adjustment_set_upper (bar->priv->zero_adjustment, ADJUSTMENT_MAX);
 
597
        gtk_scale_clear_marks (GTK_SCALE (bar->priv->scale));
 
598
 
 
599
        if (amplified) {
 
600
                char *str;
 
601
 
 
602
                if (bar->priv->base_volume == ADJUSTMENT_MAX_NORMAL) {
 
603
                        str = g_strdup_printf ("<small>%s</small>", C_("volume", "100%"));
 
604
                        gtk_scale_add_mark (GTK_SCALE (bar->priv->scale), ADJUSTMENT_MAX_NORMAL,
 
605
                                            GTK_POS_BOTTOM, str);
 
606
                } else {
 
607
                        str = g_strdup_printf ("<small>%s</small>", C_("volume", "Unamplified"));
 
608
                        gtk_scale_add_mark (GTK_SCALE (bar->priv->scale), bar->priv->base_volume,
 
609
                                            GTK_POS_BOTTOM, str);
 
610
                        /* Only show 100% if it's higher than the base volume */
 
611
                        if (bar->priv->base_volume < ADJUSTMENT_MAX_NORMAL) {
 
612
                                str = g_strdup_printf ("<small>%s</small>", C_("volume", "100%"));
 
613
                                gtk_scale_add_mark (GTK_SCALE (bar->priv->scale), ADJUSTMENT_MAX_NORMAL,
 
614
                                                    GTK_POS_BOTTOM, str);
 
615
                        }
 
616
                }
 
617
 
 
618
                g_free (str);
 
619
                gtk_alignment_set (GTK_ALIGNMENT (bar->priv->mute_box), 0.5, 0, 0, 0);
 
620
                gtk_misc_set_alignment (GTK_MISC (bar->priv->low_image), 0.5, 0.15);
 
621
                gtk_misc_set_alignment (GTK_MISC (bar->priv->high_image), 0.5, 0.15);
 
622
                gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0, 0);
 
623
        } else {
 
624
                gtk_alignment_set (GTK_ALIGNMENT (bar->priv->mute_box), 0.5, 0.5, 0, 0);
 
625
                gtk_misc_set_alignment (GTK_MISC (bar->priv->low_image), 0.5, 0.5);
 
626
                gtk_misc_set_alignment (GTK_MISC (bar->priv->high_image), 0.5, 0.5);
 
627
                gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0, 0.5);
 
628
        }
 
629
}
 
630
 
 
631
gboolean
 
632
gvc_channel_bar_get_ellipsize (GvcChannelBar *bar)
 
633
{
 
634
        g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
 
635
 
 
636
        return gtk_label_get_ellipsize (GTK_LABEL (bar->priv->label)) != PANGO_ELLIPSIZE_NONE;
 
637
}
 
638
 
 
639
void
 
640
gvc_channel_bar_set_ellipsize (GvcChannelBar *bar,
 
641
                               gboolean       ellipsized)
 
642
{
 
643
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
644
 
 
645
        if (ellipsized)
 
646
                gtk_label_set_ellipsize (GTK_LABEL (bar->priv->label), PANGO_ELLIPSIZE_END);
 
647
        else
 
648
                gtk_label_set_ellipsize (GTK_LABEL (bar->priv->label), PANGO_ELLIPSIZE_NONE);
 
649
}
 
650
 
 
651
void
 
652
gvc_channel_bar_set_base_volume (GvcChannelBar *bar,
 
653
                                 pa_volume_t    base_volume)
 
654
{
 
655
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
656
 
 
657
        if (base_volume == 0) {
 
658
                bar->priv->base_volume = ADJUSTMENT_MAX_NORMAL;
 
659
                return;
 
660
        }
 
661
 
 
662
        /* Note that you need to call _is_amplified() afterwards to update the marks */
 
663
        bar->priv->base_volume = base_volume;
 
664
}
 
665
 
 
666
static void
 
667
gvc_channel_bar_set_property (GObject       *object,
 
668
                              guint          prop_id,
 
669
                              const GValue  *value,
 
670
                              GParamSpec    *pspec)
 
671
{
 
672
        GvcChannelBar *self = GVC_CHANNEL_BAR (object);
 
673
 
 
674
        switch (prop_id) {
 
675
        case PROP_ORIENTATION:
 
676
                gvc_channel_bar_set_orientation (self, g_value_get_enum (value));
 
677
                break;
 
678
        case PROP_IS_MUTED:
 
679
                gvc_channel_bar_set_is_muted (self, g_value_get_boolean (value));
 
680
                break;
 
681
        case PROP_SHOW_MUTE:
 
682
                gvc_channel_bar_set_show_mute (self, g_value_get_boolean (value));
 
683
                break;
 
684
        case PROP_NAME:
 
685
                gvc_channel_bar_set_name (self, g_value_get_string (value));
 
686
                break;
 
687
        case PROP_ICON_NAME:
 
688
                gvc_channel_bar_set_icon_name (self, g_value_get_string (value));
 
689
                break;
 
690
        case PROP_LOW_ICON_NAME:
 
691
                gvc_channel_bar_set_low_icon_name (self, g_value_get_string (value));
 
692
                break;
 
693
        case PROP_HIGH_ICON_NAME:
 
694
                gvc_channel_bar_set_high_icon_name (self, g_value_get_string (value));
 
695
                break;
 
696
        case PROP_ADJUSTMENT:
 
697
                gvc_channel_bar_set_adjustment (self, g_value_get_object (value));
 
698
                break;
 
699
        case PROP_IS_AMPLIFIED:
 
700
                gvc_channel_bar_set_is_amplified (self, g_value_get_boolean (value));
 
701
                break;
 
702
        case PROP_ELLIPSIZE:
 
703
                gvc_channel_bar_set_ellipsize (self, g_value_get_boolean (value));
 
704
                break;
 
705
        default:
 
706
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
707
                break;
 
708
        }
 
709
}
 
710
 
 
711
static void
 
712
gvc_channel_bar_get_property (GObject     *object,
 
713
                              guint        prop_id,
 
714
                              GValue      *value,
 
715
                              GParamSpec  *pspec)
 
716
{
 
717
        GvcChannelBar *self = GVC_CHANNEL_BAR (object);
 
718
        GvcChannelBarPrivate *priv = self->priv;
 
719
 
 
720
        switch (prop_id) {
 
721
        case PROP_ORIENTATION:
 
722
                g_value_set_enum (value, priv->orientation);
 
723
                break;
 
724
        case PROP_IS_MUTED:
 
725
                g_value_set_boolean (value, priv->is_muted);
 
726
                break;
 
727
        case PROP_SHOW_MUTE:
 
728
                g_value_set_boolean (value, priv->show_mute);
 
729
                break;
 
730
        case PROP_NAME:
 
731
                g_value_set_string (value, priv->name);
 
732
                break;
 
733
        case PROP_ICON_NAME:
 
734
                g_value_set_string (value, priv->icon_name);
 
735
                break;
 
736
        case PROP_LOW_ICON_NAME:
 
737
                g_value_set_string (value, priv->low_icon_name);
 
738
                break;
 
739
        case PROP_HIGH_ICON_NAME:
 
740
                g_value_set_string (value, priv->high_icon_name);
 
741
                break;
 
742
        case PROP_ADJUSTMENT:
 
743
                g_value_set_object (value, gvc_channel_bar_get_adjustment (self));
 
744
                break;
 
745
        case PROP_IS_AMPLIFIED:
 
746
                g_value_set_boolean (value, priv->is_amplified);
 
747
                break;
 
748
        case PROP_ELLIPSIZE:
 
749
                g_value_set_boolean (value, gvc_channel_bar_get_ellipsize (self));
 
750
                break;
 
751
        default:
 
752
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
753
                break;
 
754
        }
 
755
}
 
756
 
 
757
static GObject *
 
758
gvc_channel_bar_constructor (GType                  type,
 
759
                             guint                  n_construct_properties,
 
760
                             GObjectConstructParam *construct_params)
 
761
{
 
762
        GObject       *object;
 
763
        GvcChannelBar *self;
 
764
 
 
765
        object = G_OBJECT_CLASS (gvc_channel_bar_parent_class)->constructor (type, n_construct_properties, construct_params);
 
766
 
 
767
        self = GVC_CHANNEL_BAR (object);
 
768
 
 
769
        update_mute_switch (self);
 
770
 
 
771
        return object;
 
772
}
 
773
 
 
774
static void
 
775
gvc_channel_bar_class_init (GvcChannelBarClass *klass)
 
776
{
 
777
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
 
778
 
 
779
        object_class->constructor = gvc_channel_bar_constructor;
 
780
        object_class->finalize = gvc_channel_bar_finalize;
 
781
        object_class->set_property = gvc_channel_bar_set_property;
 
782
        object_class->get_property = gvc_channel_bar_get_property;
 
783
 
 
784
        g_object_class_install_property (object_class,
 
785
                                         PROP_ORIENTATION,
 
786
                                         g_param_spec_enum ("orientation",
 
787
                                                            "Orientation",
 
788
                                                            "The orientation of the scale",
 
789
                                                            GTK_TYPE_ORIENTATION,
 
790
                                                            GTK_ORIENTATION_VERTICAL,
 
791
                                                            G_PARAM_READWRITE));
 
792
        g_object_class_install_property (object_class,
 
793
                                         PROP_IS_MUTED,
 
794
                                         g_param_spec_boolean ("is-muted",
 
795
                                                               "is muted",
 
796
                                                               "Whether stream is muted",
 
797
                                                               FALSE,
 
798
                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
799
        g_object_class_install_property (object_class,
 
800
                                         PROP_SHOW_MUTE,
 
801
                                         g_param_spec_boolean ("show-mute",
 
802
                                                               "show mute",
 
803
                                                               "Whether stream is muted",
 
804
                                                               FALSE,
 
805
                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
806
 
 
807
        g_object_class_install_property (object_class,
 
808
                                         PROP_ADJUSTMENT,
 
809
                                         g_param_spec_object ("adjustment",
 
810
                                                              "Adjustment",
 
811
                                                              "The GtkAdjustment that contains the current value of this scale button object",
 
812
                                                              GTK_TYPE_ADJUSTMENT,
 
813
                                                              G_PARAM_READWRITE));
 
814
        g_object_class_install_property (object_class,
 
815
                                         PROP_NAME,
 
816
                                         g_param_spec_string ("name",
 
817
                                                              "Name",
 
818
                                                              "Name to display for this stream",
 
819
                                                              NULL,
 
820
                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
821
        g_object_class_install_property (object_class,
 
822
                                         PROP_ICON_NAME,
 
823
                                         g_param_spec_string ("icon-name",
 
824
                                                              "Icon Name",
 
825
                                                              "Name of icon to display for this stream",
 
826
                                                              NULL,
 
827
                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
828
        g_object_class_install_property (object_class,
 
829
                                         PROP_LOW_ICON_NAME,
 
830
                                         g_param_spec_string ("low-icon-name",
 
831
                                                              "Icon Name",
 
832
                                                              "Name of icon to display for this stream",
 
833
                                                              "audio-volume-low-symbolic",
 
834
                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
835
        g_object_class_install_property (object_class,
 
836
                                         PROP_HIGH_ICON_NAME,
 
837
                                         g_param_spec_string ("high-icon-name",
 
838
                                                              "Icon Name",
 
839
                                                              "Name of icon to display for this stream",
 
840
                                                              "audio-volume-high-symbolic",
 
841
                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
842
        g_object_class_install_property (object_class,
 
843
                                         PROP_IS_AMPLIFIED,
 
844
                                         g_param_spec_boolean ("is-amplified",
 
845
                                                               "Is amplified",
 
846
                                                               "Whether the stream is digitally amplified",
 
847
                                                               FALSE,
 
848
                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
849
        g_object_class_install_property (object_class,
 
850
                                         PROP_ELLIPSIZE,
 
851
                                         g_param_spec_boolean ("ellipsize",
 
852
                                                               "Label is ellipsized",
 
853
                                                               "Whether the label is ellipsized",
 
854
                                                               FALSE,
 
855
                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
856
        g_type_class_add_private (klass, sizeof (GvcChannelBarPrivate));
 
857
}
 
858
 
 
859
static void
 
860
on_mute_switch_toggled (GtkSwitch     *sw,
 
861
                        GParamSpec *pspec,
 
862
                        GvcChannelBar *bar)
 
863
{
 
864
        gboolean is_muted;
 
865
        is_muted = gtk_switch_get_active (sw);
 
866
        gvc_channel_bar_set_is_muted (bar, !is_muted);
 
867
}
 
868
 
 
869
static void
 
870
gvc_channel_bar_init (GvcChannelBar *bar)
 
871
{
 
872
        GtkWidget *frame;
 
873
 
 
874
        bar->priv = GVC_CHANNEL_BAR_GET_PRIVATE (bar);
 
875
 
 
876
        bar->priv->base_volume = ADJUSTMENT_MAX_NORMAL;
 
877
        bar->priv->low_icon_name = g_strdup ("audio-volume-low-symbolic");
 
878
        bar->priv->high_icon_name = g_strdup ("audio-volume-high-symbolic");
 
879
 
 
880
        bar->priv->orientation = GTK_ORIENTATION_VERTICAL;
 
881
        bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
 
882
                                                                    0.0,
 
883
                                                                    ADJUSTMENT_MAX_NORMAL,
 
884
                                                                    ADJUSTMENT_MAX_NORMAL/100.0,
 
885
                                                                    ADJUSTMENT_MAX_NORMAL/10.0,
 
886
                                                                    0.0));
 
887
        g_object_ref_sink (bar->priv->adjustment);
 
888
 
 
889
        bar->priv->zero_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
 
890
                                                                         0.0,
 
891
                                                                         ADJUSTMENT_MAX_NORMAL,
 
892
                                                                         ADJUSTMENT_MAX_NORMAL/100.0,
 
893
                                                                         ADJUSTMENT_MAX_NORMAL/10.0,
 
894
                                                                         0.0));
 
895
        g_object_ref_sink (bar->priv->zero_adjustment);
 
896
 
 
897
        g_signal_connect (bar->priv->zero_adjustment,
 
898
                          "value-changed",
 
899
                          G_CALLBACK (on_zero_adjustment_value_changed),
 
900
                          bar);
 
901
 
 
902
        bar->priv->mute_switch = gtk_switch_new ();
 
903
        gtk_widget_set_no_show_all (bar->priv->mute_switch, TRUE);
 
904
        g_signal_connect (bar->priv->mute_switch,
 
905
                          "notify::active",
 
906
                          G_CALLBACK (on_mute_switch_toggled),
 
907
                          bar);
 
908
        bar->priv->mute_box = gtk_alignment_new (0.5, 0.5, 0, 0);
 
909
        gtk_container_add (GTK_CONTAINER (bar->priv->mute_box), bar->priv->mute_switch);
 
910
 
 
911
        bar->priv->low_image = gtk_image_new_from_icon_name ("audio-volume-low-symbolic",
 
912
                                                             GTK_ICON_SIZE_MENU);
 
913
        gtk_widget_set_no_show_all (bar->priv->low_image, TRUE);
 
914
        bar->priv->high_image = gtk_image_new_from_icon_name ("audio-volume-high-symbolic",
 
915
                                                              GTK_ICON_SIZE_MENU);
 
916
        gtk_widget_set_no_show_all (bar->priv->high_image, TRUE);
 
917
 
 
918
        bar->priv->image = gtk_image_new ();
 
919
        gtk_widget_set_no_show_all (bar->priv->image, TRUE);
 
920
 
 
921
        bar->priv->label = gtk_label_new (NULL);
 
922
        gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0.0, 0.5);
 
923
        gtk_widget_set_no_show_all (bar->priv->label, TRUE);
 
924
 
 
925
        /* frame */
 
926
        frame = gtk_frame_new (NULL);
 
927
        gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
 
928
        gtk_container_add (GTK_CONTAINER (bar), frame);
 
929
        gtk_widget_show_all (frame);
 
930
 
 
931
        /* box with scale */
 
932
        bar->priv->scale_box = _scale_box_new (bar);
 
933
 
 
934
        gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box);
 
935
}
 
936
 
 
937
static void
 
938
gvc_channel_bar_finalize (GObject *object)
 
939
{
 
940
        GvcChannelBar *channel_bar;
 
941
 
 
942
        g_return_if_fail (object != NULL);
 
943
        g_return_if_fail (GVC_IS_CHANNEL_BAR (object));
 
944
 
 
945
        channel_bar = GVC_CHANNEL_BAR (object);
 
946
 
 
947
        g_return_if_fail (channel_bar->priv != NULL);
 
948
 
 
949
        g_free (channel_bar->priv->name);
 
950
        g_free (channel_bar->priv->icon_name);
 
951
        g_free (channel_bar->priv->low_icon_name);
 
952
        g_free (channel_bar->priv->high_icon_name);
 
953
 
 
954
        G_OBJECT_CLASS (gvc_channel_bar_parent_class)->finalize (object);
 
955
}
 
956
 
 
957
GtkWidget *
 
958
gvc_channel_bar_new (void)
 
959
{
 
960
        GObject *bar;
 
961
        bar = g_object_new (GVC_TYPE_CHANNEL_BAR,
 
962
                            NULL);
 
963
        return GTK_WIDGET (bar);
 
964
}