~ubuntu-branches/ubuntu/saucy/gnome-control-center/saucy-proposed

« back to all changes in this revision

Viewing changes to .pc/git_sound_sliders.patch/panels/sound/gvc-stream-status-icon.c

  • Committer: Package Import Robot
  • Author(s): Sebastien Bacher, Sebastien Bacher, Robert Ancell, Iain Lane, Edward Donovan, Rico Tzschichholz, Jeremy Bicha, David Henningsson
  • Date: 2012-11-21 19:32:45 UTC
  • mfrom: (1.1.63)
  • Revision ID: package-import@ubuntu.com-20121121193245-mj61nzz1z4fk3z25
Tags: 1:3.6.3-0ubuntu1
[ Sebastien Bacher ]
* New upstream version
* debian/control.in: recommends libcanberra-pulse (lp: #1004973)
* debian/patches/58_ubuntu_icon_views_redesign.patch:
  - drop most of the changes, keep the different grid size though
    to fit on screen with our extra icons
* debian/patches/91_dont_show_in_unity.patch:
  - dropped, show the upstream printer panel and the layout tab
* debian/patches/revert_git_keyboard_gsettings.patch,
  debian/patches/revert_git_stop_using_gconf.patch:
  - dropped the gconf->gsettings reverts

[ Robert Ancell ]
* New upstream release (LP: #1010317)
* debian/control:
  - Bump build-depends on libgnome-desktop-3-dev, libwacom-dev
  - Add build-depends on libclutter-1.0-dev, libclutter-gtk-1.0-dev,
    libpwquality-dev
  - Drop build-depends on libgnomekbd-dev
* debian/patches/60_ubuntu_nav_bar.patch:
  - Disabled for now, doesn't apply
* debian/patches/revert_ua_gsettings.patch:
  - We can use GSettings for universal access now
* debian/patches/00git_online_accounts_gtkgrid.patch:
* debian/patches/00git_online_accounts_layout.part:
* debian/patches/git_wacom_translations.patch:
  - Applied upstream

[ Iain Lane ]
* Add Build-Depends on libxkbfile-dev
* New upstream release.
* Refresh all patches to apply cleanly.

[ Edward Donovan ]
* debian/source_gnome-control-center.py: Fix for Python 3. (LP: #1013171)

[ Rico Tzschichholz ]
* debian/control.in:
  - Build-depend on gtk-doc-tools instead of docbook directly
  - Bump minimum glib-2.0, gnome-desktop3, gnome-settings-daemon
     and gsettings-desktop-schemas

[ Jeremy Bicha ]
* Dropped more patches applied in new version:
  - git_unmute_sound_event.patch
  - git_fix_big_editable_labels.patch
  - 96_sound_nua_panel.patch
* debian/patches/04_new_appearance_settings.patch:
  - Dropped, this is now packaged separately as gnome-control-center-unity
* debian/patches/10_keyboard_layout_on_unity.patch:
  - Don't change the keyboard panel name when not running Unity
* debian/patches/52_ubuntu_language_list_mods.patch:
  - Don't disable adding current language to the list. While this
    fix shows the current language twice, at least it avoids the
    "Ubuntu suddenly in Chinese" bug (LP: #1035219)
* debian/patches/53_use_ubuntu_help.patch:
  - Only show Ubuntu help when running Unity
* debian/patches/58_hide_gdm_notifications.patch:
  - Hide "Show notifications when locked" settings when running Unity
    since it's a GNOME Shell-specific feature
* debian/patches/63_normal_scrollbar_in_a11y.patch:
  - Drop, overlay-scrollbars should handle this instead
* debian/patches/91_dont_show_in_unity.patch:
  - Hide Printers & Region panels in Unity until we're ready to switch
    to them.
* debian/patches/fix-crash-on-user-panel.patch:
  - Dropped, GNOME says it's obsolete
* debian/rules:
  - Build with -z,defs again
  - Explicitly disable ibus support since ibus 1.4 isn't supported in
    this version
* debian/control.in:
  - Drop ubuntu-docs and gnome-user-guide from recommends to suggests
  - Don't recommend indicators; let's leave that to Unity

[ David Henningsson ]
* sound_nua_panel.patch: Rebase to gnome 3.6 

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
 
#include <math.h>
27
 
 
28
 
#include <glib.h>
29
 
#include <glib/gi18n.h>
30
 
#include <gdk/gdkkeysyms.h>
31
 
#include <gtk/gtk.h>
32
 
#include <pulse/pulseaudio.h>
33
 
 
34
 
#include "gvc-mixer-stream.h"
35
 
#include "gvc-channel-bar.h"
36
 
#include "gvc-stream-status-icon.h"
37
 
 
38
 
#define GVC_STREAM_STATUS_ICON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_STREAM_STATUS_ICON, GvcStreamStatusIconPrivate))
39
 
 
40
 
struct GvcStreamStatusIconPrivate
41
 
{
42
 
        char          **icon_names;
43
 
        GvcMixerStream *mixer_stream;
44
 
        GtkWidget      *dock;
45
 
        GtkWidget      *bar;
46
 
        guint           current_icon;
47
 
        char           *display_name;
48
 
        gboolean        thaw;
49
 
};
50
 
 
51
 
enum
52
 
{
53
 
        PROP_0,
54
 
        PROP_DISPLAY_NAME,
55
 
        PROP_MIXER_STREAM,
56
 
        PROP_ICON_NAMES,
57
 
};
58
 
 
59
 
static void     gvc_stream_status_icon_class_init (GvcStreamStatusIconClass *klass);
60
 
static void     gvc_stream_status_icon_init       (GvcStreamStatusIcon      *stream_status_icon);
61
 
static void     gvc_stream_status_icon_finalize   (GObject                  *object);
62
 
 
63
 
G_DEFINE_TYPE (GvcStreamStatusIcon, gvc_stream_status_icon, GTK_TYPE_STATUS_ICON)
64
 
 
65
 
static void
66
 
on_adjustment_value_changed (GtkAdjustment *adjustment,
67
 
                             GvcStreamStatusIcon     *icon)
68
 
{
69
 
        gdouble volume;
70
 
 
71
 
        if (icon->priv->thaw)
72
 
                return;
73
 
 
74
 
        volume = gtk_adjustment_get_value (adjustment);
75
 
 
76
 
        /* Only push the volume if it's actually changed */
77
 
        if (gvc_mixer_stream_set_volume(icon->priv->mixer_stream,
78
 
                                    (pa_volume_t) round (volume)) != FALSE) {
79
 
                gvc_mixer_stream_push_volume(icon->priv->mixer_stream);
80
 
        }
81
 
}
82
 
 
83
 
static void
84
 
update_dock (GvcStreamStatusIcon *icon)
85
 
{
86
 
        GtkAdjustment *adj;
87
 
        gboolean       is_muted;
88
 
 
89
 
        g_return_if_fail (icon);
90
 
 
91
 
        adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (icon->priv->bar)));
92
 
 
93
 
        icon->priv->thaw = TRUE;
94
 
        gtk_adjustment_set_value (adj,
95
 
                                  gvc_mixer_stream_get_volume (icon->priv->mixer_stream));
96
 
        is_muted = gvc_mixer_stream_get_is_muted (icon->priv->mixer_stream);
97
 
        gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (icon->priv->bar), is_muted);
98
 
        icon->priv->thaw = FALSE;
99
 
}
100
 
 
101
 
static gboolean
102
 
popup_dock (GvcStreamStatusIcon *icon,
103
 
            guint                time)
104
 
{
105
 
        GdkRectangle   area;
106
 
        GtkOrientation orientation;
107
 
        GdkDisplay    *display;
108
 
        GdkScreen     *screen;
109
 
        gboolean       res;
110
 
        int            x;
111
 
        int            y;
112
 
        int            monitor_num;
113
 
        GdkRectangle   monitor;
114
 
        GtkRequisition dock_req;
115
 
 
116
 
        update_dock (icon);
117
 
 
118
 
        screen = gtk_status_icon_get_screen (GTK_STATUS_ICON (icon));
119
 
        res = gtk_status_icon_get_geometry (GTK_STATUS_ICON (icon),
120
 
                                            &screen,
121
 
                                            &area,
122
 
                                            &orientation);
123
 
        if (! res) {
124
 
                g_warning ("Unable to determine geometry of status icon");
125
 
                return FALSE;
126
 
        }
127
 
 
128
 
        /* position roughly */
129
 
        gtk_window_set_screen (GTK_WINDOW (icon->priv->dock), screen);
130
 
        gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (icon->priv->bar),
131
 
                                         1 - orientation);
132
 
 
133
 
        monitor_num = gdk_screen_get_monitor_at_point (screen, area.x, area.y);
134
 
        gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
135
 
 
136
 
        gtk_container_foreach (GTK_CONTAINER (icon->priv->dock),
137
 
                               (GtkCallback) gtk_widget_show_all, NULL);
138
 
        gtk_widget_get_preferred_size (icon->priv->dock, &dock_req, NULL);
139
 
 
140
 
        if (orientation == GTK_ORIENTATION_VERTICAL) {
141
 
                if (area.x + area.width + dock_req.width <= monitor.x + monitor.width) {
142
 
                        x = area.x + area.width;
143
 
                } else {
144
 
                        x = area.x - dock_req.width;
145
 
                }
146
 
                if (area.y + dock_req.height <= monitor.y + monitor.height) {
147
 
                        y = area.y;
148
 
                } else {
149
 
                        y = monitor.y + monitor.height - dock_req.height;
150
 
                }
151
 
        } else {
152
 
                if (area.y + area.height + dock_req.height <= monitor.y + monitor.height) {
153
 
                        y = area.y + area.height;
154
 
                } else {
155
 
                        y = area.y - dock_req.height;
156
 
                }
157
 
                if (area.x + dock_req.width <= monitor.x + monitor.width) {
158
 
                        x = area.x;
159
 
                } else {
160
 
                        x = monitor.x + monitor.width - dock_req.width;
161
 
                }
162
 
        }
163
 
 
164
 
        gtk_window_move (GTK_WINDOW (icon->priv->dock), x, y);
165
 
 
166
 
        /* FIXME: without this, the popup window appears as a square
167
 
         * after changing the orientation
168
 
         */
169
 
        gtk_window_resize (GTK_WINDOW (icon->priv->dock), 1, 1);
170
 
 
171
 
        gtk_widget_show_all (icon->priv->dock);
172
 
 
173
 
        /* grab focus */
174
 
        gtk_grab_add (icon->priv->dock);
175
 
 
176
 
        if (gdk_pointer_grab (gtk_widget_get_window (icon->priv->dock), TRUE,
177
 
                              GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
178
 
                              GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK, NULL, NULL,
179
 
                              time)
180
 
            != GDK_GRAB_SUCCESS) {
181
 
                gtk_grab_remove (icon->priv->dock);
182
 
                gtk_widget_hide (icon->priv->dock);
183
 
                return FALSE;
184
 
        }
185
 
 
186
 
        if (gdk_keyboard_grab (gtk_widget_get_window (icon->priv->dock), TRUE, time) != GDK_GRAB_SUCCESS) {
187
 
                display = gtk_widget_get_display (icon->priv->dock);
188
 
                gdk_display_pointer_ungrab (display, time);
189
 
                gtk_grab_remove (icon->priv->dock);
190
 
                gtk_widget_hide (icon->priv->dock);
191
 
                return FALSE;
192
 
        }
193
 
 
194
 
        gtk_widget_grab_focus (icon->priv->dock);
195
 
 
196
 
        return TRUE;
197
 
}
198
 
 
199
 
static void
200
 
on_status_icon_activate (GtkStatusIcon       *status_icon,
201
 
                         GvcStreamStatusIcon *icon)
202
 
{
203
 
        popup_dock (icon, GDK_CURRENT_TIME);
204
 
}
205
 
 
206
 
static void
207
 
on_menu_mute_toggled (GtkMenuItem         *item,
208
 
                      GvcStreamStatusIcon *icon)
209
 
{
210
 
        gboolean is_muted;
211
 
        is_muted = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item));
212
 
        gvc_channel_bar_set_is_muted (GVC_CHANNEL_BAR (icon->priv->bar), is_muted);
213
 
}
214
 
 
215
 
static void
216
 
on_menu_activate_open_volume_control (GtkMenuItem *item,
217
 
                                      GvcStreamStatusIcon   *icon)
218
 
{
219
 
        GAppInfo *app;
220
 
        GdkAppLaunchContext *context;
221
 
        GError *error;
222
 
 
223
 
        error = NULL;
224
 
        context = gdk_app_launch_context_new ();
225
 
        app = g_app_info_create_from_commandline ("gnome-control-center sound", "Sound preferences", 0, &error);
226
 
        if (app)
227
 
                g_app_info_launch (app, NULL, G_APP_LAUNCH_CONTEXT (context), &error);
228
 
 
229
 
        if (error != NULL) {
230
 
                GtkWidget *dialog;
231
 
 
232
 
                dialog = gtk_message_dialog_new (NULL,
233
 
                                                 0,
234
 
                                                 GTK_MESSAGE_ERROR,
235
 
                                                 GTK_BUTTONS_CLOSE,
236
 
                                                 _("Failed to start Sound Preferences: %s"),
237
 
                                                 error->message);
238
 
                g_signal_connect (dialog,
239
 
                                  "response",
240
 
                                  G_CALLBACK (gtk_widget_destroy),
241
 
                                  NULL);
242
 
                gtk_widget_show (dialog);
243
 
                g_error_free (error);
244
 
        }
245
 
 
246
 
        g_object_unref (context);
247
 
        g_object_unref (app);
248
 
}
249
 
 
250
 
static void
251
 
on_status_icon_popup_menu (GtkStatusIcon       *status_icon,
252
 
                           guint                button,
253
 
                           guint                activate_time,
254
 
                           GvcStreamStatusIcon *icon)
255
 
{
256
 
        GtkWidget *menu;
257
 
        GtkWidget *item;
258
 
        GtkWidget *image;
259
 
 
260
 
        menu = gtk_menu_new ();
261
 
 
262
 
        item = gtk_check_menu_item_new_with_mnemonic (_("_Mute"));
263
 
        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
264
 
                                        gvc_mixer_stream_get_is_muted (icon->priv->mixer_stream));
265
 
        g_signal_connect (item,
266
 
                          "toggled",
267
 
                          G_CALLBACK (on_menu_mute_toggled),
268
 
                          icon);
269
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
270
 
 
271
 
        item = gtk_image_menu_item_new_with_mnemonic (_("_Sound Preferences"));
272
 
        image = gtk_image_new_from_icon_name ("multimedia-volume-control",
273
 
                                              GTK_ICON_SIZE_MENU);
274
 
        gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
275
 
        g_signal_connect (item,
276
 
                          "activate",
277
 
                          G_CALLBACK (on_menu_activate_open_volume_control),
278
 
                          icon);
279
 
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
280
 
 
281
 
        gtk_widget_show_all (menu);
282
 
        gtk_menu_popup (GTK_MENU (menu),
283
 
                        NULL,
284
 
                        NULL,
285
 
                        gtk_status_icon_position_menu,
286
 
                        status_icon,
287
 
                        button,
288
 
                        activate_time);
289
 
}
290
 
 
291
 
static gboolean
292
 
on_status_icon_scroll_event (GtkStatusIcon       *status_icon,
293
 
                             GdkEventScroll      *event,
294
 
                             GvcStreamStatusIcon *icon)
295
 
{
296
 
        return gvc_channel_bar_scroll (GVC_CHANNEL_BAR (icon->priv->bar), event->direction);
297
 
}
298
 
 
299
 
static void
300
 
gvc_icon_release_grab (GvcStreamStatusIcon *icon,
301
 
                         GdkEventButton    *event)
302
 
{
303
 
        GdkDisplay     *display;
304
 
 
305
 
        /* ungrab focus */
306
 
        display = gtk_widget_get_display (GTK_WIDGET (icon->priv->dock));
307
 
        gdk_display_keyboard_ungrab (display, event->time);
308
 
        gdk_display_pointer_ungrab (display, event->time);
309
 
        gtk_grab_remove (icon->priv->dock);
310
 
 
311
 
        /* hide again */
312
 
        gtk_widget_hide (icon->priv->dock);
313
 
}
314
 
 
315
 
static gboolean
316
 
on_dock_button_press (GtkWidget      *widget,
317
 
                      GdkEventButton *event,
318
 
                      GvcStreamStatusIcon      *icon)
319
 
{
320
 
        if (event->type == GDK_BUTTON_PRESS) {
321
 
                gvc_icon_release_grab (icon, event);
322
 
                return TRUE;
323
 
        }
324
 
 
325
 
        return FALSE;
326
 
}
327
 
 
328
 
static void
329
 
popdown_dock (GvcStreamStatusIcon *icon)
330
 
{
331
 
        GdkDisplay *display;
332
 
 
333
 
        /* ungrab focus */
334
 
        display = gtk_widget_get_display (icon->priv->dock);
335
 
        gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
336
 
        gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
337
 
        gtk_grab_remove (icon->priv->dock);
338
 
 
339
 
        /* hide again */
340
 
        gtk_widget_hide (icon->priv->dock);
341
 
}
342
 
 
343
 
static gboolean
344
 
on_dock_key_release (GtkWidget           *widget,
345
 
                     GdkEventKey         *event,
346
 
                     GvcStreamStatusIcon *icon)
347
 
{
348
 
        if (event->keyval == GDK_KEY_Escape) {
349
 
                popdown_dock (icon);
350
 
                return TRUE;
351
 
        }
352
 
 
353
 
#if 0
354
 
        if (!gtk_bindings_activate_event (GTK_OBJECT (widget), event)) {
355
 
                /* The popup hasn't managed the event, pass onto the button */
356
 
                gtk_bindings_activate_event (GTK_OBJECT (user_data), event);
357
 
        }
358
 
#endif
359
 
        return TRUE;
360
 
}
361
 
 
362
 
static gboolean
363
 
on_dock_scroll_event (GtkWidget           *widget,
364
 
                      GdkEventScroll      *event,
365
 
                      GvcStreamStatusIcon *icon)
366
 
{
367
 
        /* Forward event to the status icon */
368
 
        on_status_icon_scroll_event (NULL, event, icon);
369
 
        return TRUE;
370
 
}
371
 
 
372
 
static void
373
 
update_icon (GvcStreamStatusIcon *icon)
374
 
{
375
 
        guint    volume;
376
 
        gboolean is_muted;
377
 
        guint    n;
378
 
        char    *markup;
379
 
        gboolean can_decibel;
380
 
        gdouble  db;
381
 
 
382
 
        if (icon->priv->mixer_stream == NULL) {
383
 
                return;
384
 
        }
385
 
 
386
 
        volume = gvc_mixer_stream_get_volume (icon->priv->mixer_stream);
387
 
        is_muted = gvc_mixer_stream_get_is_muted (icon->priv->mixer_stream);
388
 
        db = gvc_mixer_stream_get_decibel (icon->priv->mixer_stream);
389
 
        can_decibel = gvc_mixer_stream_get_can_decibel (icon->priv->mixer_stream);
390
 
 
391
 
        /* select image */
392
 
        if (volume == 0 || is_muted) {
393
 
                n = 0;
394
 
        } else {
395
 
                n = 3 * volume / PA_VOLUME_NORM + 1;
396
 
                if (n < 1) {
397
 
                        n = 1;
398
 
                } else if (n > 3) {
399
 
                        n = 3;
400
 
                }
401
 
        }
402
 
 
403
 
        /* apparently status icon will reset icon even if
404
 
         * if doesn't change */
405
 
        if (icon->priv->current_icon != n) {
406
 
                gtk_status_icon_set_from_icon_name (GTK_STATUS_ICON (icon),
407
 
                                                    icon->priv->icon_names [n]);
408
 
                icon->priv->current_icon = n;
409
 
        }
410
 
 
411
 
 
412
 
        if (is_muted) {
413
 
                markup = g_strdup_printf (
414
 
                                          "<b>%s: %s</b>\n<small>%s</small>",
415
 
                                          icon->priv->display_name,
416
 
                                          _("Muted"),
417
 
                                          gvc_mixer_stream_get_description (icon->priv->mixer_stream));
418
 
        } else if (can_decibel && (db > PA_DECIBEL_MININFTY)) {
419
 
                markup = g_strdup_printf (
420
 
                                          "<b>%s: %.0f%%</b>\n<small>%0.2f dB\n%s</small>",
421
 
                                          icon->priv->display_name,
422
 
                                          100 * (float)volume / PA_VOLUME_NORM,
423
 
                                          db,
424
 
                                          gvc_mixer_stream_get_description (icon->priv->mixer_stream));
425
 
        } else if (can_decibel) {
426
 
                markup = g_strdup_printf (
427
 
                                          "<b>%s: %.0f%%</b>\n<small>-&#8734; dB\n%s</small>",
428
 
                                          icon->priv->display_name,
429
 
                                          100 * (float)volume / PA_VOLUME_NORM,
430
 
                                          gvc_mixer_stream_get_description (icon->priv->mixer_stream));
431
 
        } else {
432
 
                markup = g_strdup_printf (
433
 
                                          "<b>%s: %.0f%%</b>\n<small>%s</small>",
434
 
                                          icon->priv->display_name,
435
 
                                          100 * (float)volume / PA_VOLUME_NORM,
436
 
                                          gvc_mixer_stream_get_description (icon->priv->mixer_stream));
437
 
        }
438
 
        gtk_status_icon_set_tooltip_markup (GTK_STATUS_ICON (icon), markup);
439
 
        g_free (markup);
440
 
}
441
 
 
442
 
void
443
 
gvc_stream_status_icon_set_icon_names (GvcStreamStatusIcon  *icon,
444
 
                                       const char          **names)
445
 
{
446
 
        g_return_if_fail (GVC_IS_STREAM_STATUS_ICON (icon));
447
 
 
448
 
        g_strfreev (icon->priv->icon_names);
449
 
        icon->priv->icon_names = g_strdupv ((char **)names);
450
 
        update_icon (icon);
451
 
        g_object_notify (G_OBJECT (icon), "icon-names");
452
 
}
453
 
 
454
 
static void
455
 
on_stream_volume_notify (GObject             *object,
456
 
                         GParamSpec          *pspec,
457
 
                         GvcStreamStatusIcon *icon)
458
 
{
459
 
        update_icon (icon);
460
 
        update_dock (icon);
461
 
}
462
 
 
463
 
static void
464
 
on_stream_is_muted_notify (GObject             *object,
465
 
                           GParamSpec          *pspec,
466
 
                           GvcStreamStatusIcon *icon)
467
 
{
468
 
        update_icon (icon);
469
 
        update_dock (icon);
470
 
}
471
 
 
472
 
void
473
 
gvc_stream_status_icon_set_display_name (GvcStreamStatusIcon *icon,
474
 
                                         const char          *name)
475
 
{
476
 
        g_return_if_fail (GVC_STREAM_STATUS_ICON (icon));
477
 
 
478
 
        g_free (icon->priv->display_name);
479
 
        icon->priv->display_name = g_strdup (name);
480
 
        update_icon (icon);
481
 
        g_object_notify (G_OBJECT (icon), "display-name");
482
 
}
483
 
 
484
 
void
485
 
gvc_stream_status_icon_set_mixer_stream (GvcStreamStatusIcon *icon,
486
 
                                         GvcMixerStream      *stream)
487
 
{
488
 
        g_return_if_fail (GVC_STREAM_STATUS_ICON (icon));
489
 
 
490
 
        if (stream != NULL) {
491
 
                g_object_ref (stream);
492
 
        }
493
 
 
494
 
        if (icon->priv->mixer_stream != NULL) {
495
 
                g_signal_handlers_disconnect_by_func (icon->priv->mixer_stream,
496
 
                                                      G_CALLBACK (on_stream_volume_notify),
497
 
                                                      icon);
498
 
                g_signal_handlers_disconnect_by_func (icon->priv->mixer_stream,
499
 
                                                      G_CALLBACK (on_stream_is_muted_notify),
500
 
                                                      icon);
501
 
                g_object_unref (icon->priv->mixer_stream);
502
 
                icon->priv->mixer_stream = NULL;
503
 
        }
504
 
 
505
 
        icon->priv->mixer_stream = stream;
506
 
 
507
 
        if (icon->priv->mixer_stream != NULL) {
508
 
                GtkAdjustment *adj;
509
 
 
510
 
                g_object_ref (icon->priv->mixer_stream);
511
 
 
512
 
                icon->priv->thaw = TRUE;
513
 
                adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (icon->priv->bar)));
514
 
                gtk_adjustment_set_value (adj,
515
 
                                          gvc_mixer_stream_get_volume (icon->priv->mixer_stream));
516
 
                icon->priv->thaw = FALSE;
517
 
 
518
 
                g_signal_connect (icon->priv->mixer_stream,
519
 
                                  "notify::volume",
520
 
                                  G_CALLBACK (on_stream_volume_notify),
521
 
                                  icon);
522
 
                g_signal_connect (icon->priv->mixer_stream,
523
 
                                  "notify::is-muted",
524
 
                                  G_CALLBACK (on_stream_is_muted_notify),
525
 
                                  icon);
526
 
        }
527
 
 
528
 
        update_icon (icon);
529
 
 
530
 
        g_object_notify (G_OBJECT (icon), "mixer-stream");
531
 
}
532
 
 
533
 
static void
534
 
gvc_stream_status_icon_set_property (GObject       *object,
535
 
                                     guint          prop_id,
536
 
                                     const GValue  *value,
537
 
                                     GParamSpec    *pspec)
538
 
{
539
 
        GvcStreamStatusIcon *self = GVC_STREAM_STATUS_ICON (object);
540
 
 
541
 
        switch (prop_id) {
542
 
        case PROP_MIXER_STREAM:
543
 
                gvc_stream_status_icon_set_mixer_stream (self, g_value_get_object (value));
544
 
                break;
545
 
        case PROP_DISPLAY_NAME:
546
 
                gvc_stream_status_icon_set_display_name (self, g_value_get_string (value));
547
 
                break;
548
 
        case PROP_ICON_NAMES:
549
 
                gvc_stream_status_icon_set_icon_names (self, g_value_get_boxed (value));
550
 
                break;
551
 
        default:
552
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
553
 
                break;
554
 
        }
555
 
}
556
 
 
557
 
static void
558
 
gvc_stream_status_icon_get_property (GObject     *object,
559
 
                                     guint        prop_id,
560
 
                                     GValue      *value,
561
 
                                     GParamSpec  *pspec)
562
 
{
563
 
        GvcStreamStatusIcon *self = GVC_STREAM_STATUS_ICON (object);
564
 
        GvcStreamStatusIconPrivate *priv = self->priv;
565
 
 
566
 
        switch (prop_id) {
567
 
        case PROP_MIXER_STREAM:
568
 
                g_value_set_object (value, priv->mixer_stream);
569
 
                break;
570
 
        case PROP_DISPLAY_NAME:
571
 
                g_value_set_string (value, priv->display_name);
572
 
                break;
573
 
        case PROP_ICON_NAMES:
574
 
                g_value_set_boxed (value, priv->icon_names);
575
 
                break;
576
 
        default:
577
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
578
 
                break;
579
 
        }
580
 
}
581
 
 
582
 
static void
583
 
on_bar_is_muted_notify (GObject             *object,
584
 
                        GParamSpec          *pspec,
585
 
                        GvcStreamStatusIcon *icon)
586
 
{
587
 
        gboolean is_muted;
588
 
 
589
 
        is_muted = gvc_channel_bar_get_is_muted (GVC_CHANNEL_BAR (object));
590
 
 
591
 
        if (gvc_mixer_stream_get_is_muted (icon->priv->mixer_stream) != is_muted) {
592
 
                /* Update the stream before pushing the change */
593
 
                gvc_mixer_stream_set_is_muted (icon->priv->mixer_stream, is_muted);
594
 
                gvc_mixer_stream_change_is_muted (icon->priv->mixer_stream,
595
 
                                                  is_muted);
596
 
        }
597
 
}
598
 
 
599
 
static GObject *
600
 
gvc_stream_status_icon_constructor (GType                  type,
601
 
                                    guint                  n_construct_properties,
602
 
                                    GObjectConstructParam *construct_params)
603
 
{
604
 
        GObject             *object;
605
 
        GvcStreamStatusIcon *icon;
606
 
        GtkWidget           *frame;
607
 
        GtkWidget           *box;
608
 
        GtkAdjustment       *adj;
609
 
 
610
 
        object = G_OBJECT_CLASS (gvc_stream_status_icon_parent_class)->constructor (type, n_construct_properties, construct_params);
611
 
 
612
 
        icon = GVC_STREAM_STATUS_ICON (object);
613
 
 
614
 
        gtk_status_icon_set_from_icon_name (GTK_STATUS_ICON (icon),
615
 
                                            icon->priv->icon_names[0]);
616
 
 
617
 
        /* window */
618
 
        icon->priv->dock = gtk_window_new (GTK_WINDOW_POPUP);
619
 
        gtk_widget_set_name (icon->priv->dock, "gvc-stream-status-icon-popup-window");
620
 
        g_signal_connect (icon->priv->dock,
621
 
                          "button-press-event",
622
 
                          G_CALLBACK (on_dock_button_press),
623
 
                          icon);
624
 
        g_signal_connect (icon->priv->dock,
625
 
                          "key-release-event",
626
 
                          G_CALLBACK (on_dock_key_release),
627
 
                          icon);
628
 
        g_signal_connect (icon->priv->dock,
629
 
                          "scroll-event",
630
 
                          G_CALLBACK (on_dock_scroll_event),
631
 
                          icon);
632
 
 
633
 
        gtk_window_set_decorated (GTK_WINDOW (icon->priv->dock), FALSE);
634
 
 
635
 
        frame = gtk_frame_new (NULL);
636
 
        gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
637
 
        gtk_container_add (GTK_CONTAINER (icon->priv->dock), frame);
638
 
 
639
 
        box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
640
 
        gtk_container_set_border_width (GTK_CONTAINER (box), 2);
641
 
        gtk_container_add (GTK_CONTAINER (frame), box);
642
 
 
643
 
        icon->priv->bar = gvc_channel_bar_new ();
644
 
        gvc_channel_bar_set_orientation (GVC_CHANNEL_BAR (icon->priv->bar),
645
 
                                         GTK_ORIENTATION_VERTICAL);
646
 
 
647
 
        gtk_box_pack_start (GTK_BOX (box), icon->priv->bar, TRUE, FALSE, 0);
648
 
        g_signal_connect (icon->priv->bar,
649
 
                          "notify::is-muted",
650
 
                          G_CALLBACK (on_bar_is_muted_notify),
651
 
                          icon);
652
 
 
653
 
        adj = GTK_ADJUSTMENT (gvc_channel_bar_get_adjustment (GVC_CHANNEL_BAR (icon->priv->bar)));
654
 
        g_signal_connect (adj,
655
 
                          "value-changed",
656
 
                          G_CALLBACK (on_adjustment_value_changed),
657
 
                          icon);
658
 
 
659
 
        return object;
660
 
}
661
 
 
662
 
static void
663
 
gvc_stream_status_icon_dispose (GObject *object)
664
 
{
665
 
        GvcStreamStatusIcon *icon = GVC_STREAM_STATUS_ICON (object);
666
 
 
667
 
        if (icon->priv->dock != NULL) {
668
 
                gtk_widget_destroy (icon->priv->dock);
669
 
                icon->priv->dock = NULL;
670
 
        }
671
 
 
672
 
        if (icon->priv->mixer_stream != NULL) {
673
 
                g_object_unref (icon->priv->mixer_stream);
674
 
                icon->priv->mixer_stream = NULL;
675
 
        }
676
 
 
677
 
        G_OBJECT_CLASS (gvc_stream_status_icon_parent_class)->dispose (object);
678
 
}
679
 
 
680
 
static void
681
 
gvc_stream_status_icon_class_init (GvcStreamStatusIconClass *klass)
682
 
{
683
 
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
684
 
 
685
 
        object_class->constructor = gvc_stream_status_icon_constructor;
686
 
        object_class->finalize = gvc_stream_status_icon_finalize;
687
 
        object_class->dispose = gvc_stream_status_icon_dispose;
688
 
        object_class->set_property = gvc_stream_status_icon_set_property;
689
 
        object_class->get_property = gvc_stream_status_icon_get_property;
690
 
 
691
 
        g_object_class_install_property (object_class,
692
 
                                         PROP_MIXER_STREAM,
693
 
                                         g_param_spec_object ("mixer-stream",
694
 
                                                              "mixer stream",
695
 
                                                              "mixer stream",
696
 
                                                              GVC_TYPE_MIXER_STREAM,
697
 
                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
698
 
        g_object_class_install_property (object_class,
699
 
                                         PROP_DISPLAY_NAME,
700
 
                                         g_param_spec_string ("display-name",
701
 
                                                              "Display Name",
702
 
                                                              "Name to display for this stream",
703
 
                                                              NULL,
704
 
                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
705
 
        g_object_class_install_property (object_class,
706
 
                                         PROP_ICON_NAMES,
707
 
                                         g_param_spec_boxed ("icon-names",
708
 
                                                             "Icon Names",
709
 
                                                             "Name of icon to display for this stream",
710
 
                                                              G_TYPE_STRV,
711
 
                                                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
712
 
 
713
 
        g_type_class_add_private (klass, sizeof (GvcStreamStatusIconPrivate));
714
 
}
715
 
 
716
 
static void
717
 
on_status_icon_visible_notify (GvcStreamStatusIcon *icon)
718
 
{
719
 
        gboolean visible;
720
 
 
721
 
        g_object_get (icon, "visible", &visible, NULL);
722
 
        if (! visible) {
723
 
                if (icon->priv->dock != NULL) {
724
 
                        gtk_widget_hide (icon->priv->dock);
725
 
                }
726
 
        }
727
 
}
728
 
 
729
 
static void
730
 
gvc_stream_status_icon_init (GvcStreamStatusIcon *icon)
731
 
{
732
 
        icon->priv = GVC_STREAM_STATUS_ICON_GET_PRIVATE (icon);
733
 
 
734
 
        g_signal_connect (icon,
735
 
                          "activate",
736
 
                          G_CALLBACK (on_status_icon_activate),
737
 
                          icon);
738
 
        g_signal_connect (icon,
739
 
                          "popup-menu",
740
 
                          G_CALLBACK (on_status_icon_popup_menu),
741
 
                          icon);
742
 
        g_signal_connect (icon,
743
 
                          "scroll-event",
744
 
                          G_CALLBACK (on_status_icon_scroll_event),
745
 
                          icon);
746
 
        g_signal_connect (icon,
747
 
                          "notify::visible",
748
 
                          G_CALLBACK (on_status_icon_visible_notify),
749
 
                          NULL);
750
 
 
751
 
        icon->priv->thaw = FALSE;
752
 
}
753
 
 
754
 
static void
755
 
gvc_stream_status_icon_finalize (GObject *object)
756
 
{
757
 
        GvcStreamStatusIcon *stream_status_icon;
758
 
 
759
 
        g_return_if_fail (object != NULL);
760
 
        g_return_if_fail (GVC_IS_STREAM_STATUS_ICON (object));
761
 
 
762
 
        stream_status_icon = GVC_STREAM_STATUS_ICON (object);
763
 
 
764
 
        g_return_if_fail (stream_status_icon->priv != NULL);
765
 
 
766
 
        g_strfreev (stream_status_icon->priv->icon_names);
767
 
 
768
 
        G_OBJECT_CLASS (gvc_stream_status_icon_parent_class)->finalize (object);
769
 
}
770
 
 
771
 
GvcStreamStatusIcon *
772
 
gvc_stream_status_icon_new (GvcMixerStream *stream,
773
 
                            const char    **icon_names)
774
 
{
775
 
        GObject *icon;
776
 
        icon = g_object_new (GVC_TYPE_STREAM_STATUS_ICON,
777
 
                             "mixer-stream", stream,
778
 
                             "icon-names", icon_names,
779
 
                             NULL);
780
 
        return GVC_STREAM_STATUS_ICON (icon);
781
 
}