~ctf/unity-settings-daemon/bug1389099_mic_volume_icons

« back to all changes in this revision

Viewing changes to plugins/media-keys/gsd-media-keys-manager.c

  • Committer: Package Import Robot
  • Author(s): Robert Ancell
  • Date: 2014-02-07 11:44:36 UTC
  • Revision ID: package-import@ubuntu.com-20140207114436-7t5u3yvwc4ul7w3e
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) 2001-2003 Bastien Nocera <hadess@hadess.net>
 
4
 * Copyright (C) 2006-2007 William Jon McCann <mccann@jhu.edu>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
19
 *
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
 
 
24
#include <sys/types.h>
 
25
#include <sys/wait.h>
 
26
#include <stdlib.h>
 
27
#include <stdio.h>
 
28
#include <unistd.h>
 
29
#include <string.h>
 
30
#include <errno.h>
 
31
#include <math.h>
 
32
 
 
33
#include <locale.h>
 
34
 
 
35
#include <glib.h>
 
36
#include <glib/gi18n.h>
 
37
#include <gio/gio.h>
 
38
#include <gdk/gdk.h>
 
39
#include <gdk/gdkx.h>
 
40
#include <gtk/gtk.h>
 
41
#include <gio/gdesktopappinfo.h>
 
42
#include <gio/gunixfdlist.h>
 
43
 
 
44
#ifdef HAVE_GUDEV
 
45
#include <gudev/gudev.h>
 
46
#endif
 
47
 
 
48
#include "gnome-settings-plugin.h"
 
49
#include "gnome-settings-session.h"
 
50
#include "gnome-settings-profile.h"
 
51
#include "gsd-marshal.h"
 
52
#include "gsd-media-keys-manager.h"
 
53
 
 
54
#include "shortcuts-list.h"
 
55
#include "shell-key-grabber.h"
 
56
#include "gsd-screenshot-utils.h"
 
57
#include "gsd-input-helper.h"
 
58
#include "gsd-enums.h"
 
59
 
 
60
#include <canberra.h>
 
61
#include <pulse/pulseaudio.h>
 
62
#include "gvc-mixer-control.h"
 
63
#include "gvc-mixer-sink.h"
 
64
 
 
65
#include <libnotify/notify.h>
 
66
 
 
67
#define GSD_MEDIA_KEYS_DBUS_PATH GSD_DBUS_PATH "/MediaKeys"
 
68
#define GSD_MEDIA_KEYS_DBUS_NAME GSD_DBUS_NAME ".MediaKeys"
 
69
 
 
70
#define GNOME_KEYRING_DBUS_NAME "org.gnome.keyring"
 
71
#define GNOME_KEYRING_DBUS_PATH "/org/gnome/keyring/daemon"
 
72
#define GNOME_KEYRING_DBUS_INTERFACE "org.gnome.keyring.Daemon"
 
73
 
 
74
#define GS_DBUS_NAME                            "org.gnome.ScreenSaver"
 
75
#define GS_DBUS_PATH                            "/org/gnome/ScreenSaver"
 
76
#define GS_DBUS_INTERFACE                       "org.gnome.ScreenSaver"
 
77
 
 
78
#define SHELL_DBUS_NAME "org.gnome.Shell"
 
79
#define SHELL_DBUS_PATH "/org/gnome/Shell"
 
80
 
 
81
#define PANEL_DBUS_NAME "org.gnome.Panel"
 
82
 
 
83
#define UNITY_DBUS_NAME "com.canonical.Unity"
 
84
 
 
85
#define CUSTOM_BINDING_SCHEMA SETTINGS_BINDING_DIR ".custom-keybinding"
 
86
 
 
87
#define SHELL_GRABBER_RETRY_INTERVAL 1
 
88
 
 
89
static const gchar introspection_xml[] =
 
90
"<node name='/org/gnome/SettingsDaemon/MediaKeys'>"
 
91
"  <interface name='org.gnome.SettingsDaemon.MediaKeys'>"
 
92
"    <annotation name='org.freedesktop.DBus.GLib.CSymbol' value='gsd_media_keys_manager'/>"
 
93
"    <method name='GrabMediaPlayerKeys'>"
 
94
"      <arg name='application' direction='in' type='s'/>"
 
95
"      <arg name='time' direction='in' type='u'/>"
 
96
"    </method>"
 
97
"    <method name='ReleaseMediaPlayerKeys'>"
 
98
"      <arg name='application' direction='in' type='s'/>"
 
99
"    </method>"
 
100
"    <signal name='MediaPlayerKeyPressed'>"
 
101
"      <arg name='application' type='s'/>"
 
102
"      <arg name='key' type='s'/>"
 
103
"    </signal>"
 
104
"  </interface>"
 
105
"</node>";
 
106
 
 
107
#define SETTINGS_INTERFACE_DIR "org.gnome.desktop.interface"
 
108
#define SETTINGS_POWER_DIR "org.gnome.settings-daemon.plugins.power"
 
109
#define SETTINGS_XSETTINGS_DIR "org.gnome.settings-daemon.plugins.xsettings"
 
110
#define SETTINGS_TOUCHPAD_DIR "org.gnome.settings-daemon.peripherals.touchpad"
 
111
#define TOUCHPAD_ENABLED_KEY "touchpad-enabled"
 
112
#define HIGH_CONTRAST "HighContrast"
 
113
 
 
114
#define VOLUME_STEP 6           /* percents for one volume button press */
 
115
#define MAX_VOLUME 65536.0
 
116
 
 
117
#define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.gnome.desktop.input-sources"
 
118
#define KEY_CURRENT_INPUT_SOURCE "current"
 
119
#define KEY_INPUT_SOURCES        "sources"
 
120
 
 
121
#define SYSTEMD_DBUS_NAME                       "org.freedesktop.login1"
 
122
#define SYSTEMD_DBUS_PATH                       "/org/freedesktop/login1"
 
123
#define SYSTEMD_DBUS_INTERFACE                  "org.freedesktop.login1.Manager"
 
124
 
 
125
#define GSD_MEDIA_KEYS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_MEDIA_KEYS_MANAGER, GsdMediaKeysManagerPrivate))
 
126
 
 
127
typedef struct {
 
128
        char   *application;
 
129
        char   *dbus_name;
 
130
        guint32 time;
 
131
        guint   watch_id;
 
132
} MediaPlayer;
 
133
 
 
134
typedef struct {
 
135
        MediaKeyType key_type;
 
136
        ShellKeyBindingMode modes;
 
137
        const char *settings_key;
 
138
        const char *hard_coded;
 
139
        char *custom_path;
 
140
        char *custom_command;
 
141
        Key *key;
 
142
        guint accel_id;
 
143
} MediaKey;
 
144
 
 
145
typedef struct {
 
146
        GsdMediaKeysManager *manager;
 
147
        MediaKey *key;
 
148
} GrabData;
 
149
 
 
150
struct GsdMediaKeysManagerPrivate
 
151
{
 
152
        /* Volume bits */
 
153
        GvcMixerControl *volume;
 
154
        GvcMixerStream  *sink;
 
155
        GvcMixerStream  *source;
 
156
        ca_context      *ca;
 
157
        GtkSettings     *gtksettings;
 
158
#ifdef HAVE_GUDEV
 
159
        GHashTable      *streams; /* key = X device ID, value = stream id */
 
160
        GUdevClient     *udev_client;
 
161
#endif /* HAVE_GUDEV */
 
162
 
 
163
        GSettings       *settings;
 
164
        GSettings       *input_settings;
 
165
        GHashTable      *custom_settings;
 
166
 
 
167
        GPtrArray       *keys;
 
168
 
 
169
        /* HighContrast theme settings */
 
170
        GSettings       *interface_settings;
 
171
        char            *icon_theme;
 
172
        char            *gtk_theme;
 
173
 
 
174
        /* Power stuff */
 
175
        GSettings       *power_settings;
 
176
        GDBusProxy      *power_proxy;
 
177
        GDBusProxy      *power_screen_proxy;
 
178
        GDBusProxy      *power_keyboard_proxy;
 
179
 
 
180
        /* Shell stuff */
 
181
        guint            name_owner_id;
 
182
        GDBusProxy      *shell_proxy;
 
183
        ShellKeyGrabber *key_grabber;
 
184
        GCancellable    *shell_cancellable;
 
185
        GCancellable    *grab_cancellable;
 
186
 
 
187
        /* systemd stuff */
 
188
        GDBusProxy      *logind_proxy;
 
189
        gint             inhibit_keys_fd;
 
190
 
 
191
        /* Multihead stuff */
 
192
        GdkScreen *current_screen;
 
193
        GSList *screens;
 
194
 
 
195
        GdkScreen       *screen;
 
196
        int              opcode;
 
197
 
 
198
        GList           *media_players;
 
199
 
 
200
        GDBusNodeInfo   *introspection_data;
 
201
        GDBusConnection *connection;
 
202
        GCancellable    *bus_cancellable;
 
203
        GDBusProxy      *xrandr_proxy;
 
204
        GCancellable    *cancellable;
 
205
 
 
206
        guint            start_idle_id;
 
207
 
 
208
        /* Ubuntu notifications */
 
209
        NotifyNotification *volume_notification;
 
210
        NotifyNotification *brightness_notification;
 
211
        NotifyNotification *kb_backlight_notification;
 
212
 
 
213
        /* Legacy keygrabber stuff */
 
214
        guint           unity_name_owner_id;
 
215
        guint           panel_name_owner_id;
 
216
        guint           have_legacy_keygrabber;
 
217
 
 
218
};
 
219
 
 
220
static void     gsd_media_keys_manager_class_init  (GsdMediaKeysManagerClass *klass);
 
221
static void     gsd_media_keys_manager_init        (GsdMediaKeysManager      *media_keys_manager);
 
222
static void     gsd_media_keys_manager_finalize    (GObject                  *object);
 
223
static void     register_manager                   (GsdMediaKeysManager      *manager);
 
224
static void     custom_binding_changed             (GSettings           *settings,
 
225
                                                    const char          *settings_key,
 
226
                                                    GsdMediaKeysManager *manager);
 
227
static void     grab_media_keys                    (GsdMediaKeysManager *manager);
 
228
static void     grab_media_key                     (MediaKey            *key,
 
229
                                                    GsdMediaKeysManager *manager);
 
230
static void     ungrab_media_key                   (MediaKey            *key,
 
231
                                                    GsdMediaKeysManager *manager);
 
232
G_DEFINE_TYPE (GsdMediaKeysManager, gsd_media_keys_manager, G_TYPE_OBJECT)
 
233
 
 
234
static gpointer manager_object = NULL;
 
235
 
 
236
#define NOTIFY_CAP_PRIVATE_SYNCHRONOUS "x-canonical-private-synchronous"
 
237
#define NOTIFY_CAP_PRIVATE_ICON_ONLY "x-canonical-private-icon-only"
 
238
#define NOTIFY_HINT_TRUE "true"
 
239
 
 
240
typedef struct {
 
241
        GsdMediaKeysManager *manager;
 
242
        MediaKeyType type;
 
243
        guint old_percentage;
 
244
 
 
245
} GsdBrightnessActionData;
 
246
 
 
247
static const char *volume_icons[] = {
 
248
        "notification-audio-volume-muted",
 
249
        "notification-audio-volume-low",
 
250
        "notification-audio-volume-medium",
 
251
        "notification-audio-volume-high",
 
252
        NULL
 
253
};
 
254
 
 
255
static const char *brightness_icons[] = {
 
256
        "notification-display-brightness-off",
 
257
        "notification-display-brightness-low",
 
258
        "notification-display-brightness-medium",
 
259
        "notification-display-brightness-high",
 
260
        "notification-display-brightness-full",
 
261
        NULL
 
262
};
 
263
 
 
264
static const char *kb_backlight_icons[] = {
 
265
        "notification-keyboard-brightness-off",
 
266
        "notification-keyboard-brightness-low",
 
267
        "notification-keyboard-brightness-medium",
 
268
        "notification-keyboard-brightness-high",
 
269
        "notification-keyboard-brightness-full",
 
270
        NULL
 
271
};
 
272
 
 
273
static const char *
 
274
calculate_icon_name (gint value, const char **icon_names)
 
275
{
 
276
        value = CLAMP (value, 0, 100);
 
277
        gint length = g_strv_length (icon_names);
 
278
        gint s = (length - 1) * value / 100 + 1;
 
279
        s = CLAMP (s, 1, length - 1);
 
280
 
 
281
        return icon_names[s];
 
282
}
 
283
 
 
284
static gboolean
 
285
ubuntu_osd_notification_is_supported (void)
 
286
{
 
287
        GList *caps;
 
288
        gboolean has_cap;
 
289
 
 
290
        caps = notify_get_server_caps ();
 
291
        has_cap = (g_list_find_custom (caps, NOTIFY_CAP_PRIVATE_SYNCHRONOUS, (GCompareFunc) g_strcmp0) != NULL);
 
292
        g_list_foreach (caps, (GFunc) g_free, NULL);
 
293
        g_list_free (caps);
 
294
 
 
295
        return has_cap;
 
296
}
 
297
 
 
298
static gboolean
 
299
ubuntu_osd_notification_show_icon (const char *icon,
 
300
                                   const char *hint)
 
301
{
 
302
        if (!ubuntu_osd_notification_is_supported ())
 
303
                return FALSE;
 
304
 
 
305
        NotifyNotification *notification = notify_notification_new (" ", "", icon);
 
306
        notify_notification_set_hint_string (notification, NOTIFY_CAP_PRIVATE_SYNCHRONOUS, hint);
 
307
        notify_notification_set_hint_string (notification, NOTIFY_CAP_PRIVATE_ICON_ONLY, NOTIFY_HINT_TRUE);
 
308
 
 
309
        gboolean res = notify_notification_show (notification, NULL);
 
310
        g_object_unref (notification);
 
311
 
 
312
        return res;
 
313
}
 
314
 
 
315
static gboolean
 
316
ubuntu_osd_do_notification (NotifyNotification **notification,
 
317
                            const char *hint,
 
318
                            gint value,
 
319
                            gboolean muted,
 
320
                            const char **icon_names)
 
321
{
 
322
        if (!ubuntu_osd_notification_is_supported ())
 
323
                return FALSE;
 
324
 
 
325
        if (!*notification) {
 
326
                *notification = notify_notification_new (" ", "", NULL);
 
327
                notify_notification_set_hint_string (*notification, NOTIFY_CAP_PRIVATE_SYNCHRONOUS, hint);
 
328
        }
 
329
 
 
330
        value = CLAMP (value, -1, 101);
 
331
        const char *icon = muted ? icon_names[0] : calculate_icon_name (value, icon_names);
 
332
        notify_notification_set_hint_int32 (*notification, "value", value);
 
333
        notify_notification_update (*notification, " ", "", icon);
 
334
 
 
335
        return notify_notification_show (*notification, NULL);
 
336
}
 
337
 
 
338
static gboolean
 
339
ubuntu_osd_notification_show_volume (GsdMediaKeysManager *manager,
 
340
                                     gint value,
 
341
                                     gboolean muted)
 
342
{
 
343
        return ubuntu_osd_do_notification (&manager->priv->volume_notification,
 
344
                                           "volume", value, muted, volume_icons);
 
345
}
 
346
 
 
347
static gboolean
 
348
ubuntu_osd_notification_show_brightness (GsdMediaKeysManager *manager,
 
349
                                         gint value)
 
350
{
 
351
        return ubuntu_osd_do_notification (&manager->priv->brightness_notification,
 
352
                                           "brightness", value, value <= 0, brightness_icons);
 
353
}
 
354
 
 
355
static gboolean
 
356
ubuntu_osd_notification_show_kb_backlight (GsdMediaKeysManager *manager,
 
357
                                           gint value)
 
358
{
 
359
        return ubuntu_osd_do_notification (&manager->priv->kb_backlight_notification,
 
360
                                           "keyboard", value, value <= 0, kb_backlight_icons);
 
361
}
 
362
 
 
363
static void
 
364
init_screens (GsdMediaKeysManager *manager)
 
365
{
 
366
        GdkDisplay *display;
 
367
        int i;
 
368
 
 
369
        display = gdk_display_get_default ();
 
370
        for (i = 0; i < gdk_display_get_n_screens (display); i++) {
 
371
                GdkScreen *screen;
 
372
 
 
373
                screen = gdk_display_get_screen (display, i);
 
374
                if (screen == NULL) {
 
375
                        continue;
 
376
                }
 
377
                manager->priv->screens = g_slist_append (manager->priv->screens, screen);
 
378
        }
 
379
 
 
380
        manager->priv->current_screen = manager->priv->screens->data;
 
381
}
 
382
 
 
383
static void
 
384
media_key_free (MediaKey *key)
 
385
{
 
386
        if (key == NULL)
 
387
                return;
 
388
        g_free (key->custom_path);
 
389
        g_free (key->custom_command);
 
390
        if (key->key)
 
391
                free_key (key->key);
 
392
        g_free (key);
 
393
}
 
394
 
 
395
static char *
 
396
get_term_command (GsdMediaKeysManager *manager)
 
397
{
 
398
        char *cmd_term, *cmd_args;;
 
399
        char *cmd = NULL;
 
400
        GSettings *settings;
 
401
 
 
402
        settings = g_settings_new ("org.gnome.desktop.default-applications.terminal");
 
403
        cmd_term = g_settings_get_string (settings, "exec");
 
404
        if (cmd_term[0] == '\0')
 
405
                cmd_term = g_strdup ("gnome-terminal");
 
406
 
 
407
        cmd_args = g_settings_get_string (settings, "exec-arg");
 
408
        if (strcmp (cmd_term, "") != 0) {
 
409
                cmd = g_strdup_printf ("%s %s -e", cmd_term, cmd_args);
 
410
        } else {
 
411
                cmd = g_strdup_printf ("%s -e", cmd_term);
 
412
        }
 
413
 
 
414
        g_free (cmd_args);
 
415
        g_free (cmd_term);
 
416
        g_object_unref (settings);
 
417
 
 
418
        return cmd;
 
419
}
 
420
 
 
421
static char **
 
422
get_keyring_env (GsdMediaKeysManager *manager)
 
423
{
 
424
        GError *error = NULL;
 
425
        GVariant *variant, *item;
 
426
        GVariantIter *iter;
 
427
        char **envp;
 
428
 
 
429
        variant = g_dbus_connection_call_sync (manager->priv->connection,
 
430
                                               GNOME_KEYRING_DBUS_NAME,
 
431
                                               GNOME_KEYRING_DBUS_PATH,
 
432
                                               GNOME_KEYRING_DBUS_INTERFACE,
 
433
                                               "GetEnvironment",
 
434
                                               NULL,
 
435
                                               NULL,
 
436
                                               G_DBUS_CALL_FLAGS_NONE,
 
437
                                               -1,
 
438
                                               NULL,
 
439
                                               &error);
 
440
        if (variant == NULL) {
 
441
                g_warning ("Failed to call GetEnvironment on keyring daemon: %s", error->message);
 
442
                g_error_free (error);
 
443
                return NULL;
 
444
        }
 
445
 
 
446
        envp = g_get_environ ();
 
447
        envp = g_environ_unsetenv (envp, "DESKTOP_AUTOSTART_ID");
 
448
 
 
449
        g_variant_get (variant, "(a{ss})", &iter);
 
450
 
 
451
        while ((item = g_variant_iter_next_value (iter))) {
 
452
                char *key;
 
453
                char *value;
 
454
 
 
455
                g_variant_get (item,
 
456
                               "{ss}",
 
457
                               &key,
 
458
                               &value);
 
459
 
 
460
                envp = g_environ_setenv (envp, key, value, TRUE);
 
461
 
 
462
                g_variant_unref (item);
 
463
                g_free (key);
 
464
                g_free (value);
 
465
        }
 
466
 
 
467
        g_variant_iter_free (iter);
 
468
        g_variant_unref (variant);
 
469
 
 
470
        return envp;
 
471
}
 
472
 
 
473
static void
 
474
execute (GsdMediaKeysManager *manager,
 
475
         char                *cmd,
 
476
         gboolean             need_term)
 
477
{
 
478
        gboolean retval;
 
479
        char   **argv;
 
480
        int      argc;
 
481
        char    *exec;
 
482
        char    *term = NULL;
 
483
        GError  *error = NULL;
 
484
 
 
485
        retval = FALSE;
 
486
 
 
487
        if (need_term)
 
488
                term = get_term_command (manager);
 
489
 
 
490
        if (term) {
 
491
                exec = g_strdup_printf ("%s %s", term, cmd);
 
492
                g_free (term);
 
493
        } else {
 
494
                exec = g_strdup (cmd);
 
495
        }
 
496
 
 
497
        if (g_shell_parse_argv (exec, &argc, &argv, NULL)) {
 
498
                char   **envp;
 
499
 
 
500
                envp = get_keyring_env (manager);
 
501
 
 
502
                retval = g_spawn_async (g_get_home_dir (),
 
503
                                        argv,
 
504
                                        envp,
 
505
                                        G_SPAWN_SEARCH_PATH,
 
506
                                        NULL,
 
507
                                        NULL,
 
508
                                        NULL,
 
509
                                        &error);
 
510
 
 
511
                g_strfreev (argv);
 
512
                g_strfreev (envp);
 
513
        }
 
514
 
 
515
        if (retval == FALSE) {
 
516
                g_warning ("Couldn't execute command: %s: %s", exec, error->message);
 
517
                g_error_free (error);
 
518
        }
 
519
        g_free (exec);
 
520
}
 
521
 
 
522
static void
 
523
print_key_parse_error (MediaKey *key,
 
524
                       const char *str)
 
525
{
 
526
    if (str == NULL || *str == '\0')
 
527
        return;
 
528
    if (key->settings_key != NULL)
 
529
        g_debug ("Unable to parse key '%s' for GSettings entry '%s'", str, key->settings_key);
 
530
    else
 
531
        g_debug ("Unable to parse hard-coded key '%s'", key->hard_coded);
 
532
}
 
533
 
 
534
static char *
 
535
get_key_string (GsdMediaKeysManager *manager,
 
536
                MediaKey            *key)
 
537
{
 
538
        if (key->settings_key == "switch-input-source" || key->settings_key == "switch-input-source-backward")
 
539
                return g_settings_get_strv (manager->priv->input_settings, key->settings_key)[0];
 
540
        else if (key->settings_key != NULL)
 
541
                return g_settings_get_string (manager->priv->settings, key->settings_key);
 
542
        else if (key->hard_coded != NULL)
 
543
                return g_strdup (key->hard_coded);
 
544
        else if (key->custom_path != NULL) {
 
545
                GSettings *settings;
 
546
 
 
547
                settings = g_hash_table_lookup (manager->priv->custom_settings,
 
548
                                                key->custom_path);
 
549
                return g_settings_get_string (settings, "binding");
 
550
        } else
 
551
                g_assert_not_reached ();
 
552
}
 
553
 
 
554
static void
 
555
ensure_cancellable (GCancellable **cancellable)
 
556
{
 
557
        if (*cancellable == NULL) {
 
558
                *cancellable = g_cancellable_new ();
 
559
                g_object_add_weak_pointer (G_OBJECT (*cancellable),
 
560
                                           (gpointer *)cancellable);
 
561
        } else {
 
562
                g_object_ref (*cancellable);
 
563
        }
 
564
}
 
565
 
 
566
static void
 
567
show_osd (GsdMediaKeysManager *manager,
 
568
          const char          *icon,
 
569
          const char          *label,
 
570
          int                  level)
 
571
{
 
572
        GVariantBuilder builder;
 
573
 
 
574
        if (manager->priv->shell_proxy == NULL)
 
575
                return;
 
576
 
 
577
        g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
 
578
        g_variant_builder_open (&builder, G_VARIANT_TYPE_VARDICT);
 
579
        if (icon)
 
580
                g_variant_builder_add (&builder, "{sv}",
 
581
                                       "icon", g_variant_new_string (icon));
 
582
        if (label)
 
583
                g_variant_builder_add (&builder, "{sv}",
 
584
                                       "label", g_variant_new_string (label));
 
585
        if (level >= 0)
 
586
                g_variant_builder_add (&builder, "{sv}",
 
587
                                       "level", g_variant_new_int32 (level));
 
588
        g_variant_builder_close (&builder);
 
589
 
 
590
        g_dbus_proxy_call (manager->priv->shell_proxy,
 
591
                           "ShowOSD",
 
592
                           g_variant_builder_end (&builder),
 
593
                           G_DBUS_CALL_FLAGS_NO_AUTO_START,
 
594
                           -1,
 
595
                           manager->priv->shell_cancellable,
 
596
                           NULL, NULL);
 
597
}
 
598
 
 
599
static const char *
 
600
get_icon_name_for_volume (gboolean is_mic,
 
601
                          gboolean muted,
 
602
                          int volume)
 
603
{
 
604
        static const char *icon_names[] = {
 
605
                "audio-volume-muted-symbolic",
 
606
                "audio-volume-low-symbolic",
 
607
                "audio-volume-medium-symbolic",
 
608
                "audio-volume-high-symbolic",
 
609
                NULL
 
610
        };
 
611
        static const char *mic_icon_names[] = {
 
612
                "microphone-sensitivity-muted-symbolic",
 
613
                "microphone-sensitivity-low-symbolic",
 
614
                "microphone-sensitivity-medium-symbolic",
 
615
                "microphone-sensitivity-high-symbolic",
 
616
                NULL
 
617
        };
 
618
        int n;
 
619
 
 
620
        if (muted) {
 
621
                n = 0;
 
622
        } else {
 
623
                /* select image */
 
624
                n = 3 * volume / 100 + 1;
 
625
                if (n < 1) {
 
626
                        n = 1;
 
627
                } else if (n > 3) {
 
628
                        n = 3;
 
629
                }
 
630
        }
 
631
 
 
632
        if (is_mic)
 
633
                return mic_icon_names[n];
 
634
        else
 
635
                return icon_names[n];
 
636
}
 
637
 
 
638
static gboolean
 
639
retry_grabs (gpointer data)
 
640
{
 
641
        GsdMediaKeysManager *manager = data;
 
642
 
 
643
        grab_media_keys (manager);
 
644
        return FALSE;
 
645
}
 
646
 
 
647
static void
 
648
grab_accelerators_complete (GObject      *object,
 
649
                            GAsyncResult *result,
 
650
                            gpointer      user_data)
 
651
{
 
652
        GVariant *actions;
 
653
        gboolean retry = FALSE;
 
654
        GError *error = NULL;
 
655
        GsdMediaKeysManager *manager = user_data;
 
656
 
 
657
        shell_key_grabber_call_grab_accelerators_finish (SHELL_KEY_GRABBER (object),
 
658
                                                         &actions, result, &error);
 
659
 
 
660
        if (error) {
 
661
                retry = (error->code == G_DBUS_ERROR_UNKNOWN_METHOD);
 
662
                if (!retry)
 
663
                        g_warning ("%d: %s", error->code, error->message);
 
664
                g_error_free (error);
 
665
        } else {
 
666
                int i;
 
667
                for (i = 0; i < manager->priv->keys->len; i++) {
 
668
                        MediaKey *key;
 
669
 
 
670
                        key = g_ptr_array_index (manager->priv->keys, i);
 
671
                        g_variant_get_child (actions, i, "u", &key->accel_id);
 
672
                }
 
673
        }
 
674
 
 
675
        if (retry)
 
676
                g_timeout_add_seconds (SHELL_GRABBER_RETRY_INTERVAL,
 
677
                                       retry_grabs, manager);
 
678
}
 
679
 
 
680
static void
 
681
grab_media_keys (GsdMediaKeysManager *manager)
 
682
{
 
683
        GVariantBuilder builder;
 
684
        int i;
 
685
 
 
686
        g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(su)"));
 
687
 
 
688
        for (i = 0; i < manager->priv->keys->len; i++) {
 
689
                MediaKey *key;
 
690
                char *tmp;
 
691
 
 
692
                key = g_ptr_array_index (manager->priv->keys, i);
 
693
                tmp = get_key_string (manager, key);
 
694
                g_variant_builder_add (&builder, "(su)", tmp, key->modes);
 
695
                g_free (tmp);
 
696
        }
 
697
 
 
698
        shell_key_grabber_call_grab_accelerators (manager->priv->key_grabber,
 
699
                                                  g_variant_builder_end (&builder),
 
700
                                                  manager->priv->grab_cancellable,
 
701
                                                  grab_accelerators_complete,
 
702
                                                  manager);
 
703
}
 
704
 
 
705
static void
 
706
grab_accelerator_complete (GObject      *object,
 
707
                           GAsyncResult *result,
 
708
                           gpointer      user_data)
 
709
{
 
710
        GrabData *data = user_data;
 
711
        MediaKey *key = data->key;
 
712
 
 
713
        shell_key_grabber_call_grab_accelerator_finish (SHELL_KEY_GRABBER (object),
 
714
                                                        &key->accel_id, result, NULL);
 
715
 
 
716
        g_slice_free (GrabData, data);
 
717
}
 
718
 
 
719
static void
 
720
grab_media_key (MediaKey            *key,
 
721
                GsdMediaKeysManager *manager)
 
722
{
 
723
        GrabData *data;
 
724
        char *tmp;
 
725
 
 
726
        ungrab_media_key (key, manager);
 
727
 
 
728
        tmp = get_key_string (manager, key);
 
729
 
 
730
        data = g_slice_new0 (GrabData);
 
731
        data->manager = manager;
 
732
        data->key = key;
 
733
 
 
734
        shell_key_grabber_call_grab_accelerator (manager->priv->key_grabber,
 
735
                                                 tmp, key->modes,
 
736
                                                 manager->priv->grab_cancellable,
 
737
                                                 grab_accelerator_complete,
 
738
                                                 data);
 
739
 
 
740
        g_free (tmp);
 
741
}
 
742
 
 
743
static gboolean
 
744
grab_media_key_unity (MediaKey            *key,
 
745
                      GsdMediaKeysManager *manager)
 
746
{
 
747
    char *tmp;
 
748
    gboolean need_flush;
 
749
 
 
750
    need_flush = FALSE;
 
751
 
 
752
    if (key->key != NULL) {
 
753
        need_flush = TRUE;
 
754
        ungrab_key_unsafe (key->key, manager->priv->screens);
 
755
    }
 
756
 
 
757
    free_key (key->key);
 
758
    key->key = NULL;
 
759
 
 
760
    tmp = get_key_string (manager, key);
 
761
 
 
762
    key->key = parse_key (tmp);
 
763
    if (key->key == NULL) {
 
764
        print_key_parse_error (key, tmp);
 
765
        g_free (tmp);
 
766
        return need_flush;
 
767
    }
 
768
 
 
769
    grab_key_unsafe (key->key, GSD_KEYGRAB_NORMAL, manager->priv->screens);
 
770
 
 
771
    g_free (tmp);
 
772
 
 
773
    return TRUE;
 
774
}
 
775
 
 
776
static void
 
777
ungrab_accelerator_complete (GObject      *object,
 
778
                             GAsyncResult *result,
 
779
                             gpointer      user_data)
 
780
{
 
781
        GsdMediaKeysManager *manager = user_data;
 
782
        shell_key_grabber_call_ungrab_accelerator_finish (SHELL_KEY_GRABBER (object),
 
783
                                                          NULL, result, NULL);
 
784
}
 
785
 
 
786
static void
 
787
ungrab_media_key (MediaKey            *key,
 
788
                  GsdMediaKeysManager *manager)
 
789
{
 
790
        if (key->accel_id == 0)
 
791
                return;
 
792
 
 
793
        shell_key_grabber_call_ungrab_accelerator (manager->priv->key_grabber,
 
794
                                                   key->accel_id,
 
795
                                                   manager->priv->grab_cancellable,
 
796
                                                   ungrab_accelerator_complete,
 
797
                                                   manager);
 
798
        key->accel_id = 0;
 
799
}
 
800
 
 
801
static void
 
802
gsettings_changed_cb (GSettings           *settings,
 
803
                      const gchar         *settings_key,
 
804
                      GsdMediaKeysManager *manager)
 
805
{
 
806
        int      i;
 
807
        gboolean need_flush = FALSE;
 
808
 
 
809
        if (manager->priv->have_legacy_keygrabber)
 
810
                need_flush = TRUE;
 
811
        /* Give up if we don't have proxy to the shell */
 
812
        else if (!manager->priv->key_grabber)
 
813
                return;
 
814
 
 
815
        /* handled in gsettings_custom_changed_cb() */
 
816
        if (g_str_equal (settings_key, "custom-keybindings"))
 
817
                return;
 
818
 
 
819
        if (manager->priv->have_legacy_keygrabber)
 
820
                gdk_error_trap_push ();
 
821
 
 
822
        /* Find the key that was modified */
 
823
        for (i = 0; i < manager->priv->keys->len; i++) {
 
824
                MediaKey *key;
 
825
 
 
826
                key = g_ptr_array_index (manager->priv->keys, i);
 
827
 
 
828
                /* Skip over hard-coded and GConf keys */
 
829
                if (key->settings_key == NULL)
 
830
                        continue;
 
831
                if (strcmp (settings_key, key->settings_key) == 0) {
 
832
                        if (!manager->priv->have_legacy_keygrabber)
 
833
                            grab_media_key (key, manager);
 
834
                        else {
 
835
                            if (grab_media_key_unity (key, manager))
 
836
                                need_flush = TRUE;
 
837
                        }
 
838
                        break;
 
839
                }
 
840
        }
 
841
    if (manager->priv->have_legacy_keygrabber) {
 
842
        if (need_flush)
 
843
            gdk_flush ();
 
844
        if (gdk_error_trap_pop ())
 
845
            g_warning ("Grab failed for some keys, another application may already have access the them.");
 
846
    }
 
847
}
 
848
 
 
849
static MediaKey *
 
850
media_key_new_for_path (GsdMediaKeysManager *manager,
 
851
                        char                *path)
 
852
{
 
853
        GSettings *settings;
 
854
        char *command, *binding;
 
855
        MediaKey *key;
 
856
 
 
857
        g_debug ("media_key_new_for_path: %s", path);
 
858
 
 
859
        settings = g_hash_table_lookup (manager->priv->custom_settings, path);
 
860
        if (settings == NULL) {
 
861
                settings = g_settings_new_with_path (CUSTOM_BINDING_SCHEMA, path);
 
862
 
 
863
                g_signal_connect (settings, "changed",
 
864
                                  G_CALLBACK (custom_binding_changed), manager);
 
865
                g_hash_table_insert (manager->priv->custom_settings,
 
866
                                     g_strdup (path), settings);
 
867
        }
 
868
 
 
869
        command = g_settings_get_string (settings, "command");
 
870
        binding = g_settings_get_string (settings, "binding");
 
871
 
 
872
        if (*command == '\0' && *binding == '\0') {
 
873
                g_debug ("Key binding (%s) is incomplete", path);
 
874
                g_free (command);
 
875
                g_free (binding);
 
876
                return NULL;
 
877
        }
 
878
        g_free (binding);
 
879
 
 
880
        key = g_new0 (MediaKey, 1);
 
881
        key->key_type = CUSTOM_KEY;
 
882
        key->modes = GSD_KEYBINDING_MODE_LAUNCHER;
 
883
        key->custom_path = g_strdup (path);
 
884
        key->custom_command = command;
 
885
 
 
886
        return key;
 
887
}
 
888
 
 
889
static void
 
890
update_custom_binding (GsdMediaKeysManager *manager,
 
891
                       char                *path)
 
892
{
 
893
        MediaKey *key;
 
894
        int i;
 
895
 
 
896
        /* Remove the existing key */
 
897
        for (i = 0; i < manager->priv->keys->len; i++) {
 
898
                key = g_ptr_array_index (manager->priv->keys, i);
 
899
 
 
900
                if (key->custom_path == NULL)
 
901
                        continue;
 
902
                if (strcmp (key->custom_path, path) == 0) {
 
903
                        g_debug ("Removing custom key binding %s", path);
 
904
                        ungrab_media_key (key, manager);
 
905
                        g_ptr_array_remove_index_fast (manager->priv->keys, i);
 
906
                        break;
 
907
                }
 
908
        }
 
909
 
 
910
        /* And create a new one! */
 
911
        key = media_key_new_for_path (manager, path);
 
912
        if (key) {
 
913
                g_debug ("Adding new custom key binding %s", path);
 
914
                g_ptr_array_add (manager->priv->keys, key);
 
915
 
 
916
                grab_media_key (key, manager);
 
917
        }
 
918
}
 
919
 
 
920
static void
 
921
custom_binding_changed (GSettings           *settings,
 
922
                        const char          *settings_key,
 
923
                        GsdMediaKeysManager *manager)
 
924
{
 
925
        char *path;
 
926
 
 
927
        if (strcmp (settings_key, "name") == 0)
 
928
                return; /* we don't care */
 
929
 
 
930
        g_object_get (settings, "path", &path, NULL);
 
931
        update_custom_binding (manager, path);
 
932
        g_free (path);
 
933
}
 
934
 
 
935
static void
 
936
gsettings_custom_changed_cb (GSettings           *settings,
 
937
                             const char          *settings_key,
 
938
                             GsdMediaKeysManager *manager)
 
939
{
 
940
        char **bindings;
 
941
        int i, j, n_bindings;
 
942
 
 
943
        bindings = g_settings_get_strv (settings, settings_key);
 
944
        n_bindings = g_strv_length (bindings);
 
945
 
 
946
        /* Handle additions */
 
947
        for (i = 0; i < n_bindings; i++) {
 
948
                if (g_hash_table_lookup (manager->priv->custom_settings,
 
949
                                         bindings[i]))
 
950
                        continue;
 
951
                update_custom_binding (manager, bindings[i]);
 
952
        }
 
953
 
 
954
        /* Handle removals */
 
955
        for (i = 0; i < manager->priv->keys->len; i++) {
 
956
                gboolean found = FALSE;
 
957
                MediaKey *key = g_ptr_array_index (manager->priv->keys, i);
 
958
                if (key->key_type != CUSTOM_KEY)
 
959
                        continue;
 
960
 
 
961
                for (j = 0; j < n_bindings && !found; j++)
 
962
                        found = strcmp (bindings[j], key->custom_path) == 0;
 
963
 
 
964
                if (found)
 
965
                        continue;
 
966
 
 
967
                if (manager->priv->have_legacy_keygrabber && key->key) {
 
968
                        gdk_error_trap_push ();
 
969
 
 
970
                        ungrab_key_unsafe (key->key,
 
971
                                           manager->priv->screens);
 
972
 
 
973
                        gdk_flush ();
 
974
                        if (gdk_error_trap_pop ())
 
975
                                g_warning ("Ungrab failed for custom key '%s'", key->custom_path);
 
976
                } else
 
977
                        ungrab_media_key (key, manager);
 
978
                g_hash_table_remove (manager->priv->custom_settings,
 
979
                                     key->custom_path);
 
980
                g_ptr_array_remove_index_fast (manager->priv->keys, i);
 
981
                --i; /* make up for the removed key */
 
982
        }
 
983
        g_strfreev (bindings);
 
984
}
 
985
 
 
986
static void
 
987
add_key (GsdMediaKeysManager *manager, guint i)
 
988
{
 
989
        MediaKey *key;
 
990
 
 
991
        key = g_new0 (MediaKey, 1);
 
992
        key->key_type = media_keys[i].key_type;
 
993
        key->settings_key = media_keys[i].settings_key;
 
994
        key->hard_coded = media_keys[i].hard_coded;
 
995
        key->modes = media_keys[i].modes;
 
996
 
 
997
        g_ptr_array_add (manager->priv->keys, key);
 
998
 
 
999
    if (manager->priv->have_legacy_keygrabber)
 
1000
        grab_media_key_unity (key, manager);
 
1001
}
 
1002
 
 
1003
static void
 
1004
init_kbd (GsdMediaKeysManager *manager)
 
1005
{
 
1006
        char **custom_paths;
 
1007
        int i;
 
1008
 
 
1009
        gnome_settings_profile_start (NULL);
 
1010
 
 
1011
        if (manager->priv->have_legacy_keygrabber)
 
1012
                gdk_error_trap_push ();
 
1013
 
 
1014
        /* Media keys
 
1015
         * Add hard-coded shortcuts first so that they can't be preempted */
 
1016
        for (i = 0; i < G_N_ELEMENTS (media_keys); i++) {
 
1017
                if (media_keys[i].hard_coded)
 
1018
                        add_key (manager, i);
 
1019
        }
 
1020
        for (i = 0; i < G_N_ELEMENTS (media_keys); i++) {
 
1021
                if (media_keys[i].hard_coded == NULL)
 
1022
                        add_key (manager, i);
 
1023
        }
 
1024
 
 
1025
        /* Custom shortcuts */
 
1026
        custom_paths = g_settings_get_strv (manager->priv->settings,
 
1027
                                            "custom-keybindings");
 
1028
 
 
1029
        for (i = 0; i < g_strv_length (custom_paths); i++) {
 
1030
                MediaKey *key;
 
1031
 
 
1032
                g_debug ("Setting up custom keybinding %s", custom_paths[i]);
 
1033
 
 
1034
                key = media_key_new_for_path (manager, custom_paths[i]);
 
1035
                if (!key) {
 
1036
                        continue;
 
1037
                }
 
1038
                g_ptr_array_add (manager->priv->keys, key);
 
1039
 
 
1040
                if (manager->priv->have_legacy_keygrabber)
 
1041
                        grab_media_key_unity (key, manager);
 
1042
        }
 
1043
        g_strfreev (custom_paths);
 
1044
 
 
1045
        if (!manager->priv->have_legacy_keygrabber)
 
1046
            grab_media_keys (manager);
 
1047
        else {
 
1048
            gdk_flush ();
 
1049
            if (gdk_error_trap_pop ())
 
1050
                g_warning ("Grab failed for some keys, another application may already have access the them.");
 
1051
        }
 
1052
 
 
1053
        gnome_settings_profile_end (NULL);
 
1054
}
 
1055
 
 
1056
static void
 
1057
launch_app (GAppInfo *app_info,
 
1058
            gint64    timestamp)
 
1059
{
 
1060
        GError *error = NULL;
 
1061
        GdkAppLaunchContext *launch_context;
 
1062
 
 
1063
        /* setup the launch context so the startup notification is correct */
 
1064
        launch_context = gdk_display_get_app_launch_context (gdk_display_get_default ());
 
1065
        gdk_app_launch_context_set_timestamp (launch_context, timestamp);
 
1066
 
 
1067
        if (!g_app_info_launch (app_info, NULL, G_APP_LAUNCH_CONTEXT (launch_context), &error)) {
 
1068
                g_warning ("Could not launch '%s': %s",
 
1069
                           g_app_info_get_commandline (app_info),
 
1070
                           error->message);
 
1071
                g_error_free (error);
 
1072
        }
 
1073
        g_object_unref (launch_context);
 
1074
}
 
1075
 
 
1076
static void
 
1077
do_url_action (GsdMediaKeysManager *manager,
 
1078
               const char          *scheme,
 
1079
               gint64               timestamp)
 
1080
{
 
1081
        GAppInfo *app_info;
 
1082
 
 
1083
        app_info = g_app_info_get_default_for_uri_scheme (scheme);
 
1084
        if (app_info != NULL) {
 
1085
                launch_app (app_info, timestamp);
 
1086
                g_object_unref (app_info);
 
1087
        } else {
 
1088
                g_warning ("Could not find default application for '%s' scheme", scheme);
 
1089
        }
 
1090
}
 
1091
 
 
1092
static void
 
1093
do_media_action (GsdMediaKeysManager *manager,
 
1094
                 gint64               timestamp)
 
1095
{
 
1096
        GAppInfo *app_info;
 
1097
 
 
1098
        app_info = g_app_info_get_default_for_type ("audio/x-vorbis+ogg", FALSE);
 
1099
        if (app_info != NULL) {
 
1100
                launch_app (app_info, timestamp);
 
1101
                g_object_unref (app_info);
 
1102
        } else {
 
1103
                g_warning ("Could not find default application for '%s' mime-type", "audio/x-vorbis+ogg");
 
1104
        }
 
1105
}
 
1106
 
 
1107
static void
 
1108
do_terminal_action (GsdMediaKeysManager *manager)
 
1109
{
 
1110
        GSettings *settings;
 
1111
        char *term;
 
1112
 
 
1113
        settings = g_settings_new ("org.gnome.desktop.default-applications.terminal");
 
1114
        term = g_settings_get_string (settings, "exec");
 
1115
 
 
1116
        if (term)
 
1117
        execute (manager, term, FALSE);
 
1118
 
 
1119
        g_free (term);
 
1120
        g_object_unref (settings);
 
1121
}
 
1122
 
 
1123
static void
 
1124
gnome_session_shutdown (GsdMediaKeysManager *manager)
 
1125
{
 
1126
        GError *error = NULL;
 
1127
        GVariant *variant;
 
1128
        GDBusProxy *proxy;
 
1129
 
 
1130
        proxy = gnome_settings_session_get_session_proxy ();
 
1131
        variant = g_dbus_proxy_call_sync (proxy,
 
1132
                                          "Shutdown",
 
1133
                                          NULL,
 
1134
                                          G_DBUS_CALL_FLAGS_NONE,
 
1135
                                          -1,
 
1136
                                          NULL,
 
1137
                                          &error);
 
1138
        if (variant == NULL) {
 
1139
                g_warning ("Failed to call Shutdown on session manager: %s", error->message);
 
1140
                g_error_free (error);
 
1141
                return;
 
1142
        }
 
1143
        g_variant_unref (variant);
 
1144
        g_object_unref (proxy);
 
1145
}
 
1146
 
 
1147
static void
 
1148
do_logout_action (GsdMediaKeysManager *manager)
 
1149
{
 
1150
        execute (manager, "gnome-session-quit --logout", FALSE);
 
1151
}
 
1152
 
 
1153
static void
 
1154
do_eject_action_cb (GDrive              *drive,
 
1155
                    GAsyncResult        *res,
 
1156
                    GsdMediaKeysManager *manager)
 
1157
{
 
1158
        g_drive_eject_with_operation_finish (drive, res, NULL);
 
1159
}
 
1160
 
 
1161
#define NO_SCORE 0
 
1162
#define SCORE_CAN_EJECT 50
 
1163
#define SCORE_HAS_MEDIA 100
 
1164
static void
 
1165
do_eject_action (GsdMediaKeysManager *manager)
 
1166
{
 
1167
        GList *drives, *l;
 
1168
        GDrive *fav_drive;
 
1169
        guint score;
 
1170
        GVolumeMonitor *volume_monitor;
 
1171
 
 
1172
        volume_monitor = g_volume_monitor_get ();
 
1173
 
 
1174
 
 
1175
        /* Find the best drive to eject */
 
1176
        fav_drive = NULL;
 
1177
        score = NO_SCORE;
 
1178
        drives = g_volume_monitor_get_connected_drives (volume_monitor);
 
1179
        for (l = drives; l != NULL; l = l->next) {
 
1180
                GDrive *drive = l->data;
 
1181
 
 
1182
                if (g_drive_can_eject (drive) == FALSE)
 
1183
                        continue;
 
1184
                if (g_drive_is_media_removable (drive) == FALSE)
 
1185
                        continue;
 
1186
                if (score < SCORE_CAN_EJECT) {
 
1187
                        fav_drive = drive;
 
1188
                        score = SCORE_CAN_EJECT;
 
1189
                }
 
1190
                if (g_drive_has_media (drive) == FALSE)
 
1191
                        continue;
 
1192
                if (score < SCORE_HAS_MEDIA) {
 
1193
                        fav_drive = drive;
 
1194
                        score = SCORE_HAS_MEDIA;
 
1195
                        break;
 
1196
                }
 
1197
        }
 
1198
 
 
1199
        /* Show OSD */
 
1200
        if (!ubuntu_osd_notification_show_icon ("notification-device-eject", "Eject")) {
 
1201
                show_osd (manager, "media-eject-symbolic", NULL, -1);
 
1202
        }
 
1203
 
 
1204
        /* Clean up the drive selection and exit if no suitable
 
1205
         * drives are found */
 
1206
        if (fav_drive != NULL)
 
1207
                fav_drive = g_object_ref (fav_drive);
 
1208
 
 
1209
        g_list_foreach (drives, (GFunc) g_object_unref, NULL);
 
1210
        if (fav_drive == NULL)
 
1211
                return;
 
1212
 
 
1213
        /* Eject! */
 
1214
        g_drive_eject_with_operation (fav_drive, G_MOUNT_UNMOUNT_FORCE,
 
1215
                                      NULL, NULL,
 
1216
                                      (GAsyncReadyCallback) do_eject_action_cb,
 
1217
                                      manager);
 
1218
        g_object_unref (fav_drive);
 
1219
        g_object_unref (volume_monitor);
 
1220
}
 
1221
 
 
1222
static void
 
1223
do_home_key_action (GsdMediaKeysManager *manager,
 
1224
                    gint64               timestamp)
 
1225
{
 
1226
        GFile *file;
 
1227
        GError *error = NULL;
 
1228
        char *uri;
 
1229
 
 
1230
        file = g_file_new_for_path (g_get_home_dir ());
 
1231
        uri = g_file_get_uri (file);
 
1232
        g_object_unref (file);
 
1233
 
 
1234
        if (gtk_show_uri (NULL, uri, timestamp, &error) == FALSE) {
 
1235
                g_warning ("Failed to launch '%s': %s", uri, error->message);
 
1236
                g_error_free (error);
 
1237
        }
 
1238
        g_free (uri);
 
1239
}
 
1240
 
 
1241
static void
 
1242
do_search_action (GsdMediaKeysManager *manager,
 
1243
                  gint64               timestamp)
 
1244
{
 
1245
        g_dbus_proxy_call (manager->priv->shell_proxy,
 
1246
                           "FocusSearch",
 
1247
                           NULL,
 
1248
                           G_DBUS_CALL_FLAGS_NO_AUTO_START,
 
1249
                           -1,
 
1250
                           manager->priv->shell_cancellable,
 
1251
                           NULL, NULL);
 
1252
}
 
1253
 
 
1254
static void
 
1255
do_execute_desktop_or_desktop (GsdMediaKeysManager *manager,
 
1256
                               const char          *desktop,
 
1257
                               const char          *alt_desktop,
 
1258
                               gint64               timestamp)
 
1259
{
 
1260
        GDesktopAppInfo *app_info;
 
1261
 
 
1262
        app_info = g_desktop_app_info_new (desktop);
 
1263
        if (app_info == NULL)
 
1264
                app_info = g_desktop_app_info_new (alt_desktop);
 
1265
 
 
1266
        if (app_info != NULL) {
 
1267
                launch_app (G_APP_INFO (app_info), timestamp);
 
1268
                g_object_unref (app_info);
 
1269
                return;
 
1270
        }
 
1271
 
 
1272
        g_warning ("Could not find application '%s' or '%s'", desktop, alt_desktop);
 
1273
}
 
1274
 
 
1275
static void
 
1276
do_touchpad_osd_action (GsdMediaKeysManager *manager, gboolean state)
 
1277
{
 
1278
        if (!ubuntu_osd_notification_show_icon ((!state) ? "touchpad-disabled-symbolic" : "input-touchpad-symbolic", "Touchpad")) {
 
1279
                show_osd (manager, state ? "input-touchpad-symbolic"
 
1280
                                           : "touchpad-disabled-symbolic", NULL, -1);
 
1281
        }
 
1282
}
 
1283
 
 
1284
static void
 
1285
do_touchpad_action (GsdMediaKeysManager *manager)
 
1286
{
 
1287
        GSettings *settings;
 
1288
        gboolean state;
 
1289
 
 
1290
        if (touchpad_is_present () == FALSE) {
 
1291
                do_touchpad_osd_action (manager, FALSE);
 
1292
                return;
 
1293
        }
 
1294
 
 
1295
        settings = g_settings_new (SETTINGS_TOUCHPAD_DIR);
 
1296
        state = g_settings_get_boolean (settings, TOUCHPAD_ENABLED_KEY);
 
1297
 
 
1298
        do_touchpad_osd_action (manager, !state);
 
1299
 
 
1300
        g_settings_set_boolean (settings, TOUCHPAD_ENABLED_KEY, !state);
 
1301
        g_object_unref (settings);
 
1302
}
 
1303
 
 
1304
static void
 
1305
do_lock_screensaver (GsdMediaKeysManager *manager)
 
1306
{
 
1307
        GsdMediaKeysManagerPrivate *priv = manager->priv;
 
1308
 
 
1309
        if (priv->connection == NULL) {
 
1310
                g_warning ("No existing D-Bus connection trying to handle screensaver lock key");
 
1311
                return;
 
1312
        }
 
1313
        g_dbus_connection_call (manager->priv->connection,
 
1314
                                GS_DBUS_NAME,
 
1315
                                GS_DBUS_PATH,
 
1316
                                GS_DBUS_INTERFACE,
 
1317
                                "Lock",
 
1318
                                NULL, NULL,
 
1319
                                G_DBUS_CALL_FLAGS_NONE, -1,
 
1320
                                NULL, NULL, NULL);
 
1321
}
 
1322
 
 
1323
static void
 
1324
update_dialog (GsdMediaKeysManager *manager,
 
1325
               GvcMixerStream      *stream,
 
1326
               guint                vol,
 
1327
               gboolean             muted,
 
1328
               gboolean             sound_changed,
 
1329
               gboolean             quiet)
 
1330
{
 
1331
        GvcMixerUIDevice *device;
 
1332
        const GvcMixerStreamPort *port;
 
1333
        const char *icon;
 
1334
 
 
1335
        if (ubuntu_osd_notification_show_volume (manager, vol, muted))
 
1336
                goto done;
 
1337
 
 
1338
        vol = CLAMP (vol, 0, 100);
 
1339
 
 
1340
        icon = get_icon_name_for_volume (!GVC_IS_MIXER_SINK (stream), muted, vol);
 
1341
        port = gvc_mixer_stream_get_port (stream);
 
1342
        if (g_strcmp0 (gvc_mixer_stream_get_form_factor (stream), "internal") != 0 ||
 
1343
            (port != NULL &&
 
1344
             g_strcmp0 (port->port, "analog-output-speaker") != 0 &&
 
1345
             g_strcmp0 (port->port, "analog-output") != 0)) {
 
1346
                device = gvc_mixer_control_lookup_device_from_stream (manager->priv->volume, stream);
 
1347
                show_osd (manager, icon,
 
1348
                          gvc_mixer_ui_device_get_description (device), vol);
 
1349
        } else {
 
1350
                show_osd (manager, icon, NULL, vol);
 
1351
        }
 
1352
 
 
1353
done:
 
1354
        if (quiet == FALSE && sound_changed != FALSE && muted == FALSE) {
 
1355
                ca_context_change_device (manager->priv->ca,
 
1356
                                          gvc_mixer_stream_get_name (stream));
 
1357
                ca_context_play (manager->priv->ca, 1,
 
1358
                                        CA_PROP_EVENT_ID, "audio-volume-change",
 
1359
                                        CA_PROP_EVENT_DESCRIPTION, "volume changed through key press",
 
1360
                                        CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
 
1361
                                        NULL);
 
1362
        }
 
1363
}
 
1364
 
 
1365
#ifdef HAVE_GUDEV
 
1366
/* PulseAudio gives us /devices/... paths, when udev
 
1367
 * expects /sys/devices/... paths. */
 
1368
static GUdevDevice *
 
1369
get_udev_device_for_sysfs_path (GsdMediaKeysManager *manager,
 
1370
                                const char *sysfs_path)
 
1371
{
 
1372
        char *path;
 
1373
        GUdevDevice *dev;
 
1374
 
 
1375
        path = g_strdup_printf ("/sys%s", sysfs_path);
 
1376
        dev = g_udev_client_query_by_sysfs_path (manager->priv->udev_client, path);
 
1377
        g_free (path);
 
1378
 
 
1379
        return dev;
 
1380
}
 
1381
 
 
1382
static GvcMixerStream *
 
1383
get_stream_for_device_id (GsdMediaKeysManager *manager,
 
1384
                          gboolean             is_output,
 
1385
                          guint                deviceid)
 
1386
{
 
1387
        char *devnode;
 
1388
        gpointer id_ptr;
 
1389
        GvcMixerStream *res;
 
1390
        GUdevDevice *dev, *parent;
 
1391
        GSList *streams, *l;
 
1392
 
 
1393
        id_ptr = g_hash_table_lookup (manager->priv->streams, GUINT_TO_POINTER (deviceid));
 
1394
        if (id_ptr != NULL) {
 
1395
                if (GPOINTER_TO_UINT (id_ptr) == (guint) -1)
 
1396
                        return NULL;
 
1397
                else
 
1398
                        return gvc_mixer_control_lookup_stream_id (manager->priv->volume, GPOINTER_TO_UINT (id_ptr));
 
1399
        }
 
1400
 
 
1401
        devnode = xdevice_get_device_node (deviceid);
 
1402
        if (devnode == NULL) {
 
1403
                g_debug ("Could not find device node for XInput device %d", deviceid);
 
1404
                return NULL;
 
1405
        }
 
1406
 
 
1407
        dev = g_udev_client_query_by_device_file (manager->priv->udev_client, devnode);
 
1408
        if (dev == NULL) {
 
1409
                g_debug ("Could not find udev device for device path '%s'", devnode);
 
1410
                g_free (devnode);
 
1411
                return NULL;
 
1412
        }
 
1413
        g_free (devnode);
 
1414
 
 
1415
        if (g_strcmp0 (g_udev_device_get_property (dev, "ID_BUS"), "usb") != 0) {
 
1416
                g_debug ("Not handling XInput device %d, not USB", deviceid);
 
1417
                g_hash_table_insert (manager->priv->streams,
 
1418
                                     GUINT_TO_POINTER (deviceid),
 
1419
                                     GUINT_TO_POINTER ((guint) -1));
 
1420
                g_object_unref (dev);
 
1421
                return NULL;
 
1422
        }
 
1423
 
 
1424
        parent = g_udev_device_get_parent_with_subsystem (dev, "usb", "usb_device");
 
1425
        if (parent == NULL) {
 
1426
                g_warning ("No USB device parent for XInput device %d even though it's USB", deviceid);
 
1427
                g_object_unref (dev);
 
1428
                return NULL;
 
1429
        }
 
1430
 
 
1431
        res = NULL;
 
1432
        if (is_output)
 
1433
                streams = gvc_mixer_control_get_sinks (manager->priv->volume);
 
1434
        else
 
1435
                streams = gvc_mixer_control_get_sources (manager->priv->volume);
 
1436
        for (l = streams; l; l = l->next) {
 
1437
                GvcMixerStream *stream = l->data;
 
1438
                const char *sysfs_path;
 
1439
                GUdevDevice *stream_dev, *stream_parent;
 
1440
 
 
1441
                sysfs_path = gvc_mixer_stream_get_sysfs_path (stream);
 
1442
                stream_dev = get_udev_device_for_sysfs_path (manager, sysfs_path);
 
1443
                if (stream_dev == NULL)
 
1444
                        continue;
 
1445
                stream_parent = g_udev_device_get_parent_with_subsystem (stream_dev, "usb", "usb_device");
 
1446
                g_object_unref (stream_dev);
 
1447
                if (stream_parent == NULL)
 
1448
                        continue;
 
1449
 
 
1450
                if (g_strcmp0 (g_udev_device_get_sysfs_path (stream_parent),
 
1451
                               g_udev_device_get_sysfs_path (parent)) == 0) {
 
1452
                        res = stream;
 
1453
                }
 
1454
                g_object_unref (stream_parent);
 
1455
                if (res != NULL)
 
1456
                        break;
 
1457
        }
 
1458
 
 
1459
        g_slist_free (streams);
 
1460
 
 
1461
        if (res)
 
1462
                g_hash_table_insert (manager->priv->streams,
 
1463
                                     GUINT_TO_POINTER (deviceid),
 
1464
                                     GUINT_TO_POINTER (gvc_mixer_stream_get_id (res)));
 
1465
        else
 
1466
                g_hash_table_insert (manager->priv->streams,
 
1467
                                     GUINT_TO_POINTER (deviceid),
 
1468
                                     GUINT_TO_POINTER ((guint) -1));
 
1469
 
 
1470
        return res;
 
1471
}
 
1472
#endif /* HAVE_GUDEV */
 
1473
 
 
1474
static void
 
1475
do_sound_action (GsdMediaKeysManager *manager,
 
1476
                 guint                deviceid,
 
1477
                 int                  type,
 
1478
                 gboolean             is_output,
 
1479
                 gboolean             quiet)
 
1480
{
 
1481
        GvcMixerStream *stream;
 
1482
        gboolean old_muted, new_muted;
 
1483
        guint old_vol, new_vol, norm_vol_step, osd_vol;
 
1484
        gboolean sound_changed;
 
1485
 
 
1486
        /* Find the stream that corresponds to the device, if any */
 
1487
        stream = NULL;
 
1488
#ifdef HAVE_GUDEV
 
1489
        stream = get_stream_for_device_id (manager, is_output, deviceid);
 
1490
#endif /* HAVE_GUDEV */
 
1491
 
 
1492
        if (stream == NULL) {
 
1493
                if (is_output)
 
1494
                        stream = manager->priv->sink;
 
1495
                else
 
1496
                        stream = manager->priv->source;
 
1497
        }
 
1498
 
 
1499
        if (stream == NULL)
 
1500
                return;
 
1501
 
 
1502
        norm_vol_step = PA_VOLUME_NORM * VOLUME_STEP / 100;
 
1503
 
 
1504
        /* FIXME: this is racy */
 
1505
        new_vol = old_vol = gvc_mixer_stream_get_volume (stream);
 
1506
        new_muted = old_muted = gvc_mixer_stream_get_is_muted (stream);
 
1507
        sound_changed = FALSE;
 
1508
 
 
1509
        switch (type) {
 
1510
        case MUTE_KEY:
 
1511
                new_muted = !old_muted;
 
1512
                break;
 
1513
        case VOLUME_DOWN_KEY:
 
1514
                if (old_vol <= norm_vol_step) {
 
1515
                        new_vol = 0;
 
1516
                        new_muted = TRUE;
 
1517
                } else {
 
1518
                        new_vol = old_vol - norm_vol_step;
 
1519
                }
 
1520
                break;
 
1521
        case VOLUME_UP_KEY:
 
1522
                new_muted = FALSE;
 
1523
                /* When coming out of mute only increase the volume if it was 0 */
 
1524
                if (!old_muted || old_vol == 0)
 
1525
                        new_vol = MIN (old_vol + norm_vol_step, MAX_VOLUME);
 
1526
                break;
 
1527
        }
 
1528
 
 
1529
        if (old_muted != new_muted) {
 
1530
                gvc_mixer_stream_change_is_muted (stream, new_muted);
 
1531
                sound_changed = TRUE;
 
1532
        }
 
1533
 
 
1534
        if (old_vol != new_vol) {
 
1535
                if (gvc_mixer_stream_set_volume (stream, new_vol) != FALSE) {
 
1536
                        gvc_mixer_stream_push_volume (stream);
 
1537
                        sound_changed = TRUE;
 
1538
                }
 
1539
        }
 
1540
 
 
1541
        if (type == VOLUME_DOWN_KEY && old_vol == 0 && old_muted)
 
1542
                osd_vol = -1;
 
1543
        else if (type == VOLUME_UP_KEY && old_vol == PA_VOLUME_NORM && !old_muted)
 
1544
                osd_vol = 101;
 
1545
        else if (!new_muted)
 
1546
                osd_vol = (int) (100 * (double) new_vol / PA_VOLUME_NORM);
 
1547
        else
 
1548
                osd_vol = 0;
 
1549
 
 
1550
        update_dialog (manager, stream, osd_vol, new_muted, sound_changed, quiet);
 
1551
}
 
1552
 
 
1553
static void
 
1554
sound_theme_changed (GtkSettings         *settings,
 
1555
                     GParamSpec          *pspec,
 
1556
                     GsdMediaKeysManager *manager)
 
1557
{
 
1558
        char *theme_name;
 
1559
 
 
1560
        g_object_get (G_OBJECT (manager->priv->gtksettings), "gtk-sound-theme-name", &theme_name, NULL);
 
1561
        if (theme_name)
 
1562
                ca_context_change_props (manager->priv->ca, CA_PROP_CANBERRA_XDG_THEME_NAME, theme_name, NULL);
 
1563
        g_free (theme_name);
 
1564
}
 
1565
 
 
1566
static void
 
1567
update_default_sink (GsdMediaKeysManager *manager)
 
1568
{
 
1569
        GvcMixerStream *stream;
 
1570
 
 
1571
        stream = gvc_mixer_control_get_default_sink (manager->priv->volume);
 
1572
        if (stream == manager->priv->sink)
 
1573
                return;
 
1574
 
 
1575
        g_clear_object (&manager->priv->sink);
 
1576
 
 
1577
        if (stream != NULL) {
 
1578
                manager->priv->sink = g_object_ref (stream);
 
1579
        } else {
 
1580
                g_warning ("Unable to get default sink");
 
1581
        }
 
1582
}
 
1583
 
 
1584
static void
 
1585
update_default_source (GsdMediaKeysManager *manager)
 
1586
{
 
1587
        GvcMixerStream *stream;
 
1588
 
 
1589
        stream = gvc_mixer_control_get_default_source (manager->priv->volume);
 
1590
        if (stream == manager->priv->source)
 
1591
                return;
 
1592
 
 
1593
        g_clear_object (&manager->priv->source);
 
1594
 
 
1595
        if (stream != NULL) {
 
1596
                manager->priv->source = g_object_ref (stream);
 
1597
        } else {
 
1598
                g_warning ("Unable to get default source");
 
1599
        }
 
1600
}
 
1601
 
 
1602
static void
 
1603
on_control_state_changed (GvcMixerControl     *control,
 
1604
                          GvcMixerControlState new_state,
 
1605
                          GsdMediaKeysManager *manager)
 
1606
{
 
1607
        update_default_sink (manager);
 
1608
        update_default_source (manager);
 
1609
}
 
1610
 
 
1611
static void
 
1612
on_control_default_sink_changed (GvcMixerControl     *control,
 
1613
                                 guint                id,
 
1614
                                 GsdMediaKeysManager *manager)
 
1615
{
 
1616
        update_default_sink (manager);
 
1617
}
 
1618
 
 
1619
static void
 
1620
on_control_default_source_changed (GvcMixerControl     *control,
 
1621
                                   guint                id,
 
1622
                                   GsdMediaKeysManager *manager)
 
1623
{
 
1624
        update_default_source (manager);
 
1625
}
 
1626
 
 
1627
#ifdef HAVE_GUDEV
 
1628
static gboolean
 
1629
remove_stream (gpointer key,
 
1630
               gpointer value,
 
1631
               gpointer id)
 
1632
{
 
1633
        if (GPOINTER_TO_UINT (value) == GPOINTER_TO_UINT (id))
 
1634
                return TRUE;
 
1635
        return FALSE;
 
1636
}
 
1637
#endif /* HAVE_GUDEV */
 
1638
 
 
1639
static void
 
1640
on_control_stream_removed (GvcMixerControl     *control,
 
1641
                           guint                id,
 
1642
                           GsdMediaKeysManager *manager)
 
1643
{
 
1644
        if (manager->priv->sink != NULL) {
 
1645
                if (gvc_mixer_stream_get_id (manager->priv->sink) == id)
 
1646
                        g_clear_object (&manager->priv->sink);
 
1647
        }
 
1648
        if (manager->priv->source != NULL) {
 
1649
                if (gvc_mixer_stream_get_id (manager->priv->source) == id)
 
1650
                        g_clear_object (&manager->priv->source);
 
1651
        }
 
1652
 
 
1653
#ifdef HAVE_GUDEV
 
1654
        g_hash_table_foreach_remove (manager->priv->streams, (GHRFunc) remove_stream, GUINT_TO_POINTER (id));
 
1655
#endif
 
1656
}
 
1657
 
 
1658
static void
 
1659
free_media_player (MediaPlayer *player)
 
1660
{
 
1661
        if (player->watch_id > 0) {
 
1662
                g_bus_unwatch_name (player->watch_id);
 
1663
                player->watch_id = 0;
 
1664
        }
 
1665
        g_free (player->application);
 
1666
        g_free (player->dbus_name);
 
1667
        g_free (player);
 
1668
}
 
1669
 
 
1670
static gint
 
1671
find_by_application (gconstpointer a,
 
1672
                     gconstpointer b)
 
1673
{
 
1674
        return strcmp (((MediaPlayer *)a)->application, b);
 
1675
}
 
1676
 
 
1677
static gint
 
1678
find_by_name (gconstpointer a,
 
1679
              gconstpointer b)
 
1680
{
 
1681
        return strcmp (((MediaPlayer *)a)->dbus_name, b);
 
1682
}
 
1683
 
 
1684
static gint
 
1685
find_by_time (gconstpointer a,
 
1686
              gconstpointer b)
 
1687
{
 
1688
        return ((MediaPlayer *)a)->time < ((MediaPlayer *)b)->time;
 
1689
}
 
1690
 
 
1691
static void
 
1692
name_vanished_handler (GDBusConnection     *connection,
 
1693
                       const gchar         *name,
 
1694
                       GsdMediaKeysManager *manager)
 
1695
{
 
1696
        GList *iter;
 
1697
 
 
1698
        iter = g_list_find_custom (manager->priv->media_players,
 
1699
                                   name,
 
1700
                                   find_by_name);
 
1701
 
 
1702
        if (iter != NULL) {
 
1703
                MediaPlayer *player;
 
1704
 
 
1705
                player = iter->data;
 
1706
                g_debug ("Deregistering vanished %s (dbus_name: %s)", player->application, player->dbus_name);
 
1707
                free_media_player (player);
 
1708
                manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter);
 
1709
        }
 
1710
}
 
1711
 
 
1712
/*
 
1713
 * Register a new media player. Most applications will want to call
 
1714
 * this with time = GDK_CURRENT_TIME. This way, the last registered
 
1715
 * player will receive media events. In some cases, applications
 
1716
 * may want to register with a lower priority (usually 1), to grab
 
1717
 * events only nobody is interested.
 
1718
 */
 
1719
static void
 
1720
gsd_media_keys_manager_grab_media_player_keys (GsdMediaKeysManager *manager,
 
1721
                                               const char          *application,
 
1722
                                               const char          *dbus_name,
 
1723
                                               guint32              time)
 
1724
{
 
1725
        GList       *iter;
 
1726
        MediaPlayer *media_player;
 
1727
        guint        watch_id;
 
1728
 
 
1729
        if (time == GDK_CURRENT_TIME) {
 
1730
                GTimeVal tv;
 
1731
 
 
1732
                g_get_current_time (&tv);
 
1733
                time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
 
1734
        }
 
1735
 
 
1736
        iter = g_list_find_custom (manager->priv->media_players,
 
1737
                                   application,
 
1738
                                   find_by_application);
 
1739
 
 
1740
        if (iter != NULL) {
 
1741
                if (((MediaPlayer *)iter->data)->time < time) {
 
1742
                        MediaPlayer *player = iter->data;
 
1743
                        free_media_player (player);
 
1744
                        manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter);
 
1745
                } else {
 
1746
                        return;
 
1747
                }
 
1748
        }
 
1749
 
 
1750
        watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
 
1751
                                     dbus_name,
 
1752
                                     G_BUS_NAME_WATCHER_FLAGS_NONE,
 
1753
                                     NULL,
 
1754
                                     (GBusNameVanishedCallback) name_vanished_handler,
 
1755
                                     manager,
 
1756
                                     NULL);
 
1757
 
 
1758
        g_debug ("Registering %s at %u", application, time);
 
1759
        media_player = g_new0 (MediaPlayer, 1);
 
1760
        media_player->application = g_strdup (application);
 
1761
        media_player->dbus_name = g_strdup (dbus_name);
 
1762
        media_player->time = time;
 
1763
        media_player->watch_id = watch_id;
 
1764
 
 
1765
        manager->priv->media_players = g_list_insert_sorted (manager->priv->media_players,
 
1766
                                                             media_player,
 
1767
                                                             find_by_time);
 
1768
}
 
1769
 
 
1770
static void
 
1771
gsd_media_keys_manager_release_media_player_keys (GsdMediaKeysManager *manager,
 
1772
                                                  const char          *application,
 
1773
                                                  const char          *name)
 
1774
{
 
1775
        GList *iter = NULL;
 
1776
 
 
1777
        g_return_if_fail (application != NULL || name != NULL);
 
1778
 
 
1779
        if (application != NULL) {
 
1780
                iter = g_list_find_custom (manager->priv->media_players,
 
1781
                                           application,
 
1782
                                           find_by_application);
 
1783
        }
 
1784
 
 
1785
        if (iter == NULL && name != NULL) {
 
1786
                iter = g_list_find_custom (manager->priv->media_players,
 
1787
                                           name,
 
1788
                                           find_by_name);
 
1789
        }
 
1790
 
 
1791
        if (iter != NULL) {
 
1792
                MediaPlayer *player;
 
1793
 
 
1794
                player = iter->data;
 
1795
                g_debug ("Deregistering %s (dbus_name: %s)", application, player->dbus_name);
 
1796
                free_media_player (player);
 
1797
                manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter);
 
1798
        }
 
1799
}
 
1800
 
 
1801
static gboolean
 
1802
gsd_media_player_key_pressed (GsdMediaKeysManager *manager,
 
1803
                              const char          *key)
 
1804
{
 
1805
        const char  *application;
 
1806
        gboolean     have_listeners;
 
1807
        GError      *error = NULL;
 
1808
        MediaPlayer *player;
 
1809
 
 
1810
        g_return_val_if_fail (key != NULL, FALSE);
 
1811
 
 
1812
        g_debug ("Media key '%s' pressed", key);
 
1813
 
 
1814
        have_listeners = (manager->priv->media_players != NULL);
 
1815
 
 
1816
        if (!have_listeners) {
 
1817
                /* Popup a dialog with an (/) icon */
 
1818
                show_osd (manager, "action-unavailable-symbolic", NULL, -1);
 
1819
                return TRUE;
 
1820
        }
 
1821
 
 
1822
        player = manager->priv->media_players->data;
 
1823
        application = player->application;
 
1824
 
 
1825
        if (g_dbus_connection_emit_signal (manager->priv->connection,
 
1826
                                           player->dbus_name,
 
1827
                                           GSD_MEDIA_KEYS_DBUS_PATH,
 
1828
                                           GSD_MEDIA_KEYS_DBUS_NAME,
 
1829
                                           "MediaPlayerKeyPressed",
 
1830
                                           g_variant_new ("(ss)", application ? application : "", key),
 
1831
                                           &error) == FALSE) {
 
1832
                g_debug ("Error emitting signal: %s", error->message);
 
1833
                g_error_free (error);
 
1834
        }
 
1835
 
 
1836
        return !have_listeners;
 
1837
}
 
1838
 
 
1839
static void
 
1840
handle_method_call (GDBusConnection       *connection,
 
1841
                    const gchar           *sender,
 
1842
                    const gchar           *object_path,
 
1843
                    const gchar           *interface_name,
 
1844
                    const gchar           *method_name,
 
1845
                    GVariant              *parameters,
 
1846
                    GDBusMethodInvocation *invocation,
 
1847
                    gpointer               user_data)
 
1848
{
 
1849
        GsdMediaKeysManager *manager = (GsdMediaKeysManager *) user_data;
 
1850
 
 
1851
        g_debug ("Calling method '%s' for media-keys", method_name);
 
1852
 
 
1853
        if (g_strcmp0 (method_name, "ReleaseMediaPlayerKeys") == 0) {
 
1854
                const char *app_name;
 
1855
 
 
1856
                g_variant_get (parameters, "(&s)", &app_name);
 
1857
                gsd_media_keys_manager_release_media_player_keys (manager, app_name, sender);
 
1858
                g_dbus_method_invocation_return_value (invocation, NULL);
 
1859
        } else if (g_strcmp0 (method_name, "GrabMediaPlayerKeys") == 0) {
 
1860
                const char *app_name;
 
1861
                guint32 time;
 
1862
 
 
1863
                g_variant_get (parameters, "(&su)", &app_name, &time);
 
1864
                gsd_media_keys_manager_grab_media_player_keys (manager, app_name, sender, time);
 
1865
                g_dbus_method_invocation_return_value (invocation, NULL);
 
1866
        }
 
1867
}
 
1868
 
 
1869
static const GDBusInterfaceVTable interface_vtable =
 
1870
{
 
1871
        handle_method_call,
 
1872
        NULL, /* Get Property */
 
1873
        NULL, /* Set Property */
 
1874
};
 
1875
 
 
1876
static gboolean
 
1877
do_multimedia_player_action (GsdMediaKeysManager *manager,
 
1878
                             const char          *icon,
 
1879
                             const char          *key)
 
1880
{
 
1881
        if (icon != NULL)
 
1882
                ubuntu_osd_notification_show_icon (icon, key);
 
1883
        return gsd_media_player_key_pressed (manager, key);
 
1884
}
 
1885
 
 
1886
static void
 
1887
on_xrandr_action_call_finished (GObject             *source_object,
 
1888
                                GAsyncResult        *res,
 
1889
                                GsdMediaKeysManager *manager)
 
1890
{
 
1891
        GError *error = NULL;
 
1892
        GVariant *variant;
 
1893
        char *action;
 
1894
 
 
1895
        action = g_object_get_data (G_OBJECT (source_object),
 
1896
                                    "gsd-media-keys-manager-xrandr-action");
 
1897
 
 
1898
        variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error);
 
1899
 
 
1900
        g_object_unref (manager->priv->cancellable);
 
1901
        manager->priv->cancellable = NULL;
 
1902
 
 
1903
        if (error != NULL) {
 
1904
                g_warning ("Unable to call '%s': %s", action, error->message);
 
1905
                g_error_free (error);
 
1906
        } else {
 
1907
                g_variant_unref (variant);
 
1908
        }
 
1909
 
 
1910
        g_free (action);
 
1911
}
 
1912
 
 
1913
static void
 
1914
do_xrandr_action (GsdMediaKeysManager *manager,
 
1915
                  const char          *action,
 
1916
                  gint64               timestamp)
 
1917
{
 
1918
        GsdMediaKeysManagerPrivate *priv = manager->priv;
 
1919
 
 
1920
        if (priv->connection == NULL || priv->xrandr_proxy == NULL) {
 
1921
                g_warning ("No existing D-Bus connection trying to handle XRANDR keys");
 
1922
                return;
 
1923
        }
 
1924
 
 
1925
        if (priv->cancellable != NULL) {
 
1926
                g_debug ("xrandr action already in flight");
 
1927
                return;
 
1928
        }
 
1929
 
 
1930
        priv->cancellable = g_cancellable_new ();
 
1931
 
 
1932
        g_object_set_data (G_OBJECT (priv->xrandr_proxy),
 
1933
                           "gsd-media-keys-manager-xrandr-action",
 
1934
                           g_strdup (action));
 
1935
 
 
1936
        g_dbus_proxy_call (priv->xrandr_proxy,
 
1937
                           action,
 
1938
                           g_variant_new ("(x)", timestamp),
 
1939
                           G_DBUS_CALL_FLAGS_NONE,
 
1940
                           -1,
 
1941
                           priv->cancellable,
 
1942
                           (GAsyncReadyCallback) on_xrandr_action_call_finished,
 
1943
                           manager);
 
1944
}
 
1945
 
 
1946
static gboolean
 
1947
do_video_out_action (GsdMediaKeysManager *manager,
 
1948
                     gint64               timestamp)
 
1949
{
 
1950
        do_xrandr_action (manager, "VideoModeSwitch", timestamp);
 
1951
        return FALSE;
 
1952
}
 
1953
 
 
1954
static gboolean
 
1955
do_video_rotate_action (GsdMediaKeysManager *manager,
 
1956
                        gint64               timestamp)
 
1957
{
 
1958
        do_xrandr_action (manager, "Rotate", timestamp);
 
1959
        return FALSE;
 
1960
}
 
1961
 
 
1962
static void
 
1963
do_toggle_accessibility_key (const char *key)
 
1964
{
 
1965
        GSettings *settings;
 
1966
        gboolean state;
 
1967
 
 
1968
        settings = g_settings_new ("org.gnome.desktop.a11y.applications");
 
1969
        state = g_settings_get_boolean (settings, key);
 
1970
        g_settings_set_boolean (settings, key, !state);
 
1971
        g_object_unref (settings);
 
1972
}
 
1973
 
 
1974
static void
 
1975
do_magnifier_action (GsdMediaKeysManager *manager)
 
1976
{
 
1977
        do_toggle_accessibility_key ("screen-magnifier-enabled");
 
1978
}
 
1979
 
 
1980
static void
 
1981
do_screenreader_action (GsdMediaKeysManager *manager)
 
1982
{
 
1983
        do_toggle_accessibility_key ("screen-reader-enabled");
 
1984
}
 
1985
 
 
1986
static void
 
1987
do_on_screen_keyboard_action (GsdMediaKeysManager *manager)
 
1988
{
 
1989
        do_toggle_accessibility_key ("screen-keyboard-enabled");
 
1990
}
 
1991
 
 
1992
static void
 
1993
do_text_size_action (GsdMediaKeysManager *manager,
 
1994
                     MediaKeyType         type)
 
1995
{
 
1996
        gdouble factor, best, distance;
 
1997
        guint i;
 
1998
 
 
1999
        /* Same values used in the Seeing tab of the Universal Access panel */
 
2000
        static gdouble factors[] = {
 
2001
                0.75,
 
2002
                1.0,
 
2003
                1.25,
 
2004
                1.5
 
2005
        };
 
2006
 
 
2007
        /* Figure out the current DPI scaling factor */
 
2008
        factor = g_settings_get_double (manager->priv->interface_settings, "text-scaling-factor");
 
2009
        factor += (type == INCREASE_TEXT_KEY ? 0.25 : -0.25);
 
2010
 
 
2011
        /* Try to find a matching value */
 
2012
        distance = 1e6;
 
2013
        best = 1.0;
 
2014
        for (i = 0; i < G_N_ELEMENTS(factors); i++) {
 
2015
                gdouble d;
 
2016
                d = fabs (factor - factors[i]);
 
2017
                if (d < distance) {
 
2018
                        best = factors[i];
 
2019
                        distance = d;
 
2020
                }
 
2021
        }
 
2022
 
 
2023
        if (best == 1.0)
 
2024
                g_settings_reset (manager->priv->interface_settings, "text-scaling-factor");
 
2025
        else
 
2026
                g_settings_set_double (manager->priv->interface_settings, "text-scaling-factor", best);
 
2027
}
 
2028
 
 
2029
static void
 
2030
do_magnifier_zoom_action (GsdMediaKeysManager *manager,
 
2031
                          MediaKeyType         type)
 
2032
{
 
2033
        GSettings *settings;
 
2034
        gdouble offset, value;
 
2035
 
 
2036
        if (type == MAGNIFIER_ZOOM_IN_KEY)
 
2037
                offset = 1.0;
 
2038
        else
 
2039
                offset = -1.0;
 
2040
 
 
2041
        settings = g_settings_new ("org.gnome.desktop.a11y.magnifier");
 
2042
        value = g_settings_get_double (settings, "mag-factor");
 
2043
        value += offset;
 
2044
        value = roundl (value);
 
2045
        g_settings_set_double (settings, "mag-factor", value);
 
2046
        g_object_unref (settings);
 
2047
}
 
2048
 
 
2049
static void
 
2050
do_toggle_contrast_action (GsdMediaKeysManager *manager)
 
2051
{
 
2052
        gboolean high_contrast;
 
2053
        char *theme;
 
2054
 
 
2055
        /* Are we using HighContrast now? */
 
2056
        theme = g_settings_get_string (manager->priv->interface_settings, "gtk-theme");
 
2057
        high_contrast = g_str_equal (theme, HIGH_CONTRAST);
 
2058
        g_free (theme);
 
2059
 
 
2060
        if (high_contrast != FALSE) {
 
2061
                if (manager->priv->gtk_theme == NULL)
 
2062
                        g_settings_reset (manager->priv->interface_settings, "gtk-theme");
 
2063
                else
 
2064
                        g_settings_set (manager->priv->interface_settings, "gtk-theme", manager->priv->gtk_theme);
 
2065
                g_settings_set (manager->priv->interface_settings, "icon-theme", manager->priv->icon_theme);
 
2066
        } else {
 
2067
                g_settings_set (manager->priv->interface_settings, "gtk-theme", HIGH_CONTRAST);
 
2068
                g_settings_set (manager->priv->interface_settings, "icon-theme", HIGH_CONTRAST);
 
2069
        }
 
2070
}
 
2071
 
 
2072
static void
 
2073
power_action (GsdMediaKeysManager *manager,
 
2074
              const char          *action,
 
2075
              gboolean             allow_interaction)
 
2076
{
 
2077
        g_dbus_proxy_call (manager->priv->logind_proxy,
 
2078
                           action,
 
2079
                           g_variant_new ("(b)", allow_interaction),
 
2080
                           G_DBUS_CALL_FLAGS_NONE,
 
2081
                           G_MAXINT,
 
2082
                           manager->priv->bus_cancellable,
 
2083
                           NULL, NULL);
 
2084
}
 
2085
 
 
2086
static void
 
2087
do_config_power_action (GsdMediaKeysManager *manager,
 
2088
                        const gchar *config_key,
 
2089
                        gboolean in_lock_screen)
 
2090
{
 
2091
        GsdPowerActionType action_type;
 
2092
 
 
2093
        action_type = g_settings_get_enum (manager->priv->power_settings,
 
2094
                                           config_key);
 
2095
        switch (action_type) {
 
2096
        case GSD_POWER_ACTION_SUSPEND:
 
2097
                power_action (manager, "Suspend", !in_lock_screen);
 
2098
                break;
 
2099
        case GSD_POWER_ACTION_INTERACTIVE:
 
2100
                if (!in_lock_screen)
 
2101
                        gnome_session_shutdown (manager);
 
2102
                break;
 
2103
        case GSD_POWER_ACTION_SHUTDOWN:
 
2104
                power_action (manager, "PowerOff", !in_lock_screen);
 
2105
                break;
 
2106
        case GSD_POWER_ACTION_HIBERNATE:
 
2107
                power_action (manager, "Hibernate", !in_lock_screen);
 
2108
                break;
 
2109
        case GSD_POWER_ACTION_BLANK:
 
2110
        case GSD_POWER_ACTION_NOTHING:
 
2111
                /* these actions cannot be handled by media-keys and
 
2112
                 * are not used in this context */
 
2113
                break;
 
2114
        }
 
2115
 
 
2116
}
 
2117
 
 
2118
static void
 
2119
do_switch_input_source_action (GsdMediaKeysManager *manager,
 
2120
                               MediaKeyType         type)
 
2121
{
 
2122
        GSettings *settings;
 
2123
        GVariant *sources;
 
2124
        gint i, n;
 
2125
 
 
2126
        if (!manager->priv->have_legacy_keygrabber)
 
2127
                return;
 
2128
 
 
2129
        settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR);
 
2130
        sources = g_settings_get_value (settings, KEY_INPUT_SOURCES);
 
2131
 
 
2132
        n = g_variant_n_children (sources);
 
2133
        if (n < 2)
 
2134
                goto out;
 
2135
 
 
2136
        i = g_settings_get_uint (settings, KEY_CURRENT_INPUT_SOURCE);
 
2137
 
 
2138
        if (type == SWITCH_INPUT_SOURCE_KEY)
 
2139
                i += 1;
 
2140
        else
 
2141
                i -= 1;
 
2142
 
 
2143
        if (i < 0)
 
2144
                i = n - 1;
 
2145
        else if (i >= n)
 
2146
                i = 0;
 
2147
 
 
2148
        g_settings_set_uint (settings, KEY_CURRENT_INPUT_SOURCE, i);
 
2149
 
 
2150
 out:
 
2151
        g_variant_unref (sources);
 
2152
        g_object_unref (settings);
 
2153
}
 
2154
 
 
2155
static void
 
2156
update_screen_cb (GObject             *source_object,
 
2157
                  GAsyncResult        *res,
 
2158
                  gpointer             user_data)
 
2159
{
 
2160
        GError *error = NULL;
 
2161
        guint percentage;
 
2162
        GVariant *new_percentage;
 
2163
        GsdBrightnessActionData *data = (GsdBrightnessActionData *) user_data;
 
2164
        GsdMediaKeysManager *manager = data->manager;
 
2165
 
 
2166
        new_percentage = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
 
2167
                                                   res, &error);
 
2168
        if (new_percentage == NULL) {
 
2169
                g_warning ("Failed to set new screen percentage: %s",
 
2170
                           error->message);
 
2171
                g_error_free (error);
 
2172
                g_free (data);
 
2173
                return;
 
2174
        }
 
2175
 
 
2176
        /* update the dialog with the new value */
 
2177
        g_variant_get (new_percentage, "(u)", &percentage);
 
2178
        guint osd_percentage;
 
2179
 
 
2180
        if (data->old_percentage == 100 && data->type == SCREEN_BRIGHTNESS_UP_KEY)
 
2181
                osd_percentage = 101;
 
2182
        else if (data->old_percentage == 0 && data->type == SCREEN_BRIGHTNESS_DOWN_KEY)
 
2183
                osd_percentage = -1;
 
2184
        else
 
2185
                osd_percentage = CLAMP (percentage, 0, 100);
 
2186
 
 
2187
        if (!ubuntu_osd_notification_show_brightness (manager, osd_percentage)) {
 
2188
                show_osd (manager, "display-brightness-symbolic", NULL, percentage);
 
2189
        }
 
2190
        g_free (data);
 
2191
        g_variant_unref (new_percentage);
 
2192
}
 
2193
 
 
2194
static void
 
2195
do_screen_brightness_action_real (GObject       *source_object,
 
2196
                                  GAsyncResult  *res,
 
2197
                                  gpointer       user_data)
 
2198
{
 
2199
        GsdBrightnessActionData *data = (GsdBrightnessActionData *) user_data;
 
2200
        GsdMediaKeysManager *manager = data->manager;
 
2201
        GError *error = NULL;
 
2202
 
 
2203
        GVariant *old_percentage = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
 
2204
                                                             res, &error);
 
2205
        if (old_percentage == NULL) {
 
2206
                g_warning ("Failed to get old screen percentage: %s", error->message);
 
2207
                g_error_free (error);
 
2208
                g_free (data);
 
2209
                return;
 
2210
        }
 
2211
 
 
2212
        g_variant_get (old_percentage, "(u)", &data->old_percentage);
 
2213
 
 
2214
        /* call into the power plugin */
 
2215
        g_dbus_proxy_call (manager->priv->power_screen_proxy,
 
2216
                           data->type == SCREEN_BRIGHTNESS_UP_KEY ? "StepUp" : "StepDown",
 
2217
                           NULL,
 
2218
                           G_DBUS_CALL_FLAGS_NONE,
 
2219
                           -1,
 
2220
                           NULL,
 
2221
                           update_screen_cb,
 
2222
                           data);
 
2223
 
 
2224
        g_variant_unref (old_percentage);
 
2225
}
 
2226
 
 
2227
static void
 
2228
do_screen_brightness_action (GsdMediaKeysManager *manager,
 
2229
                             MediaKeyType type)
 
2230
{
 
2231
        if (manager->priv->connection == NULL ||
 
2232
            manager->priv->power_screen_proxy == NULL) {
 
2233
                g_warning ("No existing D-Bus connection trying to handle power keys");
 
2234
                return;
 
2235
        }
 
2236
 
 
2237
        GsdBrightnessActionData *data = g_new0 (GsdBrightnessActionData, 1);
 
2238
        data->manager = manager;
 
2239
        data->type = type;
 
2240
 
 
2241
        g_dbus_proxy_call (manager->priv->power_screen_proxy,
 
2242
                           "GetPercentage",
 
2243
                           NULL,
 
2244
                           G_DBUS_CALL_FLAGS_NONE,
 
2245
                           -1,
 
2246
                           NULL,
 
2247
                           do_screen_brightness_action_real,
 
2248
                           data);
 
2249
}
 
2250
 
 
2251
static void
 
2252
update_keyboard_cb (GObject             *source_object,
 
2253
                    GAsyncResult        *res,
 
2254
                    gpointer             user_data)
 
2255
{
 
2256
        GError *error = NULL;
 
2257
        guint percentage;
 
2258
        GVariant *new_percentage;
 
2259
        GsdMediaKeysManager *manager = GSD_MEDIA_KEYS_MANAGER (user_data);
 
2260
 
 
2261
        new_percentage = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
 
2262
                                                   res, &error);
 
2263
        if (new_percentage == NULL) {
 
2264
                g_warning ("Failed to set new keyboard percentage: %s",
 
2265
                           error->message);
 
2266
                g_error_free (error);
 
2267
                return;
 
2268
        }
 
2269
 
 
2270
        /* update the dialog with the new value */
 
2271
        g_variant_get (new_percentage, "(u)", &percentage);
 
2272
 
 
2273
        /* FIXME: No overshoot effect for keyboard, as the power plugin has no interface
 
2274
         *        to get the old brightness */
 
2275
        if (!ubuntu_osd_notification_show_kb_backlight (manager, CLAMP (percentage, 0, 100))) {
 
2276
                show_osd (manager, "keyboard-brightness-symbolic", NULL, percentage);
 
2277
        }
 
2278
        g_variant_unref (new_percentage);
 
2279
}
 
2280
 
 
2281
static void
 
2282
do_keyboard_brightness_action (GsdMediaKeysManager *manager,
 
2283
                               MediaKeyType type)
 
2284
{
 
2285
        const char *cmd;
 
2286
 
 
2287
        if (manager->priv->connection == NULL ||
 
2288
            manager->priv->power_keyboard_proxy == NULL) {
 
2289
                g_warning ("No existing D-Bus connection trying to handle power keys");
 
2290
                return;
 
2291
        }
 
2292
 
 
2293
        switch (type) {
 
2294
        case KEYBOARD_BRIGHTNESS_UP_KEY:
 
2295
                cmd = "StepUp";
 
2296
                break;
 
2297
        case KEYBOARD_BRIGHTNESS_DOWN_KEY:
 
2298
                cmd = "StepDown";
 
2299
                break;
 
2300
        case KEYBOARD_BRIGHTNESS_TOGGLE_KEY:
 
2301
                cmd = "Toggle";
 
2302
                break;
 
2303
        default:
 
2304
                g_assert_not_reached ();
 
2305
        }
 
2306
 
 
2307
        /* call into the power plugin */
 
2308
        g_dbus_proxy_call (manager->priv->power_keyboard_proxy,
 
2309
                           cmd,
 
2310
                           NULL,
 
2311
                           G_DBUS_CALL_FLAGS_NONE,
 
2312
                           -1,
 
2313
                           NULL,
 
2314
                           update_keyboard_cb,
 
2315
                           manager);
 
2316
}
 
2317
 
 
2318
static void
 
2319
do_battery_action (GsdMediaKeysManager *manager)
 
2320
{
 
2321
        GVariant *icon_var, *percentage;
 
2322
        char *label = NULL;
 
2323
 
 
2324
        if (manager->priv->power_proxy == NULL)
 
2325
                return;
 
2326
 
 
2327
        icon_var = g_dbus_proxy_get_cached_property (manager->priv->power_proxy, "Icon");
 
2328
        percentage = g_dbus_proxy_get_cached_property (manager->priv->power_proxy, "Percentage");
 
2329
 
 
2330
        if (g_variant_get_double (percentage) >= 0.0)
 
2331
                label = g_strdup_printf ("%d %%", (int) g_variant_get_double (percentage));
 
2332
 
 
2333
        show_osd (manager, g_variant_get_string (icon_var, NULL),
 
2334
                  label, g_variant_get_double (percentage));
 
2335
        g_free (label);
 
2336
}
 
2337
static void
 
2338
do_screenshot_action (GsdMediaKeysManager *manager,
 
2339
                      MediaKeyType         type)
 
2340
{
 
2341
        if (!manager->priv->have_legacy_keygrabber)
 
2342
                gsd_screenshot_take (type);
 
2343
        else {
 
2344
                switch (type){
 
2345
                case SCREENSHOT_KEY:
 
2346
                        execute (manager, "gnome-screenshot", FALSE);
 
2347
                        break;
 
2348
                case WINDOW_SCREENSHOT_KEY:
 
2349
                        execute (manager, "gnome-screenshot --window", FALSE);
 
2350
                        break;
 
2351
                case AREA_SCREENSHOT_KEY:
 
2352
                        execute (manager, "gnome-screenshot --area", FALSE);
 
2353
                        break;
 
2354
                case SCREENSHOT_CLIP_KEY:
 
2355
                        execute (manager, "gnome-screenshot --clipboard", FALSE);
 
2356
                        break;
 
2357
                case WINDOW_SCREENSHOT_CLIP_KEY:
 
2358
                        execute (manager, "gnome-screenshot --window --clipboard", FALSE);
 
2359
                        break;
 
2360
                case AREA_SCREENSHOT_CLIP_KEY:
 
2361
                        execute (manager, "gnome-screenshot --area --clipboard", FALSE);
 
2362
                }
 
2363
        }
 
2364
}
 
2365
 
 
2366
static void
 
2367
do_custom_action (GsdMediaKeysManager *manager,
 
2368
                  guint                deviceid,
 
2369
                  MediaKey            *key,
 
2370
                  gint64               timestamp)
 
2371
{
 
2372
        g_debug ("Launching custom action for key (on device id %d)", deviceid);
 
2373
 
 
2374
        execute (manager, key->custom_command, FALSE);
 
2375
}
 
2376
 
 
2377
static gboolean
 
2378
do_action (GsdMediaKeysManager *manager,
 
2379
           guint                deviceid,
 
2380
           MediaKeyType         type,
 
2381
           gint64               timestamp)
 
2382
{
 
2383
        g_debug ("Launching action for key type '%d' (on device id %d)", type, deviceid);
 
2384
 
 
2385
        switch (type) {
 
2386
        case TOUCHPAD_KEY:
 
2387
                do_touchpad_action (manager);
 
2388
                break;
 
2389
        case TOUCHPAD_ON_KEY:
 
2390
                do_touchpad_osd_action (manager, TRUE);
 
2391
                break;
 
2392
        case TOUCHPAD_OFF_KEY:
 
2393
                do_touchpad_osd_action (manager, FALSE);
 
2394
                break;
 
2395
        case MUTE_KEY:
 
2396
        case VOLUME_DOWN_KEY:
 
2397
        case VOLUME_UP_KEY:
 
2398
                do_sound_action (manager, deviceid, type, TRUE, FALSE);
 
2399
                break;
 
2400
        case MIC_MUTE_KEY:
 
2401
                do_sound_action (manager, deviceid, MUTE_KEY, FALSE, TRUE);
 
2402
                break;
 
2403
        case MUTE_QUIET_KEY:
 
2404
                do_sound_action (manager, deviceid, MUTE_KEY, TRUE, TRUE);
 
2405
                break;
 
2406
        case VOLUME_DOWN_QUIET_KEY:
 
2407
                do_sound_action (manager, deviceid, VOLUME_DOWN_KEY, TRUE, TRUE);
 
2408
                break;
 
2409
        case VOLUME_UP_QUIET_KEY:
 
2410
                do_sound_action (manager, deviceid, VOLUME_UP_KEY, TRUE, TRUE);
 
2411
                break;
 
2412
        case LOGOUT_KEY:
 
2413
                do_logout_action (manager);
 
2414
                break;
 
2415
        case EJECT_KEY:
 
2416
                do_eject_action (manager);
 
2417
                break;
 
2418
        case HOME_KEY:
 
2419
                do_home_key_action (manager, timestamp);
 
2420
                break;
 
2421
        case SEARCH_KEY:
 
2422
                do_search_action (manager, timestamp);
 
2423
                break;
 
2424
        case EMAIL_KEY:
 
2425
                do_url_action (manager, "mailto", timestamp);
 
2426
                break;
 
2427
        case SCREENSAVER_KEY:
 
2428
                do_lock_screensaver (manager);
 
2429
                break;
 
2430
        case HELP_KEY:
 
2431
                do_url_action (manager, "ghelp", timestamp);
 
2432
                break;
 
2433
        case SCREENSHOT_KEY:
 
2434
        case SCREENSHOT_CLIP_KEY:
 
2435
        case WINDOW_SCREENSHOT_KEY:
 
2436
        case WINDOW_SCREENSHOT_CLIP_KEY:
 
2437
        case AREA_SCREENSHOT_KEY:
 
2438
        case AREA_SCREENSHOT_CLIP_KEY:
 
2439
                do_screenshot_action (manager, type);
 
2440
                break;
 
2441
        case TERMINAL_KEY:
 
2442
                do_terminal_action (manager);
 
2443
                break;
 
2444
        case WWW_KEY:
 
2445
                do_url_action (manager, "http", timestamp);
 
2446
                break;
 
2447
        case MEDIA_KEY:
 
2448
                do_media_action (manager, timestamp);
 
2449
                break;
 
2450
        case CALCULATOR_KEY:
 
2451
                do_execute_desktop_or_desktop (manager, "gcalctool.desktop", "gnome-calculator.desktop", timestamp);
 
2452
                break;
 
2453
        case PLAY_KEY:
 
2454
                return do_multimedia_player_action (manager, NULL, "Play");
 
2455
        case PAUSE_KEY:
 
2456
                return do_multimedia_player_action (manager, NULL, "Pause");
 
2457
        case STOP_KEY:
 
2458
                return do_multimedia_player_action (manager, NULL, "Stop");
 
2459
        case PREVIOUS_KEY:
 
2460
                return do_multimedia_player_action (manager, NULL, "Previous");
 
2461
        case NEXT_KEY:
 
2462
                return do_multimedia_player_action (manager, NULL, "Next");
 
2463
        case REWIND_KEY:
 
2464
                return do_multimedia_player_action (manager, NULL, "Rewind");
 
2465
        case FORWARD_KEY:
 
2466
                return do_multimedia_player_action (manager, NULL, "FastForward");
 
2467
        case REPEAT_KEY:
 
2468
                return do_multimedia_player_action (manager, NULL, "Repeat");
 
2469
        case RANDOM_KEY:
 
2470
                return do_multimedia_player_action (manager, NULL, "Shuffle");
 
2471
        case VIDEO_OUT_KEY:
 
2472
                do_video_out_action (manager, timestamp);
 
2473
                break;
 
2474
        case ROTATE_VIDEO_KEY:
 
2475
                do_video_rotate_action (manager, timestamp);
 
2476
                break;
 
2477
        case MAGNIFIER_KEY:
 
2478
                do_magnifier_action (manager);
 
2479
                break;
 
2480
        case SCREENREADER_KEY:
 
2481
                do_screenreader_action (manager);
 
2482
                break;
 
2483
        case ON_SCREEN_KEYBOARD_KEY:
 
2484
                do_on_screen_keyboard_action (manager);
 
2485
                break;
 
2486
        case INCREASE_TEXT_KEY:
 
2487
        case DECREASE_TEXT_KEY:
 
2488
                do_text_size_action (manager, type);
 
2489
                break;
 
2490
        case MAGNIFIER_ZOOM_IN_KEY:
 
2491
        case MAGNIFIER_ZOOM_OUT_KEY:
 
2492
                do_magnifier_zoom_action (manager, type);
 
2493
                break;
 
2494
        case TOGGLE_CONTRAST_KEY:
 
2495
                do_toggle_contrast_action (manager);
 
2496
                break;
 
2497
        case POWER_KEY:
 
2498
                do_config_power_action (manager, "button-power", FALSE);
 
2499
                break;
 
2500
        case SLEEP_KEY:
 
2501
                do_config_power_action (manager, "button-sleep", FALSE);
 
2502
                break;
 
2503
        case SUSPEND_KEY:
 
2504
                do_config_power_action (manager, "button-suspend", FALSE);
 
2505
                break;
 
2506
        case HIBERNATE_KEY:
 
2507
                do_config_power_action (manager, "button-hibernate", FALSE);
 
2508
                break;
 
2509
        case POWER_KEY_NO_DIALOG:
 
2510
                do_config_power_action (manager, "button-power", TRUE);
 
2511
                break;
 
2512
        case SLEEP_KEY_NO_DIALOG:
 
2513
                do_config_power_action (manager, "button-sleep", TRUE);
 
2514
                break;
 
2515
        case SUSPEND_KEY_NO_DIALOG:
 
2516
                do_config_power_action (manager, "button-suspend", TRUE);
 
2517
                break;
 
2518
        case HIBERNATE_KEY_NO_DIALOG:
 
2519
                do_config_power_action (manager, "button-hibernate", TRUE);
 
2520
                break;
 
2521
        case SCREEN_BRIGHTNESS_UP_KEY:
 
2522
        case SCREEN_BRIGHTNESS_DOWN_KEY:
 
2523
                do_screen_brightness_action (manager, type);
 
2524
                break;
 
2525
        case KEYBOARD_BRIGHTNESS_UP_KEY:
 
2526
        case KEYBOARD_BRIGHTNESS_DOWN_KEY:
 
2527
        case KEYBOARD_BRIGHTNESS_TOGGLE_KEY:
 
2528
                do_keyboard_brightness_action (manager, type);
 
2529
                break;
 
2530
        case BATTERY_KEY:
 
2531
                do_battery_action (manager);
 
2532
                break;
 
2533
        case SWITCH_INPUT_SOURCE_KEY:
 
2534
        case SWITCH_INPUT_SOURCE_BACKWARD_KEY:
 
2535
                do_switch_input_source_action (manager, type);
 
2536
                break;
 
2537
        /* Note, no default so compiler catches missing keys */
 
2538
        case CUSTOM_KEY:
 
2539
                g_assert_not_reached ();
 
2540
        }
 
2541
 
 
2542
        return FALSE;
 
2543
}
 
2544
 
 
2545
static GdkScreen *
 
2546
get_screen_from_root (GsdMediaKeysManager *manager,
 
2547
                      Window               root)
 
2548
{
 
2549
        GSList    *l;
 
2550
 
 
2551
        /* Look for which screen we're receiving events */
 
2552
        for (l = manager->priv->screens; l != NULL; l = l->next) {
 
2553
                GdkScreen *screen = (GdkScreen *) l->data;
 
2554
                GdkWindow *window = gdk_screen_get_root_window (screen);
 
2555
 
 
2556
                if (GDK_WINDOW_XID (window) == root)
 
2557
                        return screen;
 
2558
        }
 
2559
 
 
2560
        return NULL;
 
2561
}
 
2562
 
 
2563
static GdkFilterReturn
 
2564
filter_key_events (XEvent              *xevent,
 
2565
                   GdkEvent            *event,
 
2566
                   GsdMediaKeysManager *manager)
 
2567
{
 
2568
    static gboolean ok_to_switch = TRUE;
 
2569
 
 
2570
    XIEvent             *xiev;
 
2571
    XIDeviceEvent       *xev;
 
2572
    XGenericEventCookie *cookie;
 
2573
        guint                i;
 
2574
    guint                deviceid;
 
2575
 
 
2576
        /* verify we have a key event */
 
2577
    if (xevent->type != GenericEvent)
 
2578
        return GDK_FILTER_CONTINUE;
 
2579
    cookie = &xevent->xcookie;
 
2580
    if (cookie->extension != manager->priv->opcode)
 
2581
        return GDK_FILTER_CONTINUE;
 
2582
 
 
2583
    xiev = (XIEvent *) xevent->xcookie.data;
 
2584
 
 
2585
    if (xiev->evtype != XI_KeyPress &&
 
2586
        xiev->evtype != XI_KeyRelease)
 
2587
        return GDK_FILTER_CONTINUE;
 
2588
 
 
2589
    xev = (XIDeviceEvent *) xiev;
 
2590
 
 
2591
    deviceid = xev->sourceid;
 
2592
 
 
2593
    if (xiev->evtype == XI_KeyPress)
 
2594
        ok_to_switch = TRUE;
 
2595
 
 
2596
        for (i = 0; i < manager->priv->keys->len; i++) {
 
2597
                MediaKey *key;
 
2598
 
 
2599
                key = g_ptr_array_index (manager->priv->keys, i);
 
2600
 
 
2601
                if (match_xi2_key (key->key, xev)) {
 
2602
                        switch (key->key_type) {
 
2603
                        case VOLUME_DOWN_KEY:
 
2604
                        case VOLUME_UP_KEY:
 
2605
                        case VOLUME_DOWN_QUIET_KEY:
 
2606
                        case VOLUME_UP_QUIET_KEY:
 
2607
                        case SCREEN_BRIGHTNESS_UP_KEY:
 
2608
                        case SCREEN_BRIGHTNESS_DOWN_KEY:
 
2609
                        case KEYBOARD_BRIGHTNESS_UP_KEY:
 
2610
                        case KEYBOARD_BRIGHTNESS_DOWN_KEY:
 
2611
                                /* auto-repeatable keys */
 
2612
                                if (xiev->evtype != XI_KeyPress)
 
2613
                                        return GDK_FILTER_CONTINUE;
 
2614
                                break;
 
2615
                        default:
 
2616
                                if (xiev->evtype != XI_KeyRelease) {
 
2617
                                        return GDK_FILTER_CONTINUE;
 
2618
                                }
 
2619
                        }
 
2620
 
 
2621
                        manager->priv->current_screen = get_screen_from_root (manager, xev->root);
 
2622
 
 
2623
                        if (key->key_type == CUSTOM_KEY) {
 
2624
                                do_custom_action (manager, deviceid, key, xev->time);
 
2625
                                return GDK_FILTER_REMOVE;
 
2626
                        }
 
2627
 
 
2628
                        if (key->key_type == SWITCH_INPUT_SOURCE_KEY || key->key_type == SWITCH_INPUT_SOURCE_BACKWARD_KEY) {
 
2629
                                if (ok_to_switch) {
 
2630
                                        do_action (manager, deviceid, key->key_type, xev->time);
 
2631
                                        ok_to_switch = FALSE;
 
2632
                                }
 
2633
 
 
2634
                                return GDK_FILTER_CONTINUE;
 
2635
                        }
 
2636
 
 
2637
                        if (do_action (manager, deviceid, key->key_type, xev->time) == FALSE) {
 
2638
                                return GDK_FILTER_REMOVE;
 
2639
                        } else {
 
2640
                                return GDK_FILTER_CONTINUE;
 
2641
                        }
 
2642
                }
 
2643
        }
 
2644
 
 
2645
        return GDK_FILTER_CONTINUE;
 
2646
}
 
2647
 
 
2648
static void
 
2649
on_accelerator_activated (ShellKeyGrabber     *grabber,
 
2650
                          guint                accel_id,
 
2651
                          guint                deviceid,
 
2652
                          GsdMediaKeysManager *manager)
 
2653
{
 
2654
        guint i;
 
2655
 
 
2656
        for (i = 0; i < manager->priv->keys->len; i++) {
 
2657
                MediaKey *key;
 
2658
 
 
2659
                key = g_ptr_array_index (manager->priv->keys, i);
 
2660
 
 
2661
                if (key->accel_id != accel_id)
 
2662
                        continue;
 
2663
 
 
2664
                if (key->key_type == CUSTOM_KEY)
 
2665
                        do_custom_action (manager, deviceid, key, GDK_CURRENT_TIME);
 
2666
                else
 
2667
                        do_action (manager, deviceid, key->key_type, GDK_CURRENT_TIME);
 
2668
                return;
 
2669
        }
 
2670
}
 
2671
 
 
2672
static void
 
2673
update_theme_settings (GSettings           *settings,
 
2674
                       const char          *key,
 
2675
                       GsdMediaKeysManager *manager)
 
2676
{
 
2677
        char *theme;
 
2678
 
 
2679
        theme = g_settings_get_string (manager->priv->interface_settings, key);
 
2680
        if (g_str_equal (theme, HIGH_CONTRAST)) {
 
2681
                g_free (theme);
 
2682
        } else {
 
2683
                if (g_str_equal (key, "gtk-theme")) {
 
2684
                        g_free (manager->priv->gtk_theme);
 
2685
                        manager->priv->gtk_theme = theme;
 
2686
                } else {
 
2687
                        g_free (manager->priv->icon_theme);
 
2688
                        manager->priv->icon_theme = theme;
 
2689
                }
 
2690
        }
 
2691
}
 
2692
 
 
2693
static void
 
2694
initialize_volume_handler (GsdMediaKeysManager *manager)
 
2695
{
 
2696
        /* initialise Volume handler
 
2697
         *
 
2698
         * We do this one here to force checking gstreamer cache, etc.
 
2699
         * The rest (grabbing and setting the keys) can happen in an
 
2700
         * idle.
 
2701
         */
 
2702
        gnome_settings_profile_start ("gvc_mixer_control_new");
 
2703
 
 
2704
        manager->priv->volume = gvc_mixer_control_new ("GNOME Volume Control Media Keys");
 
2705
 
 
2706
        g_signal_connect (manager->priv->volume,
 
2707
                          "state-changed",
 
2708
                          G_CALLBACK (on_control_state_changed),
 
2709
                          manager);
 
2710
        g_signal_connect (manager->priv->volume,
 
2711
                          "default-sink-changed",
 
2712
                          G_CALLBACK (on_control_default_sink_changed),
 
2713
                          manager);
 
2714
        g_signal_connect (manager->priv->volume,
 
2715
                          "default-source-changed",
 
2716
                          G_CALLBACK (on_control_default_source_changed),
 
2717
                          manager);
 
2718
        g_signal_connect (manager->priv->volume,
 
2719
                          "stream-removed",
 
2720
                          G_CALLBACK (on_control_stream_removed),
 
2721
                          manager);
 
2722
 
 
2723
        gvc_mixer_control_open (manager->priv->volume);
 
2724
 
 
2725
        gnome_settings_profile_end ("gvc_mixer_control_new");
 
2726
}
 
2727
 
 
2728
static void
 
2729
on_shell_proxy_ready (GObject      *source,
 
2730
                      GAsyncResult *result,
 
2731
                      gpointer      data)
 
2732
{
 
2733
        GsdMediaKeysManager *manager = data;
 
2734
 
 
2735
        manager->priv->shell_proxy =
 
2736
                g_dbus_proxy_new_for_bus_finish (result, NULL);
 
2737
}
 
2738
 
 
2739
static void
 
2740
on_key_grabber_ready (GObject      *source,
 
2741
                      GAsyncResult *result,
 
2742
                      gpointer      data)
 
2743
{
 
2744
        GsdMediaKeysManager *manager = data;
 
2745
 
 
2746
        manager->priv->key_grabber =
 
2747
                shell_key_grabber_proxy_new_for_bus_finish (result, NULL);
 
2748
 
 
2749
        if (!manager->priv->key_grabber)
 
2750
                return;
 
2751
 
 
2752
        g_signal_connect (manager->priv->key_grabber, "accelerator-activated",
 
2753
                          G_CALLBACK (on_accelerator_activated), manager);
 
2754
 
 
2755
        init_kbd (manager);
 
2756
}
 
2757
 
 
2758
static void
 
2759
on_shell_appeared (GDBusConnection   *connection,
 
2760
                   const char        *name,
 
2761
                   const char        *name_owner,
 
2762
                   gpointer           user_data)
 
2763
{
 
2764
        if (g_strcmp0 (g_getenv ("DESKTOP_SESSION"), "gnome") != 0)
 
2765
                return;
 
2766
 
 
2767
        GsdMediaKeysManager *manager = user_data;
 
2768
 
 
2769
        shell_key_grabber_proxy_new_for_bus (G_BUS_TYPE_SESSION,
 
2770
                                             0,
 
2771
                                             name_owner,
 
2772
                                             SHELL_DBUS_PATH,
 
2773
                                             manager->priv->grab_cancellable,
 
2774
                                             on_key_grabber_ready, manager);
 
2775
 
 
2776
        g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
 
2777
                                  0, NULL,
 
2778
                                  name_owner,
 
2779
                                  SHELL_DBUS_PATH,
 
2780
                                  SHELL_DBUS_NAME,
 
2781
                                  manager->priv->shell_cancellable,
 
2782
                                  on_shell_proxy_ready, manager);
 
2783
}
 
2784
 
 
2785
static void
 
2786
on_shell_vanished (GDBusConnection  *connection,
 
2787
                   const char       *name,
 
2788
                   gpointer          user_data)
 
2789
{
 
2790
        if (g_strcmp0 (g_getenv ("DESKTOP_SESSION"), "gnome") != 0)
 
2791
                return;
 
2792
 
 
2793
        GsdMediaKeysManager *manager = user_data;
 
2794
 
 
2795
        g_ptr_array_set_size (manager->priv->keys, 0);
 
2796
 
 
2797
        g_clear_object (&manager->priv->key_grabber);
 
2798
        g_clear_object (&manager->priv->shell_proxy);
 
2799
}
 
2800
 
 
2801
static void
 
2802
start_legacy_grabber (GDBusConnection   *connection,
 
2803
                      const char        *name,
 
2804
                      const char        *name_owner,
 
2805
                      gpointer           user_data)
 
2806
{
 
2807
        GsdMediaKeysManager *manager = user_data;
 
2808
        GSList *l;
 
2809
 
 
2810
        if (g_strcmp0 (g_getenv ("DESKTOP_SESSION"), "gnome") == 0)
 
2811
                return;
 
2812
 
 
2813
        manager->priv->have_legacy_keygrabber = TRUE;
 
2814
 
 
2815
        g_debug ("start_legacy_grabber");
 
2816
 
 
2817
        if (manager->priv->keys == NULL)
 
2818
                return;
 
2819
 
 
2820
        if (!name_owner)
 
2821
                return;
 
2822
 
 
2823
        init_screens (manager);
 
2824
        init_kbd (manager);
 
2825
 
 
2826
        /* Start filtering the events */
 
2827
        for (l = manager->priv->screens; l != NULL; l = l->next) {
 
2828
                gnome_settings_profile_start ("gdk_window_add_filter");
 
2829
 
 
2830
                g_debug ("adding key filter for screen: %d",
 
2831
                gdk_screen_get_number (l->data));
 
2832
 
 
2833
                gdk_window_add_filter (gdk_screen_get_root_window (l->data),
 
2834
                                       (GdkFilterFunc) filter_key_events,
 
2835
                                       manager);
 
2836
                gnome_settings_profile_end ("gdk_window_add_filter");
 
2837
        }
 
2838
}
 
2839
 
 
2840
static void
 
2841
stop_legacy_grabber (GDBusConnection  *connection,
 
2842
                     const char       *name,
 
2843
                     gpointer          user_data)
 
2844
{
 
2845
        GsdMediaKeysManager *manager = user_data;
 
2846
 
 
2847
        if (g_strcmp0 (g_getenv ("DESKTOP_SESSION"), "gnome") == 0)
 
2848
                return;
 
2849
 
 
2850
        manager->priv->have_legacy_keygrabber = FALSE;
 
2851
 
 
2852
        g_ptr_array_set_size (manager->priv->keys, 0);
 
2853
}
 
2854
 
 
2855
static gboolean
 
2856
start_media_keys_idle_cb (GsdMediaKeysManager *manager)
 
2857
{
 
2858
        char *theme_name;
 
2859
 
 
2860
        g_debug ("Starting media_keys manager");
 
2861
        gnome_settings_profile_start (NULL);
 
2862
 
 
2863
        manager->priv->keys = g_ptr_array_new_with_free_func ((GDestroyNotify) media_key_free);
 
2864
 
 
2865
        initialize_volume_handler (manager);
 
2866
 
 
2867
        manager->priv->settings = g_settings_new (SETTINGS_BINDING_DIR);
 
2868
        g_signal_connect (G_OBJECT (manager->priv->settings), "changed",
 
2869
                          G_CALLBACK (gsettings_changed_cb), manager);
 
2870
        g_signal_connect (G_OBJECT (manager->priv->settings), "changed::custom-keybindings",
 
2871
                          G_CALLBACK (gsettings_custom_changed_cb), manager);
 
2872
 
 
2873
        manager->priv->input_settings = g_settings_new (INPUT_SETTINGS_BINDING_DIR);
 
2874
        g_signal_connect (G_OBJECT (manager->priv->input_settings), "changed",
 
2875
                          G_CALLBACK (gsettings_changed_cb), manager);
 
2876
        g_signal_connect (G_OBJECT (manager->priv->input_settings), "changed::custom-keybindings",
 
2877
                          G_CALLBACK (gsettings_custom_changed_cb), manager);
 
2878
 
 
2879
        manager->priv->custom_settings =
 
2880
          g_hash_table_new_full (g_str_hash, g_str_equal,
 
2881
                                 g_free, g_object_unref);
 
2882
 
 
2883
        /* Sound events */
 
2884
        ca_context_create (&manager->priv->ca);
 
2885
        ca_context_set_driver (manager->priv->ca, "pulse");
 
2886
        ca_context_change_props (manager->priv->ca, 0,
 
2887
                                 CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl",
 
2888
                                 NULL);
 
2889
        manager->priv->gtksettings = gtk_settings_get_for_screen (gdk_screen_get_default ());
 
2890
        g_object_get (G_OBJECT (manager->priv->gtksettings), "gtk-sound-theme-name", &theme_name, NULL);
 
2891
        if (theme_name)
 
2892
                ca_context_change_props (manager->priv->ca, CA_PROP_CANBERRA_XDG_THEME_NAME, theme_name, NULL);
 
2893
        g_free (theme_name);
 
2894
        g_signal_connect (manager->priv->gtksettings, "notify::gtk-sound-theme-name",
 
2895
                          G_CALLBACK (sound_theme_changed), manager);
 
2896
 
 
2897
        /* for the power plugin interface code */
 
2898
        manager->priv->power_settings = g_settings_new (SETTINGS_POWER_DIR);
 
2899
 
 
2900
        /* Logic from http://git.gnome.org/browse/gnome-shell/tree/js/ui/status/accessibility.js#n163 */
 
2901
        manager->priv->interface_settings = g_settings_new (SETTINGS_INTERFACE_DIR);
 
2902
        g_signal_connect (G_OBJECT (manager->priv->interface_settings), "changed::gtk-theme",
 
2903
                          G_CALLBACK (update_theme_settings), manager);
 
2904
        g_signal_connect (G_OBJECT (manager->priv->interface_settings), "changed::icon-theme",
 
2905
                          G_CALLBACK (update_theme_settings), manager);
 
2906
        manager->priv->gtk_theme = g_settings_get_string (manager->priv->interface_settings, "gtk-theme");
 
2907
        if (g_str_equal (manager->priv->gtk_theme, HIGH_CONTRAST)) {
 
2908
                g_free (manager->priv->gtk_theme);
 
2909
                manager->priv->gtk_theme = NULL;
 
2910
        }
 
2911
        manager->priv->icon_theme = g_settings_get_string (manager->priv->interface_settings, "icon-theme");
 
2912
 
 
2913
 
 
2914
        ensure_cancellable (&manager->priv->grab_cancellable);
 
2915
        ensure_cancellable (&manager->priv->shell_cancellable);
 
2916
 
 
2917
        manager->priv->name_owner_id =
 
2918
                g_bus_watch_name (G_BUS_TYPE_SESSION,
 
2919
                                  SHELL_DBUS_NAME, 0,
 
2920
                                  on_shell_appeared,
 
2921
                                  on_shell_vanished,
 
2922
                                  manager, NULL);
 
2923
 
 
2924
        manager->priv->unity_name_owner_id =
 
2925
                g_bus_watch_name (G_BUS_TYPE_SESSION,
 
2926
                                  UNITY_DBUS_NAME, 0,
 
2927
                                  start_legacy_grabber,
 
2928
                                  stop_legacy_grabber,
 
2929
                                  manager, NULL);
 
2930
 
 
2931
        manager->priv->panel_name_owner_id =
 
2932
                g_bus_watch_name (G_BUS_TYPE_SESSION,
 
2933
                                  PANEL_DBUS_NAME, 0,
 
2934
                                  start_legacy_grabber,
 
2935
                                  stop_legacy_grabber,
 
2936
                                  manager, NULL);
 
2937
 
 
2938
        gnome_settings_profile_end (NULL);
 
2939
 
 
2940
        manager->priv->start_idle_id = 0;
 
2941
 
 
2942
        return FALSE;
 
2943
}
 
2944
 
 
2945
gboolean
 
2946
gsd_media_keys_manager_start (GsdMediaKeysManager *manager,
 
2947
                              GError             **error)
 
2948
{
 
2949
        const char * const subsystems[] = { "input", "usb", "sound", NULL };
 
2950
 
 
2951
        gnome_settings_profile_start (NULL);
 
2952
 
 
2953
        if (supports_xinput2_devices (&manager->priv->opcode) == FALSE) {
 
2954
                g_debug ("No Xinput2 support, disabling plugin");
 
2955
                return TRUE;
 
2956
        }
 
2957
 
 
2958
#ifdef HAVE_GUDEV
 
2959
        manager->priv->streams = g_hash_table_new (g_direct_hash, g_direct_equal);
 
2960
        manager->priv->udev_client = g_udev_client_new (subsystems);
 
2961
#endif
 
2962
 
 
2963
        manager->priv->start_idle_id = g_idle_add ((GSourceFunc) start_media_keys_idle_cb, manager);
 
2964
 
 
2965
        register_manager (manager_object);
 
2966
 
 
2967
        gnome_settings_profile_end (NULL);
 
2968
 
 
2969
        return TRUE;
 
2970
}
 
2971
 
 
2972
void
 
2973
gsd_media_keys_manager_stop (GsdMediaKeysManager *manager)
 
2974
{
 
2975
        GsdMediaKeysManagerPrivate *priv = manager->priv;
 
2976
        GSList *ls;
 
2977
        int i;
 
2978
 
 
2979
        g_debug ("Stopping media_keys manager");
 
2980
 
 
2981
        if (priv->bus_cancellable != NULL) {
 
2982
                g_cancellable_cancel (priv->bus_cancellable);
 
2983
                g_object_unref (priv->bus_cancellable);
 
2984
                priv->bus_cancellable = NULL;
 
2985
        }
 
2986
 
 
2987
        if (manager->priv->have_legacy_keygrabber){
 
2988
                for (ls = priv->screens; ls != NULL; ls = ls->next) {
 
2989
                        gdk_window_remove_filter (gdk_screen_get_root_window (ls->data),
 
2990
                                                 (GdkFilterFunc) filter_key_events,
 
2991
                                                  manager);
 
2992
                }
 
2993
        }
 
2994
 
 
2995
        if (manager->priv->gtksettings != NULL) {
 
2996
                g_signal_handlers_disconnect_by_func (manager->priv->gtksettings, sound_theme_changed, manager);
 
2997
                manager->priv->gtksettings = NULL;
 
2998
        }
 
2999
 
 
3000
        g_clear_pointer (&manager->priv->ca, ca_context_destroy);
 
3001
 
 
3002
#ifdef HAVE_GUDEV
 
3003
        g_clear_pointer (&priv->streams, g_hash_table_destroy);
 
3004
        g_clear_object (&priv->udev_client);
 
3005
#endif /* HAVE_GUDEV */
 
3006
 
 
3007
        g_clear_object (&priv->logind_proxy);
 
3008
        g_clear_object (&priv->settings);
 
3009
        g_clear_object (&priv->input_settings);
 
3010
        g_clear_object (&priv->power_settings);
 
3011
        g_clear_object (&priv->power_proxy);
 
3012
        g_clear_object (&priv->power_screen_proxy);
 
3013
        g_clear_object (&priv->power_keyboard_proxy);
 
3014
 
 
3015
        if (manager->priv->name_owner_id) {
 
3016
                g_bus_unwatch_name (manager->priv->name_owner_id);
 
3017
                manager->priv->name_owner_id = 0;
 
3018
        }
 
3019
 
 
3020
        if (manager->priv->unity_name_owner_id) {
 
3021
                g_bus_unwatch_name (manager->priv->unity_name_owner_id);
 
3022
                manager->priv->unity_name_owner_id = 0;
 
3023
        }
 
3024
 
 
3025
        if (manager->priv->panel_name_owner_id) {
 
3026
                g_bus_unwatch_name (manager->priv->panel_name_owner_id);
 
3027
                manager->priv->panel_name_owner_id = 0;
 
3028
        }
 
3029
 
 
3030
        if (priv->cancellable != NULL) {
 
3031
                g_cancellable_cancel (priv->cancellable);
 
3032
                g_clear_object (&priv->cancellable);
 
3033
        }
 
3034
 
 
3035
        g_clear_pointer (&priv->introspection_data, g_dbus_node_info_unref);
 
3036
        g_clear_object (&priv->connection);
 
3037
 
 
3038
        if (priv->volume_notification != NULL) {
 
3039
                notify_notification_close (priv->volume_notification, NULL);
 
3040
                g_object_unref (priv->volume_notification);
 
3041
                priv->volume_notification = NULL;
 
3042
        }
 
3043
 
 
3044
        if (priv->brightness_notification != NULL) {
 
3045
                notify_notification_close (priv->brightness_notification, NULL);
 
3046
                g_object_unref (priv->brightness_notification);
 
3047
                priv->brightness_notification = NULL;
 
3048
        }
 
3049
 
 
3050
        if (priv->kb_backlight_notification != NULL) {
 
3051
                notify_notification_close (priv->kb_backlight_notification, NULL);
 
3052
                g_object_unref (priv->kb_backlight_notification);
 
3053
                priv->kb_backlight_notification = NULL;
 
3054
        }
 
3055
 
 
3056
        if (priv->keys != NULL) {
 
3057
                if (manager->priv->have_legacy_keygrabber)
 
3058
                        gdk_error_trap_push ();
 
3059
                for (i = 0; i < priv->keys->len; ++i) {
 
3060
                        MediaKey *key;
 
3061
 
 
3062
                        key = g_ptr_array_index (manager->priv->keys, i);
 
3063
                        if (manager->priv->have_legacy_keygrabber && key->key)
 
3064
                                ungrab_key_unsafe (key->key, priv->screens);
 
3065
                        else
 
3066
                                ungrab_media_key (key, manager);
 
3067
                }
 
3068
                g_ptr_array_free (priv->keys, TRUE);
 
3069
                priv->keys = NULL;
 
3070
        }
 
3071
 
 
3072
        if (manager->priv->have_legacy_keygrabber){
 
3073
                gdk_flush ();
 
3074
                gdk_error_trap_pop_ignored ();
 
3075
        }
 
3076
 
 
3077
        if (priv->grab_cancellable != NULL) {
 
3078
                g_cancellable_cancel (priv->grab_cancellable);
 
3079
                g_clear_object (&priv->grab_cancellable);
 
3080
        }
 
3081
 
 
3082
        if (priv->shell_cancellable != NULL) {
 
3083
                g_cancellable_cancel (priv->shell_cancellable);
 
3084
                g_clear_object (&priv->shell_cancellable);
 
3085
        }
 
3086
 
 
3087
        g_clear_pointer (&priv->screens, g_slist_free);
 
3088
        g_clear_object (&priv->sink);
 
3089
        g_clear_object (&priv->source);
 
3090
        g_clear_object (&priv->volume);
 
3091
 
 
3092
        if (priv->media_players != NULL) {
 
3093
                g_list_free_full (priv->media_players, (GDestroyNotify) free_media_player);
 
3094
                priv->media_players = NULL;
 
3095
        }
 
3096
}
 
3097
 
 
3098
static GObject *
 
3099
gsd_media_keys_manager_constructor (GType                  type,
 
3100
                              guint                  n_construct_properties,
 
3101
                              GObjectConstructParam *construct_properties)
 
3102
{
 
3103
        GsdMediaKeysManager      *media_keys_manager;
 
3104
 
 
3105
        media_keys_manager = GSD_MEDIA_KEYS_MANAGER (G_OBJECT_CLASS (gsd_media_keys_manager_parent_class)->constructor (type,
 
3106
                                                                                                      n_construct_properties,
 
3107
                                                                                                      construct_properties));
 
3108
 
 
3109
        return G_OBJECT (media_keys_manager);
 
3110
}
 
3111
 
 
3112
static void
 
3113
gsd_media_keys_manager_class_init (GsdMediaKeysManagerClass *klass)
 
3114
{
 
3115
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
 
3116
 
 
3117
        object_class->constructor = gsd_media_keys_manager_constructor;
 
3118
        object_class->finalize = gsd_media_keys_manager_finalize;
 
3119
 
 
3120
        g_type_class_add_private (klass, sizeof (GsdMediaKeysManagerPrivate));
 
3121
}
 
3122
 
 
3123
static void
 
3124
inhibit_done (GObject      *source,
 
3125
              GAsyncResult *result,
 
3126
              gpointer      user_data)
 
3127
{
 
3128
        GDBusProxy *proxy = G_DBUS_PROXY (source);
 
3129
        GsdMediaKeysManager *manager = GSD_MEDIA_KEYS_MANAGER (user_data);
 
3130
        GError *error = NULL;
 
3131
        GVariant *res;
 
3132
        GUnixFDList *fd_list = NULL;
 
3133
        gint idx;
 
3134
 
 
3135
        res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error);
 
3136
        if (res == NULL) {
 
3137
                g_warning ("Unable to inhibit keypresses: %s", error->message);
 
3138
                g_error_free (error);
 
3139
        } else {
 
3140
                g_variant_get (res, "(h)", &idx);
 
3141
                manager->priv->inhibit_keys_fd = g_unix_fd_list_get (fd_list, idx, &error);
 
3142
                if (manager->priv->inhibit_keys_fd == -1) {
 
3143
                        g_warning ("Failed to receive system inhibitor fd: %s", error->message);
 
3144
                        g_error_free (error);
 
3145
                }
 
3146
                g_debug ("System inhibitor fd is %d", manager->priv->inhibit_keys_fd);
 
3147
                g_object_unref (fd_list);
 
3148
                g_variant_unref (res);
 
3149
        }
 
3150
}
 
3151
 
 
3152
static void
 
3153
gsd_media_keys_manager_init (GsdMediaKeysManager *manager)
 
3154
{
 
3155
        GError *error;
 
3156
        GDBusConnection *bus;
 
3157
 
 
3158
        error = NULL;
 
3159
        manager->priv = GSD_MEDIA_KEYS_MANAGER_GET_PRIVATE (manager);
 
3160
 
 
3161
        bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
 
3162
        if (bus == NULL) {
 
3163
                g_warning ("Failed to connect to system bus: %s",
 
3164
                           error->message);
 
3165
                g_error_free (error);
 
3166
                return;
 
3167
        }
 
3168
 
 
3169
        manager->priv->logind_proxy =
 
3170
                g_dbus_proxy_new_sync (bus,
 
3171
                                       0,
 
3172
                                       NULL,
 
3173
                                       SYSTEMD_DBUS_NAME,
 
3174
                                       SYSTEMD_DBUS_PATH,
 
3175
                                       SYSTEMD_DBUS_INTERFACE,
 
3176
                                       NULL,
 
3177
                                       &error);
 
3178
 
 
3179
        if (manager->priv->logind_proxy == NULL) {
 
3180
                g_warning ("Failed to connect to systemd: %s",
 
3181
                           error->message);
 
3182
                g_error_free (error);
 
3183
        }
 
3184
 
 
3185
        g_object_unref (bus);
 
3186
 
 
3187
        g_debug ("Adding system inhibitors for power keys");
 
3188
        manager->priv->inhibit_keys_fd = -1;
 
3189
        g_dbus_proxy_call_with_unix_fd_list (manager->priv->logind_proxy,
 
3190
                                             "Inhibit",
 
3191
                                             g_variant_new ("(ssss)",
 
3192
                                                            "handle-power-key:handle-suspend-key:handle-hibernate-key",
 
3193
                                                            g_get_user_name (),
 
3194
                                                            "GNOME handling keypresses",
 
3195
                                                            "block"),
 
3196
                                             0,
 
3197
                                             G_MAXINT,
 
3198
                                             NULL,
 
3199
                                             NULL,
 
3200
                                             inhibit_done,
 
3201
                                             manager);
 
3202
 
 
3203
}
 
3204
 
 
3205
static void
 
3206
gsd_media_keys_manager_finalize (GObject *object)
 
3207
{
 
3208
        GsdMediaKeysManager *media_keys_manager;
 
3209
 
 
3210
        g_return_if_fail (object != NULL);
 
3211
        g_return_if_fail (GSD_IS_MEDIA_KEYS_MANAGER (object));
 
3212
 
 
3213
        media_keys_manager = GSD_MEDIA_KEYS_MANAGER (object);
 
3214
 
 
3215
        g_return_if_fail (media_keys_manager->priv != NULL);
 
3216
 
 
3217
        if (media_keys_manager->priv->start_idle_id != 0)
 
3218
                g_source_remove (media_keys_manager->priv->start_idle_id);
 
3219
        if (media_keys_manager->priv->inhibit_keys_fd != -1)
 
3220
                close (media_keys_manager->priv->inhibit_keys_fd);
 
3221
 
 
3222
        G_OBJECT_CLASS (gsd_media_keys_manager_parent_class)->finalize (object);
 
3223
}
 
3224
 
 
3225
static void
 
3226
xrandr_ready_cb (GObject             *source_object,
 
3227
                 GAsyncResult        *res,
 
3228
                 GsdMediaKeysManager *manager)
 
3229
{
 
3230
        GError *error = NULL;
 
3231
 
 
3232
        manager->priv->xrandr_proxy = g_dbus_proxy_new_finish (res, &error);
 
3233
        if (manager->priv->xrandr_proxy == NULL) {
 
3234
                g_warning ("Failed to get proxy for XRandR operations: %s", error->message);
 
3235
                g_error_free (error);
 
3236
        }
 
3237
}
 
3238
 
 
3239
static void
 
3240
power_ready_cb (GObject             *source_object,
 
3241
                GAsyncResult        *res,
 
3242
                GsdMediaKeysManager *manager)
 
3243
{
 
3244
        GError *error = NULL;
 
3245
 
 
3246
        manager->priv->power_proxy = g_dbus_proxy_new_finish (res, &error);
 
3247
        if (manager->priv->power_proxy == NULL) {
 
3248
                g_warning ("Failed to get proxy for power: %s",
 
3249
                           error->message);
 
3250
                g_error_free (error);
 
3251
        }
 
3252
}
 
3253
 
 
3254
static void
 
3255
power_screen_ready_cb (GObject             *source_object,
 
3256
                       GAsyncResult        *res,
 
3257
                       GsdMediaKeysManager *manager)
 
3258
{
 
3259
        GError *error = NULL;
 
3260
 
 
3261
        manager->priv->power_screen_proxy = g_dbus_proxy_new_finish (res, &error);
 
3262
        if (manager->priv->power_screen_proxy == NULL) {
 
3263
                g_warning ("Failed to get proxy for power (screen): %s",
 
3264
                           error->message);
 
3265
                g_error_free (error);
 
3266
        }
 
3267
}
 
3268
 
 
3269
static void
 
3270
power_keyboard_ready_cb (GObject             *source_object,
 
3271
                         GAsyncResult        *res,
 
3272
                         GsdMediaKeysManager *manager)
 
3273
{
 
3274
        GError *error = NULL;
 
3275
 
 
3276
        manager->priv->power_keyboard_proxy = g_dbus_proxy_new_finish (res, &error);
 
3277
        if (manager->priv->power_keyboard_proxy == NULL) {
 
3278
                g_warning ("Failed to get proxy for power (keyboard): %s",
 
3279
                           error->message);
 
3280
                g_error_free (error);
 
3281
        }
 
3282
}
 
3283
 
 
3284
static void
 
3285
on_bus_gotten (GObject             *source_object,
 
3286
               GAsyncResult        *res,
 
3287
               GsdMediaKeysManager *manager)
 
3288
{
 
3289
        GDBusConnection *connection;
 
3290
        GError *error = NULL;
 
3291
 
 
3292
        if (manager->priv->bus_cancellable == NULL ||
 
3293
            g_cancellable_is_cancelled (manager->priv->bus_cancellable)) {
 
3294
                g_warning ("Operation has been cancelled, so not retrieving session bus");
 
3295
                return;
 
3296
        }
 
3297
 
 
3298
        connection = g_bus_get_finish (res, &error);
 
3299
        if (connection == NULL) {
 
3300
                g_warning ("Could not get session bus: %s", error->message);
 
3301
                g_error_free (error);
 
3302
                return;
 
3303
        }
 
3304
        manager->priv->connection = connection;
 
3305
 
 
3306
        g_dbus_connection_register_object (connection,
 
3307
                                           GSD_MEDIA_KEYS_DBUS_PATH,
 
3308
                                           manager->priv->introspection_data->interfaces[0],
 
3309
                                           &interface_vtable,
 
3310
                                           manager,
 
3311
                                           NULL,
 
3312
                                           NULL);
 
3313
 
 
3314
        g_dbus_proxy_new (manager->priv->connection,
 
3315
                          G_DBUS_PROXY_FLAGS_NONE,
 
3316
                          NULL,
 
3317
                          GSD_DBUS_NAME ".XRANDR",
 
3318
                          GSD_DBUS_PATH "/XRANDR",
 
3319
                          GSD_DBUS_BASE_INTERFACE ".XRANDR_2",
 
3320
                          NULL,
 
3321
                          (GAsyncReadyCallback) xrandr_ready_cb,
 
3322
                          manager);
 
3323
 
 
3324
        g_dbus_proxy_new (manager->priv->connection,
 
3325
                          G_DBUS_PROXY_FLAGS_NONE,
 
3326
                          NULL,
 
3327
                          GSD_DBUS_NAME ".Power",
 
3328
                          GSD_DBUS_PATH "/Power",
 
3329
                          GSD_DBUS_BASE_INTERFACE ".Power",
 
3330
                          NULL,
 
3331
                          (GAsyncReadyCallback) power_ready_cb,
 
3332
                          manager);
 
3333
 
 
3334
        g_dbus_proxy_new (manager->priv->connection,
 
3335
                          G_DBUS_PROXY_FLAGS_NONE,
 
3336
                          NULL,
 
3337
                          GSD_DBUS_NAME ".Power",
 
3338
                          GSD_DBUS_PATH "/Power",
 
3339
                          GSD_DBUS_BASE_INTERFACE ".Power.Screen",
 
3340
                          NULL,
 
3341
                          (GAsyncReadyCallback) power_screen_ready_cb,
 
3342
                          manager);
 
3343
 
 
3344
        g_dbus_proxy_new (manager->priv->connection,
 
3345
                          G_DBUS_PROXY_FLAGS_NONE,
 
3346
                          NULL,
 
3347
                          GSD_DBUS_NAME ".Power",
 
3348
                          GSD_DBUS_PATH "/Power",
 
3349
                          GSD_DBUS_BASE_INTERFACE ".Power.Keyboard",
 
3350
                          NULL,
 
3351
                          (GAsyncReadyCallback) power_keyboard_ready_cb,
 
3352
                          manager);
 
3353
}
 
3354
 
 
3355
static void
 
3356
register_manager (GsdMediaKeysManager *manager)
 
3357
{
 
3358
        manager->priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
 
3359
        manager->priv->bus_cancellable = g_cancellable_new ();
 
3360
        g_assert (manager->priv->introspection_data != NULL);
 
3361
 
 
3362
        g_bus_get (G_BUS_TYPE_SESSION,
 
3363
                   manager->priv->bus_cancellable,
 
3364
                   (GAsyncReadyCallback) on_bus_gotten,
 
3365
                   manager);
 
3366
}
 
3367
 
 
3368
GsdMediaKeysManager *
 
3369
gsd_media_keys_manager_new (void)
 
3370
{
 
3371
        if (manager_object != NULL) {
 
3372
                g_object_ref (manager_object);
 
3373
        } else {
 
3374
                manager_object = g_object_new (GSD_TYPE_MEDIA_KEYS_MANAGER, NULL);
 
3375
                g_object_add_weak_pointer (manager_object,
 
3376
                                           (gpointer *) &manager_object);
 
3377
        }
 
3378
 
 
3379
        return GSD_MEDIA_KEYS_MANAGER (manager_object);
 
3380
}