~ubuntu-branches/ubuntu/trusty/unity-control-center/trusty

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Robert Ancell
  • Date: 2014-01-08 16:29:18 UTC
  • Revision ID: package-import@ubuntu.com-20140108162918-g29dd08tr913y2qh
Tags: upstream-14.04.0
ImportĀ upstreamĀ versionĀ 14.04.0

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_scale_new (GTK_ORIENTATION_VERTICAL, 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
        bar->priv->click_lock = TRUE;
 
386
 
 
387
        return FALSE;
 
388
}
 
389
 
 
390
static gboolean
 
391
on_scale_button_release_event (GtkWidget      *widget,
 
392
                               GdkEventButton *event,
 
393
                               GvcChannelBar  *bar)
 
394
{
 
395
        GtkAdjustment *adj;
 
396
        gdouble value;
 
397
 
 
398
        bar->priv->click_lock = FALSE;
 
399
 
 
400
        adj = gtk_range_get_adjustment (GTK_RANGE (widget));
 
401
 
 
402
        value = gtk_adjustment_get_value (adj);
 
403
 
 
404
        /* this means the adjustment moved away from zero and
 
405
         * therefore we should unmute and set the volume. */
 
406
        gvc_channel_bar_set_is_muted (bar, (value == 0.0));
 
407
 
 
408
        /* Play a sound! */
 
409
        ca_gtk_play_for_widget (GTK_WIDGET (bar), 0,
 
410
                                CA_PROP_EVENT_ID, "audio-volume-change",
 
411
                                CA_PROP_EVENT_DESCRIPTION, "foobar event happened",
 
412
                                CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl",
 
413
                                NULL);
 
414
 
 
415
        return FALSE;
 
416
}
 
417
 
 
418
gboolean
 
419
gvc_channel_bar_scroll (GvcChannelBar *bar, GdkEventScroll *event)
 
420
{
 
421
        GtkAdjustment *adj;
 
422
        gdouble value;
 
423
        GdkScrollDirection direction;
 
424
        gdouble dx, dy;
 
425
 
 
426
        g_return_val_if_fail (bar != NULL, FALSE);
 
427
        g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
 
428
 
 
429
        direction = event->direction;
 
430
 
 
431
        if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
 
432
                if (direction == GDK_SCROLL_LEFT || direction == GDK_SCROLL_RIGHT)
 
433
                        return FALSE;
 
434
        } else {
 
435
                /* Switch direction for RTL */
 
436
                if (gtk_widget_get_direction (GTK_WIDGET (bar)) == GTK_TEXT_DIR_RTL) {
 
437
                        if (direction == GDK_SCROLL_RIGHT)
 
438
                                direction = GDK_SCROLL_LEFT;
 
439
                        else if (direction == GDK_SCROLL_LEFT)
 
440
                                direction = GDK_SCROLL_RIGHT;
 
441
                }
 
442
                /* Switch side scroll to vertical */
 
443
                if (direction == GDK_SCROLL_RIGHT)
 
444
                        direction = GDK_SCROLL_UP;
 
445
                else if (direction == GDK_SCROLL_LEFT)
 
446
                        direction = GDK_SCROLL_DOWN;
 
447
        }
 
448
 
 
449
        if (!gdk_event_get_scroll_deltas ((GdkEvent*)event, &dx, &dy)) {
 
450
                dx = 0.0;
 
451
                dy = 0.0;
 
452
 
 
453
                switch (direction) {
 
454
                case GDK_SCROLL_UP:
 
455
                case GDK_SCROLL_LEFT:
 
456
                        dy = 1.0;
 
457
                        break;
 
458
                case GDK_SCROLL_DOWN:
 
459
                case GDK_SCROLL_RIGHT:
 
460
                        dy = -1.0;
 
461
                        break;
 
462
                default:
 
463
                        ;
 
464
                }
 
465
        }
 
466
 
 
467
        adj = gtk_range_get_adjustment (GTK_RANGE (bar->priv->scale));
 
468
        if (adj == bar->priv->zero_adjustment) {
 
469
                if (dy > 0)
 
470
                        gvc_channel_bar_set_is_muted (bar, FALSE);
 
471
                return TRUE;
 
472
        }
 
473
 
 
474
        value = gtk_adjustment_get_value (adj);
 
475
 
 
476
        if (dy > 0) {
 
477
                if (value + dy * SCROLLSTEP > ADJUSTMENT_MAX)
 
478
                        value = ADJUSTMENT_MAX;
 
479
                else
 
480
                        value = value + dy * SCROLLSTEP;
 
481
        } else if (dy < 0) {
 
482
                if (value + dy * SCROLLSTEP < 0)
 
483
                        value = 0.0;
 
484
                else
 
485
                        value = value + dy * SCROLLSTEP;
 
486
        }
 
487
 
 
488
        gvc_channel_bar_set_is_muted (bar, (value == 0.0));
 
489
        adj = gtk_range_get_adjustment (GTK_RANGE (bar->priv->scale));
 
490
        gtk_adjustment_set_value (adj, value);
 
491
 
 
492
        return TRUE;
 
493
}
 
494
 
 
495
static gboolean
 
496
on_scale_scroll_event (GtkWidget      *widget,
 
497
                       GdkEventScroll *event,
 
498
                       GvcChannelBar  *bar)
 
499
{
 
500
        return gvc_channel_bar_scroll (bar, event);
 
501
}
 
502
 
 
503
static void
 
504
on_zero_adjustment_value_changed (GtkAdjustment *adjustment,
 
505
                                  GvcChannelBar *bar)
 
506
{
 
507
        gdouble value;
 
508
 
 
509
        if (bar->priv->click_lock != FALSE) {
 
510
                return;
 
511
        }
 
512
 
 
513
        value = gtk_adjustment_get_value (bar->priv->zero_adjustment);
 
514
        gtk_adjustment_set_value (bar->priv->adjustment, value);
 
515
 
 
516
 
 
517
        if (bar->priv->show_mute == FALSE) {
 
518
                /* this means the adjustment moved away from zero and
 
519
                 * therefore we should unmute and set the volume. */
 
520
                gvc_channel_bar_set_is_muted (bar, value > 0.0);
 
521
        }
 
522
}
 
523
 
 
524
static void
 
525
update_mute_switch (GvcChannelBar *bar)
 
526
{
 
527
        if (bar->priv->show_mute) {
 
528
                gtk_widget_show (bar->priv->mute_switch);
 
529
                gtk_switch_set_active (GTK_SWITCH (bar->priv->mute_switch),
 
530
                                       !bar->priv->is_muted);
 
531
        } else {
 
532
                gtk_widget_hide (bar->priv->mute_switch);
 
533
        }
 
534
 
 
535
        if (bar->priv->is_muted) {
 
536
                /* If we aren't showing the mute button then
 
537
                 * move slider to the zero.  But we don't want to
 
538
                 * change the adjustment.  */
 
539
                g_signal_handlers_block_by_func (bar->priv->zero_adjustment,
 
540
                                                 on_zero_adjustment_value_changed,
 
541
                                                 bar);
 
542
                gtk_adjustment_set_value (bar->priv->zero_adjustment, 0);
 
543
                g_signal_handlers_unblock_by_func (bar->priv->zero_adjustment,
 
544
                                                   on_zero_adjustment_value_changed,
 
545
                                                   bar);
 
546
                gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale),
 
547
                                          bar->priv->zero_adjustment);
 
548
        } else {
 
549
                /* no longer muted so restore the original adjustment
 
550
                 * and tell the front-end that the value changed */
 
551
                gtk_range_set_adjustment (GTK_RANGE (bar->priv->scale),
 
552
                                          bar->priv->adjustment);
 
553
                gtk_adjustment_value_changed (bar->priv->adjustment);
 
554
        }
 
555
}
 
556
 
 
557
void
 
558
gvc_channel_bar_set_is_muted (GvcChannelBar *bar,
 
559
                              gboolean       is_muted)
 
560
{
 
561
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
562
 
 
563
        if (is_muted != bar->priv->is_muted) {
 
564
                /* Update our internal state before telling the
 
565
                 * front-end about our changes */
 
566
                bar->priv->is_muted = is_muted;
 
567
                update_mute_switch (bar);
 
568
                g_object_notify (G_OBJECT (bar), "is-muted");
 
569
        }
 
570
}
 
571
 
 
572
gboolean
 
573
gvc_channel_bar_get_is_muted  (GvcChannelBar *bar)
 
574
{
 
575
        g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
 
576
        return bar->priv->is_muted;
 
577
}
 
578
 
 
579
void
 
580
gvc_channel_bar_set_show_mute (GvcChannelBar *bar,
 
581
                               gboolean       show_mute)
 
582
{
 
583
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
584
 
 
585
        if (show_mute != bar->priv->show_mute) {
 
586
                bar->priv->show_mute = show_mute;
 
587
                g_object_notify (G_OBJECT (bar), "show-mute");
 
588
                update_mute_switch (bar);
 
589
        }
 
590
}
 
591
 
 
592
gboolean
 
593
gvc_channel_bar_get_show_mute (GvcChannelBar *bar)
 
594
{
 
595
        g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
 
596
        return bar->priv->show_mute;
 
597
}
 
598
 
 
599
void
 
600
gvc_channel_bar_set_is_amplified (GvcChannelBar *bar, gboolean amplified)
 
601
{
 
602
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
603
 
 
604
        bar->priv->is_amplified = amplified;
 
605
        gtk_adjustment_set_upper (bar->priv->adjustment, ADJUSTMENT_MAX);
 
606
        gtk_adjustment_set_upper (bar->priv->zero_adjustment, ADJUSTMENT_MAX);
 
607
        gtk_scale_clear_marks (GTK_SCALE (bar->priv->scale));
 
608
 
 
609
        if (amplified) {
 
610
                char *str;
 
611
 
 
612
                if (bar->priv->base_volume == ADJUSTMENT_MAX_NORMAL) {
 
613
                        str = g_strdup_printf ("<small>%s</small>", C_("volume", "100%"));
 
614
                        gtk_scale_add_mark (GTK_SCALE (bar->priv->scale), ADJUSTMENT_MAX_NORMAL,
 
615
                                            GTK_POS_BOTTOM, str);
 
616
                } else {
 
617
                        str = g_strdup_printf ("<small>%s</small>", C_("volume", "Unamplified"));
 
618
                        gtk_scale_add_mark (GTK_SCALE (bar->priv->scale), bar->priv->base_volume,
 
619
                                            GTK_POS_BOTTOM, str);
 
620
                        /* Only show 100% if it's higher than the base volume */
 
621
                        if (bar->priv->base_volume < ADJUSTMENT_MAX_NORMAL) {
 
622
                                str = g_strdup_printf ("<small>%s</small>", C_("volume", "100%"));
 
623
                                gtk_scale_add_mark (GTK_SCALE (bar->priv->scale), ADJUSTMENT_MAX_NORMAL,
 
624
                                                    GTK_POS_BOTTOM, str);
 
625
                        }
 
626
                }
 
627
 
 
628
                g_free (str);
 
629
                gtk_alignment_set (GTK_ALIGNMENT (bar->priv->mute_box), 0.5, 0, 0, 0);
 
630
                gtk_misc_set_alignment (GTK_MISC (bar->priv->low_image), 0.5, 0.15);
 
631
                gtk_misc_set_alignment (GTK_MISC (bar->priv->high_image), 0.5, 0.15);
 
632
                gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0, 0);
 
633
        } else {
 
634
                gtk_alignment_set (GTK_ALIGNMENT (bar->priv->mute_box), 0.5, 0.5, 0, 0);
 
635
                gtk_misc_set_alignment (GTK_MISC (bar->priv->low_image), 0.5, 0.5);
 
636
                gtk_misc_set_alignment (GTK_MISC (bar->priv->high_image), 0.5, 0.5);
 
637
                gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0, 0.5);
 
638
        }
 
639
}
 
640
 
 
641
gboolean
 
642
gvc_channel_bar_get_ellipsize (GvcChannelBar *bar)
 
643
{
 
644
        g_return_val_if_fail (GVC_IS_CHANNEL_BAR (bar), FALSE);
 
645
 
 
646
        return gtk_label_get_ellipsize (GTK_LABEL (bar->priv->label)) != PANGO_ELLIPSIZE_NONE;
 
647
}
 
648
 
 
649
void
 
650
gvc_channel_bar_set_ellipsize (GvcChannelBar *bar,
 
651
                               gboolean       ellipsized)
 
652
{
 
653
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
654
 
 
655
        if (ellipsized)
 
656
                gtk_label_set_ellipsize (GTK_LABEL (bar->priv->label), PANGO_ELLIPSIZE_END);
 
657
        else
 
658
                gtk_label_set_ellipsize (GTK_LABEL (bar->priv->label), PANGO_ELLIPSIZE_NONE);
 
659
}
 
660
 
 
661
void
 
662
gvc_channel_bar_set_base_volume (GvcChannelBar *bar,
 
663
                                 pa_volume_t    base_volume)
 
664
{
 
665
        g_return_if_fail (GVC_IS_CHANNEL_BAR (bar));
 
666
 
 
667
        if (base_volume == 0) {
 
668
                bar->priv->base_volume = ADJUSTMENT_MAX_NORMAL;
 
669
                return;
 
670
        }
 
671
 
 
672
        /* Note that you need to call _is_amplified() afterwards to update the marks */
 
673
        bar->priv->base_volume = base_volume;
 
674
}
 
675
 
 
676
static void
 
677
gvc_channel_bar_set_property (GObject       *object,
 
678
                              guint          prop_id,
 
679
                              const GValue  *value,
 
680
                              GParamSpec    *pspec)
 
681
{
 
682
        GvcChannelBar *self = GVC_CHANNEL_BAR (object);
 
683
 
 
684
        switch (prop_id) {
 
685
        case PROP_ORIENTATION:
 
686
                gvc_channel_bar_set_orientation (self, g_value_get_enum (value));
 
687
                break;
 
688
        case PROP_IS_MUTED:
 
689
                gvc_channel_bar_set_is_muted (self, g_value_get_boolean (value));
 
690
                break;
 
691
        case PROP_SHOW_MUTE:
 
692
                gvc_channel_bar_set_show_mute (self, g_value_get_boolean (value));
 
693
                break;
 
694
        case PROP_NAME:
 
695
                gvc_channel_bar_set_name (self, g_value_get_string (value));
 
696
                break;
 
697
        case PROP_ICON_NAME:
 
698
                gvc_channel_bar_set_icon_name (self, g_value_get_string (value));
 
699
                break;
 
700
        case PROP_LOW_ICON_NAME:
 
701
                gvc_channel_bar_set_low_icon_name (self, g_value_get_string (value));
 
702
                break;
 
703
        case PROP_HIGH_ICON_NAME:
 
704
                gvc_channel_bar_set_high_icon_name (self, g_value_get_string (value));
 
705
                break;
 
706
        case PROP_ADJUSTMENT:
 
707
                gvc_channel_bar_set_adjustment (self, g_value_get_object (value));
 
708
                break;
 
709
        case PROP_IS_AMPLIFIED:
 
710
                gvc_channel_bar_set_is_amplified (self, g_value_get_boolean (value));
 
711
                break;
 
712
        case PROP_ELLIPSIZE:
 
713
                gvc_channel_bar_set_ellipsize (self, g_value_get_boolean (value));
 
714
                break;
 
715
        default:
 
716
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
717
                break;
 
718
        }
 
719
}
 
720
 
 
721
static void
 
722
gvc_channel_bar_get_property (GObject     *object,
 
723
                              guint        prop_id,
 
724
                              GValue      *value,
 
725
                              GParamSpec  *pspec)
 
726
{
 
727
        GvcChannelBar *self = GVC_CHANNEL_BAR (object);
 
728
        GvcChannelBarPrivate *priv = self->priv;
 
729
 
 
730
        switch (prop_id) {
 
731
        case PROP_ORIENTATION:
 
732
                g_value_set_enum (value, priv->orientation);
 
733
                break;
 
734
        case PROP_IS_MUTED:
 
735
                g_value_set_boolean (value, priv->is_muted);
 
736
                break;
 
737
        case PROP_SHOW_MUTE:
 
738
                g_value_set_boolean (value, priv->show_mute);
 
739
                break;
 
740
        case PROP_NAME:
 
741
                g_value_set_string (value, priv->name);
 
742
                break;
 
743
        case PROP_ICON_NAME:
 
744
                g_value_set_string (value, priv->icon_name);
 
745
                break;
 
746
        case PROP_LOW_ICON_NAME:
 
747
                g_value_set_string (value, priv->low_icon_name);
 
748
                break;
 
749
        case PROP_HIGH_ICON_NAME:
 
750
                g_value_set_string (value, priv->high_icon_name);
 
751
                break;
 
752
        case PROP_ADJUSTMENT:
 
753
                g_value_set_object (value, gvc_channel_bar_get_adjustment (self));
 
754
                break;
 
755
        case PROP_IS_AMPLIFIED:
 
756
                g_value_set_boolean (value, priv->is_amplified);
 
757
                break;
 
758
        case PROP_ELLIPSIZE:
 
759
                g_value_set_boolean (value, gvc_channel_bar_get_ellipsize (self));
 
760
                break;
 
761
        default:
 
762
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
763
                break;
 
764
        }
 
765
}
 
766
 
 
767
static GObject *
 
768
gvc_channel_bar_constructor (GType                  type,
 
769
                             guint                  n_construct_properties,
 
770
                             GObjectConstructParam *construct_params)
 
771
{
 
772
        GObject       *object;
 
773
        GvcChannelBar *self;
 
774
 
 
775
        object = G_OBJECT_CLASS (gvc_channel_bar_parent_class)->constructor (type, n_construct_properties, construct_params);
 
776
 
 
777
        self = GVC_CHANNEL_BAR (object);
 
778
 
 
779
        update_mute_switch (self);
 
780
 
 
781
        return object;
 
782
}
 
783
 
 
784
static void
 
785
gvc_channel_bar_class_init (GvcChannelBarClass *klass)
 
786
{
 
787
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
 
788
 
 
789
        object_class->constructor = gvc_channel_bar_constructor;
 
790
        object_class->finalize = gvc_channel_bar_finalize;
 
791
        object_class->set_property = gvc_channel_bar_set_property;
 
792
        object_class->get_property = gvc_channel_bar_get_property;
 
793
 
 
794
        g_object_class_install_property (object_class,
 
795
                                         PROP_ORIENTATION,
 
796
                                         g_param_spec_enum ("orientation",
 
797
                                                            "Orientation",
 
798
                                                            "The orientation of the scale",
 
799
                                                            GTK_TYPE_ORIENTATION,
 
800
                                                            GTK_ORIENTATION_VERTICAL,
 
801
                                                            G_PARAM_READWRITE));
 
802
        g_object_class_install_property (object_class,
 
803
                                         PROP_IS_MUTED,
 
804
                                         g_param_spec_boolean ("is-muted",
 
805
                                                               "is muted",
 
806
                                                               "Whether stream is muted",
 
807
                                                               FALSE,
 
808
                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
809
        g_object_class_install_property (object_class,
 
810
                                         PROP_SHOW_MUTE,
 
811
                                         g_param_spec_boolean ("show-mute",
 
812
                                                               "show mute",
 
813
                                                               "Whether stream is muted",
 
814
                                                               FALSE,
 
815
                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
816
 
 
817
        g_object_class_install_property (object_class,
 
818
                                         PROP_ADJUSTMENT,
 
819
                                         g_param_spec_object ("adjustment",
 
820
                                                              "Adjustment",
 
821
                                                              "The GtkAdjustment that contains the current value of this scale button object",
 
822
                                                              GTK_TYPE_ADJUSTMENT,
 
823
                                                              G_PARAM_READWRITE));
 
824
        g_object_class_install_property (object_class,
 
825
                                         PROP_NAME,
 
826
                                         g_param_spec_string ("name",
 
827
                                                              "Name",
 
828
                                                              "Name to display for this stream",
 
829
                                                              NULL,
 
830
                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
831
        g_object_class_install_property (object_class,
 
832
                                         PROP_ICON_NAME,
 
833
                                         g_param_spec_string ("icon-name",
 
834
                                                              "Icon Name",
 
835
                                                              "Name of icon to display for this stream",
 
836
                                                              NULL,
 
837
                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
838
        g_object_class_install_property (object_class,
 
839
                                         PROP_LOW_ICON_NAME,
 
840
                                         g_param_spec_string ("low-icon-name",
 
841
                                                              "Icon Name",
 
842
                                                              "Name of icon to display for this stream",
 
843
                                                              "audio-volume-low-symbolic",
 
844
                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
845
        g_object_class_install_property (object_class,
 
846
                                         PROP_HIGH_ICON_NAME,
 
847
                                         g_param_spec_string ("high-icon-name",
 
848
                                                              "Icon Name",
 
849
                                                              "Name of icon to display for this stream",
 
850
                                                              "audio-volume-high-symbolic",
 
851
                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
852
        g_object_class_install_property (object_class,
 
853
                                         PROP_IS_AMPLIFIED,
 
854
                                         g_param_spec_boolean ("is-amplified",
 
855
                                                               "Is amplified",
 
856
                                                               "Whether the stream is digitally amplified",
 
857
                                                               FALSE,
 
858
                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
859
        g_object_class_install_property (object_class,
 
860
                                         PROP_ELLIPSIZE,
 
861
                                         g_param_spec_boolean ("ellipsize",
 
862
                                                               "Label is ellipsized",
 
863
                                                               "Whether the label is ellipsized",
 
864
                                                               FALSE,
 
865
                                                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
 
866
        g_type_class_add_private (klass, sizeof (GvcChannelBarPrivate));
 
867
}
 
868
 
 
869
static void
 
870
on_mute_switch_toggled (GtkSwitch     *sw,
 
871
                        GParamSpec *pspec,
 
872
                        GvcChannelBar *bar)
 
873
{
 
874
        gboolean is_muted;
 
875
        is_muted = gtk_switch_get_active (sw);
 
876
        gvc_channel_bar_set_is_muted (bar, !is_muted);
 
877
}
 
878
 
 
879
static void
 
880
gvc_channel_bar_init (GvcChannelBar *bar)
 
881
{
 
882
        GtkWidget *frame;
 
883
 
 
884
        bar->priv = GVC_CHANNEL_BAR_GET_PRIVATE (bar);
 
885
 
 
886
        bar->priv->base_volume = ADJUSTMENT_MAX_NORMAL;
 
887
        bar->priv->low_icon_name = g_strdup ("audio-volume-low-symbolic");
 
888
        bar->priv->high_icon_name = g_strdup ("audio-volume-high-symbolic");
 
889
 
 
890
        bar->priv->orientation = GTK_ORIENTATION_VERTICAL;
 
891
        bar->priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
 
892
                                                                    0.0,
 
893
                                                                    ADJUSTMENT_MAX_NORMAL,
 
894
                                                                    ADJUSTMENT_MAX_NORMAL/100.0,
 
895
                                                                    ADJUSTMENT_MAX_NORMAL/10.0,
 
896
                                                                    0.0));
 
897
        g_object_ref_sink (bar->priv->adjustment);
 
898
 
 
899
        bar->priv->zero_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
 
900
                                                                         0.0,
 
901
                                                                         ADJUSTMENT_MAX_NORMAL,
 
902
                                                                         ADJUSTMENT_MAX_NORMAL/100.0,
 
903
                                                                         ADJUSTMENT_MAX_NORMAL/10.0,
 
904
                                                                         0.0));
 
905
        g_object_ref_sink (bar->priv->zero_adjustment);
 
906
 
 
907
        g_signal_connect (bar->priv->zero_adjustment,
 
908
                          "value-changed",
 
909
                          G_CALLBACK (on_zero_adjustment_value_changed),
 
910
                          bar);
 
911
 
 
912
        bar->priv->mute_switch = gtk_switch_new ();
 
913
        gtk_widget_set_no_show_all (bar->priv->mute_switch, TRUE);
 
914
        g_signal_connect (bar->priv->mute_switch,
 
915
                          "notify::active",
 
916
                          G_CALLBACK (on_mute_switch_toggled),
 
917
                          bar);
 
918
        bar->priv->mute_box = gtk_alignment_new (0.5, 0.5, 0, 0);
 
919
        gtk_container_add (GTK_CONTAINER (bar->priv->mute_box), bar->priv->mute_switch);
 
920
 
 
921
        bar->priv->low_image = gtk_image_new_from_icon_name ("audio-volume-low-symbolic",
 
922
                                                             GTK_ICON_SIZE_MENU);
 
923
        gtk_widget_set_no_show_all (bar->priv->low_image, TRUE);
 
924
        bar->priv->high_image = gtk_image_new_from_icon_name ("audio-volume-high-symbolic",
 
925
                                                              GTK_ICON_SIZE_MENU);
 
926
        gtk_widget_set_no_show_all (bar->priv->high_image, TRUE);
 
927
 
 
928
        bar->priv->image = gtk_image_new ();
 
929
        gtk_widget_set_no_show_all (bar->priv->image, TRUE);
 
930
 
 
931
        bar->priv->label = gtk_label_new (NULL);
 
932
        gtk_misc_set_alignment (GTK_MISC (bar->priv->label), 0.0, 0.5);
 
933
        gtk_widget_set_no_show_all (bar->priv->label, TRUE);
 
934
 
 
935
        /* frame */
 
936
        frame = gtk_frame_new (NULL);
 
937
        gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
 
938
        gtk_container_add (GTK_CONTAINER (bar), frame);
 
939
        gtk_widget_show_all (frame);
 
940
 
 
941
        /* box with scale */
 
942
        bar->priv->scale_box = _scale_box_new (bar);
 
943
 
 
944
        gtk_container_add (GTK_CONTAINER (frame), bar->priv->scale_box);
 
945
}
 
946
 
 
947
static void
 
948
gvc_channel_bar_finalize (GObject *object)
 
949
{
 
950
        GvcChannelBar *channel_bar;
 
951
 
 
952
        g_return_if_fail (object != NULL);
 
953
        g_return_if_fail (GVC_IS_CHANNEL_BAR (object));
 
954
 
 
955
        channel_bar = GVC_CHANNEL_BAR (object);
 
956
 
 
957
        g_return_if_fail (channel_bar->priv != NULL);
 
958
 
 
959
        g_free (channel_bar->priv->name);
 
960
        g_free (channel_bar->priv->icon_name);
 
961
        g_free (channel_bar->priv->low_icon_name);
 
962
        g_free (channel_bar->priv->high_icon_name);
 
963
 
 
964
        G_OBJECT_CLASS (gvc_channel_bar_parent_class)->finalize (object);
 
965
}
 
966
 
 
967
GtkWidget *
 
968
gvc_channel_bar_new (void)
 
969
{
 
970
        GObject *bar;
 
971
        bar = g_object_new (GVC_TYPE_CHANNEL_BAR,
 
972
                            NULL);
 
973
        return GTK_WIDGET (bar);
 
974
}