Merge lp:~jm-leddy/ubuntu/precise/gnome-settings-daemon/micmute into lp:ubuntu/precise/gnome-settings-daemon

Proposed by James M. Leddy
Status: Superseded
Proposed branch: lp:~jm-leddy/ubuntu/precise/gnome-settings-daemon/micmute
Merge into: lp:ubuntu/precise/gnome-settings-daemon
Diff against target: 34350 lines (+22355/-4853)
103 files modified
.pc/05_disable_corner_tapping.patch/plugins/mouse/gsd-mouse-manager.c (+15/-3)
.pc/10_smaller_syndaemon_timeout.patch/plugins/mouse/gsd-mouse-manager.c (+15/-3)
.pc/16_use_synchronous_notifications.patch/configure.ac (+1/-1)
.pc/16_use_synchronous_notifications.patch/plugins/media-keys/gsd-media-keys-manager.c (+62/-1)
.pc/47_delay_pa_connect_to_idle.patch/plugins/media-keys/gsd-media-keys-manager.c (+62/-1)
.pc/61_unity_use_application_indicator.patch/configure.ac (+1/-1)
.pc/64_micmute.patch/plugins/media-keys/gsd-media-keys-manager.c (+2743/-0)
.pc/64_micmute.patch/plugins/media-keys/shortcuts-list.h (+152/-0)
.pc/applied-patches (+10/-1)
.pc/correct_logout_action.patch/plugins/media-keys/gsd-media-keys-manager.c (+62/-1)
.pc/disable_three_touch_tap.patch/plugins/mouse/gsd-mouse-manager.c (+16/-4)
.pc/dont_overwrite_gconf_keys.patch/plugins/gconf/conf-watcher.c (+150/-0)
.pc/git-mask-out-virtual-modifiers.patch/plugins/common/gsd-keygrab.c (+433/-0)
.pc/git-smartcard-crash.patch/plugins/smartcard/gsd-smartcard-manager.c (+1515/-0)
.pc/git_keyring_environment.patch/plugins/media-keys/gsd-media-keys-manager.c (+0/-2682)
.pc/git_new_xinput_handle.patch/plugins/common/gsd-input-helper.c (+507/-0)
.pc/git_no_numlock_eating_cpu_loop.patch/plugins/keyboard/gsd-keyboard-manager.c (+495/-0)
.pc/git_xrandr_explicitly_set_clone_state.patch/plugins/xrandr/gsd-xrandr-manager.c (+2226/-0)
.pc/power-check-null-devices.patch/plugins/power/gsd-power-manager.c (+4262/-0)
.pc/power-ignore-bad-dbus-requests.patch/plugins/power/gsd-power-manager.c (+4262/-0)
.pc/revert_git_datetime_dropping.patch/configure.ac (+1/-1)
.pc/revert_git_dropping_gconf_wrapper.patch/configure.ac (+1/-1)
.pc/revert_git_stop_using_gconf.patch/configure.ac (+1/-1)
.pc/revert_git_use_gsetting_keybindings.patch/configure.ac (+1/-1)
.pc/revert_git_use_gsetting_keybindings.patch/plugins/media-keys/gsd-media-keys-manager.c (+62/-1)
.pc/xsettings_signal_handling.patch/plugins/xsettings/gsd-xsettings-gtk.c (+384/-0)
.pc/xsettings_signal_handling.patch/plugins/xsettings/gsd-xsettings-manager.c (+1090/-0)
Makefile.in (+54/-26)
NEWS (+13/-0)
aclocal.m4 (+353/-120)
compile (+183/-16)
config.guess (+136/-115)
config.sub (+125/-64)
configure (+239/-134)
configure.ac (+1/-1)
data/Makefile.in (+34/-29)
debian/changelog (+103/-0)
debian/control (+1/-2)
debian/control.in (+1/-1)
debian/patches/10_smaller_syndaemon_timeout.patch (+14/-5)
debian/patches/64_micmute.patch (+291/-0)
debian/patches/bugzilla_segfault_dpms.patch (+6/-7)
debian/patches/correct_logout_action.patch (+6/-5)
debian/patches/dont_overwrite_gconf_keys.patch (+54/-0)
debian/patches/git-mask-out-virtual-modifiers.patch (+47/-0)
debian/patches/git-smartcard-crash.patch (+38/-0)
debian/patches/git_keyring_environment.patch (+0/-105)
debian/patches/git_new_xinput_handle.patch (+41/-0)
debian/patches/git_no_numlock_eating_cpu_loop.patch (+62/-0)
debian/patches/git_xrandr_explicitly_set_clone_state.patch (+63/-0)
debian/patches/power-check-null-devices.patch (+13/-0)
debian/patches/power-ignore-bad-dbus-requests.patch (+30/-0)
debian/patches/power-no-fallback-notifications.patch (+3/-3)
debian/patches/revert_git_a11y_gsettings.patch (+3/-3)
debian/patches/revert_git_dropping_gconf_wrapper.patch (+28/-28)
debian/patches/revert_git_stop_using_gconf.patch (+3/-3)
debian/patches/revert_git_use_gsetting_keybindings.patch (+27/-27)
debian/patches/series (+10/-1)
debian/patches/xsettings_signal_handling.patch (+52/-0)
depcomp (+66/-8)
gnome-settings-daemon/Makefile.in (+67/-67)
install-sh (+18/-11)
ltmain.sh (+57/-38)
missing (+4/-49)
plugins/Makefile.in (+22/-11)
plugins/a11y-keyboard/Makefile.in (+58/-55)
plugins/a11y-settings/Makefile.in (+46/-36)
plugins/automount/Makefile.in (+54/-48)
plugins/background/Makefile.in (+55/-49)
plugins/clipboard/Makefile.in (+50/-42)
plugins/color/Makefile.in (+72/-70)
plugins/common/Makefile.in (+56/-50)
plugins/common/gsd-input-helper.c (+17/-8)
plugins/common/gsd-keygrab.c (+2/-0)
plugins/cursor/Makefile.in (+46/-36)
plugins/dummy/Makefile.in (+46/-36)
plugins/gconf/conf-watcher.c (+22/-0)
plugins/housekeeping/Makefile.in (+76/-80)
plugins/housekeeping/gsd-disk-space.c (+1/-1)
plugins/keyboard/Makefile.in (+51/-45)
plugins/keyboard/gsd-keyboard-manager.c (+11/-6)
plugins/media-keys/Makefile.in (+86/-95)
plugins/media-keys/cut-n-paste/Makefile.in (+35/-27)
plugins/media-keys/gsd-media-keys-manager.c (+130/-16)
plugins/media-keys/shortcuts-list.h (+2/-0)
plugins/mouse/Makefile.in (+55/-49)
plugins/mouse/gsd-mouse-manager.c (+16/-4)
plugins/orientation/Makefile.in (+55/-49)
plugins/power/Makefile.in (+58/-55)
plugins/power/gsd-power-manager.c (+13/-1)
plugins/print-notifications/Makefile.in (+60/-56)
plugins/smartcard/Makefile.in (+48/-39)
plugins/smartcard/gsd-smartcard-manager.c (+4/-4)
plugins/sound/Makefile.in (+46/-36)
plugins/updates/Makefile.in (+51/-45)
plugins/wacom/Makefile.in (+76/-81)
plugins/xrandr/Makefile.in (+46/-36)
plugins/xrandr/gsd-xrandr-manager.c (+8/-0)
plugins/xsettings/Makefile.in (+88/-98)
plugins/xsettings/gsd-xsettings-gtk.c (+1/-2)
plugins/xsettings/gsd-xsettings-manager.c (+2/-4)
po/Makefile.in.in (+9/-4)
po/it.po (+6/-8)
To merge this branch: bzr merge lp:~jm-leddy/ubuntu/precise/gnome-settings-daemon/micmute
Reviewer Review Type Date Requested Status
Ubuntu branches Pending
Review via email: mp+188633@code.launchpad.net

This proposal has been superseded by a proposal from 2013-10-01.

To post a comment you must log in.

Unmerged revisions

226. By James M. Leddy on 2013-06-01

* debian/patches/64_micmute.patch:
  - put the mic mute key used on thinkpad laptops to good use
    (lp: #408903)

225. By Ritesh Khadgaray on 2013-01-10

* debian/patches/git-smartcard-crash.patch:
  - gnome-settings-daemon segfaults when using smartcard authentication
    (lp: #1031034)

224. By Sebastien Bacher on 2012-12-04

* debian/patches/git_new_xinput_handle.patch:
  - deal with new xinput versions, that will be need for the hardware
    enablement work, and the updated xorg stack, once it runs on the lts
    (lp: #1034090)

223. By Sebastien Bacher on 2012-11-12

* debian/patches/git_no_numlock_eating_cpu_loop.patch:
  - backport upstream fix for "numlock keeps changing state and
    gnome-settings-daemon is eating 100% cpu while that's happening"
    (lp: #969359)

222. By Sebastien Bacher on 2012-10-30

* debian/patches/dont_overwrite_gconf_keys.patch:
  - don't trigger the gsettings->gconf keys conversion on "dconf update"
    runs, thanks Margarita Manterola for the fix and testing
    (lp: #1071950)

221. By Mathieu Trudel-Lapierre on 2012-07-10

debian/patches/series: properly enable git-mask-out-virtual-modifiers.patch
so that the patch can really fix the grabbing issue with virtual modifiers.
(LP: #950160)

220. By Mathieu Trudel-Lapierre on 2012-06-28

[ Keng-Yu Lin ]
* debian/patches/git-mask-out-virtual-modifiers.patch
  - patch from upstream git, fix the grabbing issue of the
    keyboard shortcut with virtual (Super, Hyper, Meta) modifier.
    (lp: #950160)

219. By Sebastien Bacher on 2012-06-18

* Upload to precise-proposed

[ Chris Coulson ]
* debian/patches/10_smaller_syndaemon_timeout.patch: Update to increase
  the size of the stack allocated array for the extra argument passed to
  syndaemon. This fixes a crash in the PLT due to a corrupt %ebx register
  (which holds the GOT base address on i386), which was caused in an earlier
  function by writing zero in to the location on the stack where the value of
  %ebx is saved. Thanks to Sebastien Bacher for spotting the buggy patch!
  (fixes LP: #1007588)

[ Hsin-Yi, Chen (hychen) ]
* debian/patches/git_xrandr_explicitly_set_clone_state.patch:
  - "xrandr; explicitly set clone state variable when generating monitor
     configs" (LP: #1014533)

218. By Sebastien Bacher on 2012-05-23

* New upstream version
* debian/patches/git_keyring_environment.patch:
  - dropped, the fix is in the new version
* debian/patches/xsettings_signal_handling.patch:
  - upstream bugzilla patch, fix segfaults in the xsettings code which
    seem to happen at logout (lp: #946295, #948347, #963704)

217. By Michael Terry on 2012-05-01

* debian/patches/power-check-null-devices.patch:
  - NULL-guard the return value of up_client_get_devices.
    LP: #868928
* debian/patches/power-ignore-bad-dbus-requests.patch:
  - If we get a DBus request while the manager isn't active, ignore it.
    LP: #969535

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.pc/05_disable_corner_tapping.patch/plugins/mouse/gsd-mouse-manager.c'
2--- .pc/05_disable_corner_tapping.patch/plugins/mouse/gsd-mouse-manager.c 2012-04-16 15:55:26 +0000
3+++ .pc/05_disable_corner_tapping.patch/plugins/mouse/gsd-mouse-manager.c 2013-10-01 15:38:46 +0000
4@@ -317,8 +317,6 @@
5 gint n_buttons;
6 const char *name;
7
8- buttons = g_new (guchar, buttons_capacity);
9-
10 name = gdk_device_get_name (device);
11 if (name != NULL && g_str_equal ("Virtual core XTEST pointer", name))
12 return;
13@@ -329,6 +327,8 @@
14 if (xdevice == NULL)
15 return;
16
17+ buttons = g_new (guchar, buttons_capacity);
18+
19 /* If the device is a touchpad, swap tap buttons
20 * around too, otherwise a tap would be a right-click */
21 if (device_is_touchpad (xdevice)) {
22@@ -515,6 +515,18 @@
23 #endif
24 }
25
26+static gboolean
27+have_program_in_path (const char *name)
28+{
29+ gchar *path;
30+ gboolean result;
31+
32+ path = g_find_program_in_path (name);
33+ result = (path != NULL);
34+ g_free (path);
35+ return result;
36+}
37+
38 static void
39 syndaemon_died (GPid pid, gint status, gpointer user_data)
40 {
41@@ -542,7 +554,7 @@
42 args[4] = "-R";
43 args[5] = NULL;
44
45- if (!g_find_program_in_path (args[0]))
46+ if (!have_program_in_path (args[0]))
47 return 0;
48
49 /* we must use G_SPAWN_DO_NOT_REAP_CHILD to avoid
50
51=== modified file '.pc/10_smaller_syndaemon_timeout.patch/plugins/mouse/gsd-mouse-manager.c'
52--- .pc/10_smaller_syndaemon_timeout.patch/plugins/mouse/gsd-mouse-manager.c 2012-04-16 15:55:26 +0000
53+++ .pc/10_smaller_syndaemon_timeout.patch/plugins/mouse/gsd-mouse-manager.c 2013-10-01 15:38:46 +0000
54@@ -317,8 +317,6 @@
55 gint n_buttons;
56 const char *name;
57
58- buttons = g_new (guchar, buttons_capacity);
59-
60 name = gdk_device_get_name (device);
61 if (name != NULL && g_str_equal ("Virtual core XTEST pointer", name))
62 return;
63@@ -329,6 +327,8 @@
64 if (xdevice == NULL)
65 return;
66
67+ buttons = g_new (guchar, buttons_capacity);
68+
69 /* If the device is a touchpad, swap tap buttons
70 * around too, otherwise a tap would be a right-click */
71 if (device_is_touchpad (xdevice)) {
72@@ -515,6 +515,18 @@
73 #endif
74 }
75
76+static gboolean
77+have_program_in_path (const char *name)
78+{
79+ gchar *path;
80+ gboolean result;
81+
82+ path = g_find_program_in_path (name);
83+ result = (path != NULL);
84+ g_free (path);
85+ return result;
86+}
87+
88 static void
89 syndaemon_died (GPid pid, gint status, gpointer user_data)
90 {
91@@ -542,7 +554,7 @@
92 args[4] = "-R";
93 args[5] = NULL;
94
95- if (!g_find_program_in_path (args[0]))
96+ if (!have_program_in_path (args[0]))
97 return 0;
98
99 /* we must use G_SPAWN_DO_NOT_REAP_CHILD to avoid
100
101=== modified file '.pc/16_use_synchronous_notifications.patch/configure.ac'
102--- .pc/16_use_synchronous_notifications.patch/configure.ac 2012-04-16 15:55:26 +0000
103+++ .pc/16_use_synchronous_notifications.patch/configure.ac 2013-10-01 15:38:46 +0000
104@@ -1,7 +1,7 @@
105 AC_PREREQ([2.60])
106
107 AC_INIT([gnome-settings-daemon],
108- [3.4.1],
109+ [3.4.2],
110 [http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-settings-daemon])
111
112 AC_CONFIG_SRCDIR([gnome-settings-daemon/gnome-settings-manager.c])
113
114=== modified file '.pc/16_use_synchronous_notifications.patch/plugins/media-keys/gsd-media-keys-manager.c'
115--- .pc/16_use_synchronous_notifications.patch/plugins/media-keys/gsd-media-keys-manager.c 2012-03-19 18:57:50 +0000
116+++ .pc/16_use_synchronous_notifications.patch/plugins/media-keys/gsd-media-keys-manager.c 2013-10-01 15:38:46 +0000
117@@ -66,6 +66,10 @@
118 #define GNOME_SESSION_DBUS_PATH "/org/gnome/SessionManager"
119 #define GNOME_SESSION_DBUS_INTERFACE "org.gnome.SessionManager"
120
121+#define GNOME_KEYRING_DBUS_NAME "org.gnome.keyring"
122+#define GNOME_KEYRING_DBUS_PATH "/org/gnome/keyring/daemon"
123+#define GNOME_KEYRING_DBUS_INTERFACE "org.gnome.keyring.Daemon"
124+
125 #define CUSTOM_BINDING_SCHEMA SETTINGS_BINDING_DIR ".custom-keybinding"
126
127 static const gchar introspection_xml[] =
128@@ -228,6 +232,57 @@
129 return cmd;
130 }
131
132+static char **
133+get_keyring_env (GsdMediaKeysManager *manager)
134+{
135+ GError *error = NULL;
136+ GVariant *variant, *item;
137+ GVariantIter *iter;
138+ char **envp;
139+
140+ variant = g_dbus_connection_call_sync (manager->priv->connection,
141+ GNOME_KEYRING_DBUS_NAME,
142+ GNOME_KEYRING_DBUS_PATH,
143+ GNOME_KEYRING_DBUS_INTERFACE,
144+ "GetEnvironment",
145+ NULL,
146+ NULL,
147+ G_DBUS_CALL_FLAGS_NONE,
148+ -1,
149+ NULL,
150+ &error);
151+ if (variant == NULL) {
152+ g_warning ("Failed to call GetEnvironment on keyring daemon: %s", error->message);
153+ g_error_free (error);
154+ return NULL;
155+ }
156+
157+ envp = g_get_environ ();
158+
159+ g_variant_get (variant, "(a{ss})", &iter);
160+
161+ while ((item = g_variant_iter_next_value (iter))) {
162+ char *key;
163+ char *value;
164+
165+ g_variant_get (item,
166+ "{ss}",
167+ &key,
168+ &value);
169+
170+ envp = g_environ_setenv (envp, key, value, TRUE);
171+
172+ g_variant_unref (item);
173+ g_free (key);
174+ g_free (value);
175+ }
176+
177+ g_variant_iter_free (iter);
178+ g_variant_unref (variant);
179+
180+ return envp;
181+}
182+
183 static void
184 execute (GsdMediaKeysManager *manager,
185 char *cmd,
186@@ -253,15 +308,21 @@
187 }
188
189 if (g_shell_parse_argv (exec, &argc, &argv, NULL)) {
190+ char **envp;
191+
192+ envp = get_keyring_env (manager);
193+
194 retval = g_spawn_async (g_get_home_dir (),
195 argv,
196- NULL,
197+ envp,
198 G_SPAWN_SEARCH_PATH,
199 NULL,
200 NULL,
201 NULL,
202 &error);
203+
204 g_strfreev (argv);
205+ g_strfreev (envp);
206 }
207
208 if (retval == FALSE) {
209
210=== modified file '.pc/47_delay_pa_connect_to_idle.patch/plugins/media-keys/gsd-media-keys-manager.c'
211--- .pc/47_delay_pa_connect_to_idle.patch/plugins/media-keys/gsd-media-keys-manager.c 2012-03-29 21:43:49 +0000
212+++ .pc/47_delay_pa_connect_to_idle.patch/plugins/media-keys/gsd-media-keys-manager.c 2013-10-01 15:38:46 +0000
213@@ -68,6 +68,10 @@
214 #define GNOME_SESSION_DBUS_PATH "/org/gnome/SessionManager"
215 #define GNOME_SESSION_DBUS_INTERFACE "org.gnome.SessionManager"
216
217+#define GNOME_KEYRING_DBUS_NAME "org.gnome.keyring"
218+#define GNOME_KEYRING_DBUS_PATH "/org/gnome/keyring/daemon"
219+#define GNOME_KEYRING_DBUS_INTERFACE "org.gnome.keyring.Daemon"
220+
221 #define CUSTOM_BINDING_SCHEMA SETTINGS_BINDING_DIR ".custom-keybinding"
222
223 static const gchar introspection_xml[] =
224@@ -361,6 +365,57 @@
225 return cmd;
226 }
227
228+static char **
229+get_keyring_env (GsdMediaKeysManager *manager)
230+{
231+ GError *error = NULL;
232+ GVariant *variant, *item;
233+ GVariantIter *iter;
234+ char **envp;
235+
236+ variant = g_dbus_connection_call_sync (manager->priv->connection,
237+ GNOME_KEYRING_DBUS_NAME,
238+ GNOME_KEYRING_DBUS_PATH,
239+ GNOME_KEYRING_DBUS_INTERFACE,
240+ "GetEnvironment",
241+ NULL,
242+ NULL,
243+ G_DBUS_CALL_FLAGS_NONE,
244+ -1,
245+ NULL,
246+ &error);
247+ if (variant == NULL) {
248+ g_warning ("Failed to call GetEnvironment on keyring daemon: %s", error->message);
249+ g_error_free (error);
250+ return NULL;
251+ }
252+
253+ envp = g_get_environ ();
254+
255+ g_variant_get (variant, "(a{ss})", &iter);
256+
257+ while ((item = g_variant_iter_next_value (iter))) {
258+ char *key;
259+ char *value;
260+
261+ g_variant_get (item,
262+ "{ss}",
263+ &key,
264+ &value);
265+
266+ envp = g_environ_setenv (envp, key, value, TRUE);
267+
268+ g_variant_unref (item);
269+ g_free (key);
270+ g_free (value);
271+ }
272+
273+ g_variant_iter_free (iter);
274+ g_variant_unref (variant);
275+
276+ return envp;
277+}
278+
279 static void
280 execute (GsdMediaKeysManager *manager,
281 char *cmd,
282@@ -386,15 +441,21 @@
283 }
284
285 if (g_shell_parse_argv (exec, &argc, &argv, NULL)) {
286+ char **envp;
287+
288+ envp = get_keyring_env (manager);
289+
290 retval = g_spawn_async (g_get_home_dir (),
291 argv,
292- NULL,
293+ envp,
294 G_SPAWN_SEARCH_PATH,
295 NULL,
296 NULL,
297 NULL,
298 &error);
299+
300 g_strfreev (argv);
301+ g_strfreev (envp);
302 }
303
304 if (retval == FALSE) {
305
306=== modified file '.pc/61_unity_use_application_indicator.patch/configure.ac'
307--- .pc/61_unity_use_application_indicator.patch/configure.ac 2012-04-16 15:55:26 +0000
308+++ .pc/61_unity_use_application_indicator.patch/configure.ac 2013-10-01 15:38:46 +0000
309@@ -1,7 +1,7 @@
310 AC_PREREQ([2.60])
311
312 AC_INIT([gnome-settings-daemon],
313- [3.4.1],
314+ [3.4.2],
315 [http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-settings-daemon])
316
317 AC_CONFIG_SRCDIR([gnome-settings-daemon/gnome-settings-manager.c])
318
319=== added directory '.pc/64_micmute.patch'
320=== added file '.pc/64_micmute.patch/.timestamp'
321=== added directory '.pc/64_micmute.patch/plugins'
322=== added directory '.pc/64_micmute.patch/plugins/media-keys'
323=== added file '.pc/64_micmute.patch/plugins/media-keys/gsd-media-keys-manager.c'
324--- .pc/64_micmute.patch/plugins/media-keys/gsd-media-keys-manager.c 1970-01-01 00:00:00 +0000
325+++ .pc/64_micmute.patch/plugins/media-keys/gsd-media-keys-manager.c 2013-10-01 15:38:46 +0000
326@@ -0,0 +1,2743 @@
327+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
328+ *
329+ * Copyright (C) 2001-2003 Bastien Nocera <hadess@hadess.net>
330+ * Copyright (C) 2006-2007 William Jon McCann <mccann@jhu.edu>
331+ *
332+ * This program is free software; you can redistribute it and/or modify
333+ * it under the terms of the GNU General Public License as published by
334+ * the Free Software Foundation; either version 2 of the License, or
335+ * (at your option) any later version.
336+ *
337+ * This program is distributed in the hope that it will be useful,
338+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
339+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
340+ * GNU General Public License for more details.
341+ *
342+ * You should have received a copy of the GNU General Public License
343+ * along with this program; if not, write to the Free Software
344+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
345+ *
346+ */
347+
348+#include "config.h"
349+
350+#include <sys/types.h>
351+#include <sys/wait.h>
352+#include <stdlib.h>
353+#include <stdio.h>
354+#include <unistd.h>
355+#include <string.h>
356+#include <errno.h>
357+#include <math.h>
358+
359+#include <locale.h>
360+
361+#include <glib.h>
362+#include <glib/gi18n.h>
363+#include <gio/gio.h>
364+#include <gdk/gdk.h>
365+#include <gdk/gdkx.h>
366+#include <gtk/gtk.h>
367+#include <gio/gdesktopappinfo.h>
368+#include <gconf/gconf-client.h>
369+
370+#ifdef HAVE_GUDEV
371+#include <gudev/gudev.h>
372+#endif
373+
374+#include "gnome-settings-profile.h"
375+#include "gsd-marshal.h"
376+#include "gsd-media-keys-manager.h"
377+
378+#include "shortcuts-list.h"
379+#include "gsd-media-keys-window.h"
380+#include "gsd-input-helper.h"
381+#include "gsd-enums.h"
382+
383+#include <canberra.h>
384+#include <pulse/pulseaudio.h>
385+#include "gvc-mixer-control.h"
386+
387+#include <libnotify/notify.h>
388+
389+#define GSD_DBUS_PATH "/org/gnome/SettingsDaemon"
390+#define GSD_DBUS_NAME "org.gnome.SettingsDaemon"
391+#define GSD_MEDIA_KEYS_DBUS_PATH GSD_DBUS_PATH "/MediaKeys"
392+#define GSD_MEDIA_KEYS_DBUS_NAME GSD_DBUS_NAME ".MediaKeys"
393+
394+#define GNOME_SESSION_DBUS_NAME "org.gnome.SessionManager"
395+#define GNOME_SESSION_DBUS_PATH "/org/gnome/SessionManager"
396+#define GNOME_SESSION_DBUS_INTERFACE "org.gnome.SessionManager"
397+
398+#define GNOME_KEYRING_DBUS_NAME "org.gnome.keyring"
399+#define GNOME_KEYRING_DBUS_PATH "/org/gnome/keyring/daemon"
400+#define GNOME_KEYRING_DBUS_INTERFACE "org.gnome.keyring.Daemon"
401+
402+#define GCONF_BINDING_DIR "/desktop/gnome/keybindings"
403+
404+static const gchar introspection_xml[] =
405+"<node>"
406+" <interface name='org.gnome.SettingsDaemon.MediaKeys'>"
407+" <annotation name='org.freedesktop.DBus.GLib.CSymbol' value='gsd_media_keys_manager'/>"
408+" <method name='GrabMediaPlayerKeys'>"
409+" <arg name='application' direction='in' type='s'/>"
410+" <arg name='time' direction='in' type='u'/>"
411+" </method>"
412+" <method name='ReleaseMediaPlayerKeys'>"
413+" <arg name='application' direction='in' type='s'/>"
414+" </method>"
415+" <signal name='MediaPlayerKeyPressed'>"
416+" <arg name='application' type='s'/>"
417+" <arg name='key' type='s'/>"
418+" </signal>"
419+" </interface>"
420+"</node>";
421+
422+#define SETTINGS_INTERFACE_DIR "org.gnome.desktop.interface"
423+#define SETTINGS_POWER_DIR "org.gnome.settings-daemon.plugins.power"
424+#define SETTINGS_XSETTINGS_DIR "org.gnome.settings-daemon.plugins.xsettings"
425+#define SETTINGS_TOUCHPAD_DIR "org.gnome.settings-daemon.peripherals.touchpad"
426+#define TOUCHPAD_ENABLED_KEY "touchpad-enabled"
427+#define HIGH_CONTRAST "HighContrast"
428+
429+#define VOLUME_STEP 6 /* percents for one volume button press */
430+#define MAX_VOLUME 65536.0
431+
432+#define GSD_MEDIA_KEYS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_MEDIA_KEYS_MANAGER, GsdMediaKeysManagerPrivate))
433+
434+typedef struct {
435+ char *application;
436+ char *name;
437+ guint32 time;
438+ guint watch_id;
439+} MediaPlayer;
440+
441+typedef struct {
442+ MediaKeyType key_type;
443+ const char *settings_key;
444+ const char *hard_coded;
445+ char *gconf_dir;
446+ char *custom_command;
447+ Key *key;
448+} MediaKey;
449+
450+struct GsdMediaKeysManagerPrivate
451+{
452+ /* Volume bits */
453+ GvcMixerControl *volume;
454+ GvcMixerStream *stream;
455+ ca_context *ca;
456+ GtkSettings *gtksettings;
457+#ifdef HAVE_GUDEV
458+ GHashTable *streams; /* key = X device ID, value = stream id */
459+ GUdevClient *udev_client;
460+#endif /* HAVE_GUDEV */
461+
462+ GtkWidget *dialog;
463+ GSettings *settings;
464+
465+ GPtrArray *keys;
466+ GConfClient *gconf;
467+ guint gconf_id;
468+
469+ /* HighContrast theme settings */
470+ GSettings *interface_settings;
471+ char *icon_theme;
472+ char *gtk_theme;
473+
474+ /* Power stuff */
475+ GSettings *power_settings;
476+ GDBusProxy *upower_proxy;
477+ GDBusProxy *power_screen_proxy;
478+ GDBusProxy *power_keyboard_proxy;
479+
480+ /* Multihead stuff */
481+ GdkScreen *current_screen;
482+ GSList *screens;
483+ int opcode;
484+
485+ GList *media_players;
486+
487+ GDBusNodeInfo *introspection_data;
488+ GDBusConnection *connection;
489+ GCancellable *bus_cancellable;
490+ GDBusProxy *xrandr_proxy;
491+ GCancellable *cancellable;
492+
493+ guint start_idle_id;
494+
495+ /* Ubuntu notifications */
496+ NotifyNotification *volume_notification;
497+ NotifyNotification *brightness_notification;
498+ NotifyNotification *kb_backlight_notification;
499+};
500+
501+static void gsd_media_keys_manager_class_init (GsdMediaKeysManagerClass *klass);
502+static void gsd_media_keys_manager_init (GsdMediaKeysManager *media_keys_manager);
503+static void gsd_media_keys_manager_finalize (GObject *object);
504+static void register_manager (GsdMediaKeysManager *manager);
505+G_DEFINE_TYPE (GsdMediaKeysManager, gsd_media_keys_manager, G_TYPE_OBJECT)
506+
507+static gpointer manager_object = NULL;
508+
509+#define NOTIFY_CAP_PRIVATE_SYNCHRONOUS "x-canonical-private-synchronous"
510+#define NOTIFY_CAP_PRIVATE_ICON_ONLY "x-canonical-private-icon-only"
511+#define NOTIFY_HINT_TRUE "true"
512+
513+typedef struct {
514+ GsdMediaKeysManager *manager;
515+ MediaKeyType type;
516+ guint old_percentage;
517+
518+} GsdBrightnessActionData;
519+
520+static const char *volume_icons[] = {
521+ "notification-audio-volume-muted",
522+ "notification-audio-volume-low",
523+ "notification-audio-volume-medium",
524+ "notification-audio-volume-high",
525+ NULL
526+};
527+
528+static const char *brightness_icons[] = {
529+ "notification-display-brightness-off",
530+ "notification-display-brightness-low",
531+ "notification-display-brightness-medium",
532+ "notification-display-brightness-high",
533+ "notification-display-brightness-full",
534+ NULL
535+};
536+
537+static const char *kb_backlight_icons[] = {
538+ "notification-keyboard-brightness-off",
539+ "notification-keyboard-brightness-low",
540+ "notification-keyboard-brightness-medium",
541+ "notification-keyboard-brightness-high",
542+ "notification-keyboard-brightness-full",
543+ NULL
544+};
545+
546+static const char *
547+calculate_icon_name (gint value, const char **icon_names)
548+{
549+ value = CLAMP (value, 0, 100);
550+ gint length = g_strv_length (icon_names);
551+ gint s = (length - 1) * value / 100 + 1;
552+ s = CLAMP (s, 1, length - 1);
553+
554+ return icon_names[s];
555+}
556+
557+static gboolean
558+ubuntu_osd_notification_is_supported (void)
559+{
560+ GList *caps;
561+ gboolean has_cap;
562+
563+ caps = notify_get_server_caps ();
564+ has_cap = (g_list_find_custom (caps, NOTIFY_CAP_PRIVATE_SYNCHRONOUS, (GCompareFunc) g_strcmp0) != NULL);
565+ g_list_foreach (caps, (GFunc) g_free, NULL);
566+ g_list_free (caps);
567+
568+ return has_cap;
569+}
570+
571+static gboolean
572+ubuntu_osd_notification_show_icon (const char *icon,
573+ const char *hint)
574+{
575+ if (!ubuntu_osd_notification_is_supported ())
576+ return FALSE;
577+
578+ NotifyNotification *notification = notify_notification_new (" ", "", icon);
579+ notify_notification_set_hint_string (notification, NOTIFY_CAP_PRIVATE_SYNCHRONOUS, hint);
580+ notify_notification_set_hint_string (notification, NOTIFY_CAP_PRIVATE_ICON_ONLY, NOTIFY_HINT_TRUE);
581+
582+ gboolean res = notify_notification_show (notification, NULL);
583+ g_object_unref (notification);
584+
585+ return res;
586+}
587+
588+static gboolean
589+ubuntu_osd_do_notification (NotifyNotification **notification,
590+ const char *hint,
591+ gint value,
592+ gboolean muted,
593+ const char **icon_names)
594+{
595+ if (!ubuntu_osd_notification_is_supported ())
596+ return FALSE;
597+
598+ if (!*notification) {
599+ *notification = notify_notification_new (" ", "", NULL);
600+ notify_notification_set_hint_string (*notification, NOTIFY_CAP_PRIVATE_SYNCHRONOUS, hint);
601+ }
602+
603+ value = CLAMP (value, -1, 101);
604+ const char *icon = muted ? icon_names[0] : calculate_icon_name (value, icon_names);
605+ notify_notification_set_hint_int32 (*notification, "value", value);
606+ notify_notification_update (*notification, " ", "", icon);
607+
608+ return notify_notification_show (*notification, NULL);
609+}
610+
611+static gboolean
612+ubuntu_osd_notification_show_volume (GsdMediaKeysManager *manager,
613+ gint value,
614+ gboolean muted)
615+{
616+ return ubuntu_osd_do_notification (&manager->priv->volume_notification,
617+ "volume", value, muted, volume_icons);
618+}
619+
620+static gboolean
621+ubuntu_osd_notification_show_brightness (GsdMediaKeysManager *manager,
622+ gint value)
623+{
624+ return ubuntu_osd_do_notification (&manager->priv->brightness_notification,
625+ "brightness", value, value <= 0, brightness_icons);
626+}
627+
628+static gboolean
629+ubuntu_osd_notification_show_kb_backlight (GsdMediaKeysManager *manager,
630+ gint value)
631+{
632+ return ubuntu_osd_do_notification (&manager->priv->kb_backlight_notification,
633+ "keyboard", value, value <= 0, kb_backlight_icons);
634+}
635+
636+static void
637+init_screens (GsdMediaKeysManager *manager)
638+{
639+ GdkDisplay *display;
640+ int i;
641+
642+ display = gdk_display_get_default ();
643+ for (i = 0; i < gdk_display_get_n_screens (display); i++) {
644+ GdkScreen *screen;
645+
646+ screen = gdk_display_get_screen (display, i);
647+ if (screen == NULL) {
648+ continue;
649+ }
650+ manager->priv->screens = g_slist_append (manager->priv->screens, screen);
651+ }
652+
653+ manager->priv->current_screen = manager->priv->screens->data;
654+}
655+
656+static void
657+media_key_free (MediaKey *key)
658+{
659+ if (key == NULL)
660+ return;
661+ g_free (key->gconf_dir);
662+ g_free (key->custom_command);
663+ free_key (key->key);
664+ g_free (key);
665+}
666+
667+static char *
668+get_term_command (GsdMediaKeysManager *manager)
669+{
670+ char *cmd_term, *cmd_args;;
671+ char *cmd = NULL;
672+ GSettings *settings;
673+
674+ settings = g_settings_new ("org.gnome.desktop.default-applications.terminal");
675+ cmd_term = g_settings_get_string (settings, "exec");
676+ if (cmd_term[0] == '\0')
677+ cmd_term = g_strdup ("gnome-terminal");
678+
679+ cmd_args = g_settings_get_string (settings, "exec-arg");
680+ if (strcmp (cmd_term, "") != 0) {
681+ cmd = g_strdup_printf ("%s %s -e", cmd_term, cmd_args);
682+ } else {
683+ cmd = g_strdup_printf ("%s -e", cmd_term);
684+ }
685+
686+ g_free (cmd_args);
687+ g_free (cmd_term);
688+ g_object_unref (settings);
689+
690+ return cmd;
691+}
692+
693+static char **
694+get_keyring_env (GsdMediaKeysManager *manager)
695+{
696+ GError *error = NULL;
697+ GVariant *variant, *item;
698+ GVariantIter *iter;
699+ char **envp;
700+
701+ variant = g_dbus_connection_call_sync (manager->priv->connection,
702+ GNOME_KEYRING_DBUS_NAME,
703+ GNOME_KEYRING_DBUS_PATH,
704+ GNOME_KEYRING_DBUS_INTERFACE,
705+ "GetEnvironment",
706+ NULL,
707+ NULL,
708+ G_DBUS_CALL_FLAGS_NONE,
709+ -1,
710+ NULL,
711+ &error);
712+ if (variant == NULL) {
713+ g_warning ("Failed to call GetEnvironment on keyring daemon: %s", error->message);
714+ g_error_free (error);
715+ return NULL;
716+ }
717+
718+ envp = g_get_environ ();
719+
720+ g_variant_get (variant, "(a{ss})", &iter);
721+
722+ while ((item = g_variant_iter_next_value (iter))) {
723+ char *key;
724+ char *value;
725+
726+ g_variant_get (item,
727+ "{ss}",
728+ &key,
729+ &value);
730+
731+ envp = g_environ_setenv (envp, key, value, TRUE);
732+
733+ g_variant_unref (item);
734+ g_free (key);
735+ g_free (value);
736+ }
737+
738+ g_variant_iter_free (iter);
739+ g_variant_unref (variant);
740+
741+ return envp;
742+}
743+
744+static void
745+execute (GsdMediaKeysManager *manager,
746+ char *cmd,
747+ gboolean need_term)
748+{
749+ gboolean retval;
750+ char **argv;
751+ int argc;
752+ char *exec;
753+ char *term = NULL;
754+ GError *error = NULL;
755+
756+ retval = FALSE;
757+
758+ if (need_term)
759+ term = get_term_command (manager);
760+
761+ if (term) {
762+ exec = g_strdup_printf ("%s %s", term, cmd);
763+ g_free (term);
764+ } else {
765+ exec = g_strdup (cmd);
766+ }
767+
768+ if (g_shell_parse_argv (exec, &argc, &argv, NULL)) {
769+ char **envp;
770+
771+ envp = get_keyring_env (manager);
772+
773+ retval = g_spawn_async (g_get_home_dir (),
774+ argv,
775+ envp,
776+ G_SPAWN_SEARCH_PATH,
777+ NULL,
778+ NULL,
779+ NULL,
780+ &error);
781+
782+ g_strfreev (argv);
783+ g_strfreev (envp);
784+ }
785+
786+ if (retval == FALSE) {
787+ g_warning ("Couldn't execute command: %s: %s", exec, error->message);
788+ g_error_free (error);
789+ }
790+ g_free (exec);
791+}
792+
793+static void
794+dialog_init (GsdMediaKeysManager *manager)
795+{
796+ if (manager->priv->dialog != NULL
797+ && !gsd_osd_window_is_valid (GSD_OSD_WINDOW (manager->priv->dialog))) {
798+ gtk_widget_destroy (manager->priv->dialog);
799+ manager->priv->dialog = NULL;
800+ }
801+
802+ if (manager->priv->dialog == NULL) {
803+ manager->priv->dialog = gsd_media_keys_window_new ();
804+ }
805+}
806+
807+static void
808+print_key_parse_error (MediaKey *key,
809+ const char *str)
810+{
811+ if (str == NULL || *str == '\0')
812+ return;
813+ if (key->settings_key != NULL)
814+ g_debug ("Unable to parse key '%s' for GSettings entry '%s'", str, key->settings_key);
815+ else
816+ g_debug ("Unable to parse hard-coded key '%s'", key->hard_coded);
817+}
818+
819+static char *
820+get_key_string (GsdMediaKeysManager *manager,
821+ MediaKey *key)
822+{
823+ if (key->settings_key != NULL)
824+ return g_settings_get_string (manager->priv->settings, key->settings_key);
825+ else if (key->hard_coded != NULL)
826+ return g_strdup (key->hard_coded);
827+ else if (key->gconf_dir != NULL) {
828+ char *entry, *str;
829+
830+ entry = g_strdup_printf ("%s/binding", key->gconf_dir);
831+ str = gconf_client_get_string (manager->priv->gconf, entry, NULL);
832+ g_free (entry);
833+ return str;
834+ } else
835+ g_assert_not_reached ();
836+}
837+
838+static gboolean
839+grab_media_key (MediaKey *key,
840+ GsdMediaKeysManager *manager)
841+{
842+ char *tmp;
843+ gboolean need_flush;
844+
845+ need_flush = FALSE;
846+
847+ if (key->key != NULL) {
848+ need_flush = TRUE;
849+ grab_key_unsafe (key->key, FALSE, manager->priv->screens);
850+ }
851+
852+ free_key (key->key);
853+ key->key = NULL;
854+
855+ tmp = get_key_string (manager, key);
856+
857+ key->key = parse_key (tmp);
858+ if (key->key == NULL) {
859+ print_key_parse_error (key, tmp);
860+ g_free (tmp);
861+ return need_flush;
862+ }
863+
864+ grab_key_unsafe (key->key, TRUE, manager->priv->screens);
865+
866+ g_free (tmp);
867+
868+ return TRUE;
869+}
870+
871+static void
872+gsettings_changed_cb (GSettings *settings,
873+ const gchar *settings_key,
874+ GsdMediaKeysManager *manager)
875+{
876+ int i;
877+ gboolean need_flush = TRUE;
878+
879+ gdk_error_trap_push ();
880+
881+ /* Find the key that was modified */
882+ for (i = 0; i < manager->priv->keys->len; i++) {
883+ MediaKey *key;
884+
885+ key = g_ptr_array_index (manager->priv->keys, i);
886+
887+ /* Skip over hard-coded and GConf keys */
888+ if (key->settings_key == NULL)
889+ continue;
890+ if (strcmp (settings_key, key->settings_key) == 0) {
891+ if (grab_media_key (key, manager))
892+ need_flush = TRUE;
893+ break;
894+ }
895+ }
896+
897+ if (need_flush)
898+ gdk_flush ();
899+ if (gdk_error_trap_pop ())
900+ g_warning ("Grab failed for some keys, another application may already have access the them.");
901+}
902+
903+static char *
904+entry_get_string (GConfEntry *entry)
905+{
906+ GConfValue *value = gconf_entry_get_value (entry);
907+
908+ if (value == NULL || value->type != GCONF_VALUE_STRING) {
909+ return NULL;
910+ }
911+
912+ return g_strdup (gconf_value_get_string (value));
913+}
914+
915+static MediaKey *
916+media_key_new_for_gconf (GsdMediaKeysManager *manager,
917+ char *dir)
918+{
919+ GSList *list, *l;
920+ char *action, *binding;
921+ MediaKey *key;
922+
923+ /* Get entries for this binding */
924+ list = gconf_client_all_entries (manager->priv->gconf, dir, NULL);
925+ action = NULL;
926+ binding = NULL;
927+
928+ for (l = list; l != NULL; l = l->next) {
929+ GConfEntry *entry = l->data;
930+ char *key_name;
931+
932+ key_name = g_path_get_basename (gconf_entry_get_key (entry));
933+
934+ if (key_name == NULL) {
935+ /* ignore entry */
936+ } else if (strcmp (key_name, "action") == 0) {
937+ action = entry_get_string (entry);
938+ } else if (strcmp (key_name, "binding") == 0) {
939+ binding = entry_get_string (entry);
940+ }
941+
942+ g_free (key_name);
943+ gconf_entry_free (entry);
944+ }
945+
946+ g_slist_free (list);
947+
948+ if (action == NULL && binding == NULL) {
949+ g_debug ("Key binding (%s) is incomplete", dir);
950+ return NULL;
951+ }
952+ g_free (binding);
953+
954+ key = g_new0 (MediaKey, 1);
955+ key->key_type = CUSTOM_KEY;
956+ key->gconf_dir = dir;
957+ key->custom_command = action;
958+
959+ return key;
960+}
961+
962+static void
963+gconf_changed_cb (GConfClient *client,
964+ guint cnxn_id,
965+ GConfEntry *entry,
966+ GsdMediaKeysManager *manager)
967+{
968+ char *gconf_key, **key_elems;
969+ int i;
970+ MediaKey *key;
971+
972+ g_return_if_fail (entry != NULL);
973+ g_return_if_fail (entry->key[0] == '/');
974+
975+ /* Look for the dir that changed, thus the MediaKey */
976+ key_elems = g_strsplit (entry->key + 1, "/", -1);
977+ if (key_elems == NULL ||
978+ (g_strv_length (key_elems) != 4 &&
979+ g_strv_length (key_elems) != 5)) {
980+ g_warning ("Unexpected GConf notification for key '%s'", entry->key);
981+ g_strfreev (key_elems);
982+ return;
983+ }
984+
985+ if (g_strv_length (key_elems) == 5 &&
986+ g_str_equal (key_elems[4], "binding") == FALSE &&
987+ g_str_equal (key_elems[4], "action") == FALSE) {
988+ g_debug ("Not interested in notification for key '%s'", entry->key);
989+ g_strfreev (key_elems);
990+ return;
991+ }
992+ gconf_key = g_strdup_printf ("/%s/%s/%s/%s",
993+ key_elems[0],
994+ key_elems[1],
995+ key_elems[2],
996+ key_elems[3]);
997+ g_strfreev (key_elems);
998+
999+ g_debug ("Got notification for key '%s' (dir: '%s')",
1000+ entry->key, gconf_key);
1001+
1002+ /* Remove the existing key */
1003+ for (i = 0; i < manager->priv->keys->len; i++) {
1004+ key = g_ptr_array_index (manager->priv->keys, i);
1005+
1006+ if (key->gconf_dir == NULL)
1007+ continue;
1008+ if (strcmp (key->gconf_dir, gconf_key) == 0) {
1009+ if (key->key) {
1010+ gdk_error_trap_push ();
1011+
1012+ grab_key_unsafe (key->key, FALSE, manager->priv->screens);
1013+
1014+ gdk_flush ();
1015+ if (gdk_error_trap_pop ())
1016+ g_warning ("Ungrab failed for GConf key '%s'", gconf_key);
1017+ }
1018+ g_ptr_array_remove_index_fast (manager->priv->keys, i);
1019+ break;
1020+ }
1021+ }
1022+
1023+ /* And create a new one! */
1024+ key = media_key_new_for_gconf (manager, gconf_key);
1025+ if (key) {
1026+ g_ptr_array_add (manager->priv->keys, key);
1027+
1028+ gdk_error_trap_push ();
1029+
1030+ grab_media_key (key, manager);
1031+
1032+ gdk_flush ();
1033+ if (gdk_error_trap_pop ())
1034+ g_warning ("Grab failed for GConf key '%s'", key->gconf_dir);
1035+ } else {
1036+ g_free (gconf_key);
1037+ }
1038+}
1039+
1040+
1041+static void
1042+add_key (GsdMediaKeysManager *manager, guint i)
1043+{
1044+ MediaKey *key;
1045+
1046+ key = g_new0 (MediaKey, 1);
1047+ key->key_type = media_keys[i].key_type;
1048+ key->settings_key = media_keys[i].settings_key;
1049+ key->hard_coded = media_keys[i].hard_coded;
1050+
1051+ g_ptr_array_add (manager->priv->keys, key);
1052+
1053+ grab_media_key (key, manager);
1054+}
1055+
1056+static void
1057+init_kbd (GsdMediaKeysManager *manager)
1058+{
1059+ int i;
1060+ GSList *list, *l;
1061+
1062+ gnome_settings_profile_start (NULL);
1063+
1064+ gdk_error_trap_push ();
1065+
1066+ manager->priv->keys = g_ptr_array_new_with_free_func ((GDestroyNotify) media_key_free);
1067+
1068+ /* Media keys
1069+ * Add hard-coded shortcuts first so that they can't be preempted */
1070+ for (i = 0; i < G_N_ELEMENTS (media_keys); i++) {
1071+ if (media_keys[i].hard_coded)
1072+ add_key (manager, i);
1073+ }
1074+ for (i = 0; i < G_N_ELEMENTS (media_keys); i++) {
1075+ if (media_keys[i].hard_coded == NULL)
1076+ add_key (manager, i);
1077+ }
1078+
1079+ /* Custom shortcuts */
1080+ list = gconf_client_all_dirs (manager->priv->gconf, GCONF_BINDING_DIR, NULL);
1081+ for (l = list; l != NULL; l = l->next) {
1082+ MediaKey *key;
1083+
1084+ key = media_key_new_for_gconf (manager, l->data);
1085+ if (!key) {
1086+ g_free (l->data);
1087+ continue;
1088+ }
1089+ g_ptr_array_add (manager->priv->keys, key);
1090+
1091+ grab_media_key (key, manager);
1092+ }
1093+ g_slist_free (list);
1094+
1095+ gdk_flush ();
1096+ if (gdk_error_trap_pop ())
1097+ g_warning ("Grab failed for some keys, another application may already have access the them.");
1098+
1099+ gnome_settings_profile_end (NULL);
1100+}
1101+
1102+static void
1103+dialog_show (GsdMediaKeysManager *manager)
1104+{
1105+ int orig_w;
1106+ int orig_h;
1107+ int screen_w;
1108+ int screen_h;
1109+ int x;
1110+ int y;
1111+ GtkRequisition win_req;
1112+ GdkRectangle geometry;
1113+ int monitor;
1114+
1115+ gtk_window_set_screen (GTK_WINDOW (manager->priv->dialog),
1116+ manager->priv->current_screen);
1117+
1118+ /*
1119+ * get the window size
1120+ * if the window hasn't been mapped, it doesn't necessarily
1121+ * know its true size, yet, so we need to jump through hoops
1122+ */
1123+ gtk_window_get_default_size (GTK_WINDOW (manager->priv->dialog), &orig_w, &orig_h);
1124+ gtk_widget_size_request (manager->priv->dialog, &win_req);
1125+
1126+ if (win_req.width > orig_w)
1127+ orig_w = win_req.width;
1128+ if (win_req.height > orig_h)
1129+ orig_h = win_req.height;
1130+
1131+ monitor = gdk_screen_get_primary_monitor (manager->priv->current_screen);
1132+
1133+ gdk_screen_get_monitor_geometry (manager->priv->current_screen,
1134+ monitor,
1135+ &geometry);
1136+
1137+ screen_w = geometry.width;
1138+ screen_h = geometry.height;
1139+
1140+ x = ((screen_w - orig_w) / 2) + geometry.x;
1141+ y = geometry.y + (screen_h / 2) + (screen_h / 2 - orig_h) / 2;
1142+
1143+ gtk_window_move (GTK_WINDOW (manager->priv->dialog), x, y);
1144+
1145+ gtk_widget_show (manager->priv->dialog);
1146+
1147+ gdk_display_sync (gdk_screen_get_display (manager->priv->current_screen));
1148+}
1149+
1150+static void
1151+launch_app (GAppInfo *app_info,
1152+ gint64 timestamp)
1153+{
1154+ GError *error = NULL;
1155+ GdkAppLaunchContext *launch_context;
1156+
1157+ /* setup the launch context so the startup notification is correct */
1158+ launch_context = gdk_display_get_app_launch_context (gdk_display_get_default ());
1159+ gdk_app_launch_context_set_timestamp (launch_context, timestamp);
1160+
1161+ if (!g_app_info_launch (app_info, NULL, G_APP_LAUNCH_CONTEXT (launch_context), &error)) {
1162+ g_warning ("Could not launch '%s': %s",
1163+ g_app_info_get_commandline (app_info),
1164+ error->message);
1165+ g_error_free (error);
1166+ }
1167+ g_object_unref (launch_context);
1168+}
1169+
1170+static void
1171+do_url_action (GsdMediaKeysManager *manager,
1172+ const char *scheme,
1173+ gint64 timestamp)
1174+{
1175+ GAppInfo *app_info;
1176+
1177+ app_info = g_app_info_get_default_for_uri_scheme (scheme);
1178+ if (app_info != NULL) {
1179+ launch_app (app_info, timestamp);
1180+ g_object_unref (app_info);
1181+ } else {
1182+ g_warning ("Could not find default application for '%s' scheme", scheme);
1183+ }
1184+}
1185+
1186+static void
1187+do_media_action (GsdMediaKeysManager *manager,
1188+ gint64 timestamp)
1189+{
1190+ GAppInfo *app_info;
1191+
1192+ app_info = g_app_info_get_default_for_type ("audio/x-vorbis+ogg", FALSE);
1193+ if (app_info != NULL) {
1194+ launch_app (app_info, timestamp);
1195+ g_object_unref (app_info);
1196+ } else {
1197+ g_warning ("Could not find default application for '%s' mime-type", "audio/x-vorbis+ogg");
1198+ }
1199+}
1200+
1201+static void
1202+gnome_session_shutdown (GsdMediaKeysManager *manager)
1203+{
1204+ GError *error = NULL;
1205+ GVariant *variant;
1206+
1207+ /* Shouldn't happen, but you never know */
1208+ if (manager->priv->connection == NULL) {
1209+ execute (manager, "gnome-session-quit --logout", FALSE);
1210+ return;
1211+ }
1212+
1213+ variant = g_dbus_connection_call_sync (manager->priv->connection,
1214+ GNOME_SESSION_DBUS_NAME,
1215+ GNOME_SESSION_DBUS_PATH,
1216+ GNOME_SESSION_DBUS_INTERFACE,
1217+ "Shutdown",
1218+ NULL,
1219+ NULL,
1220+ G_DBUS_CALL_FLAGS_NONE,
1221+ -1,
1222+ NULL,
1223+ &error);
1224+ if (variant == NULL) {
1225+ g_warning ("Failed to call Shutdown on session manager: %s", error->message);
1226+ g_error_free (error);
1227+ return;
1228+ }
1229+ g_variant_unref (variant);
1230+}
1231+
1232+static void
1233+do_logout_action (GsdMediaKeysManager *manager)
1234+{
1235+ execute (manager, "gnome-session-quit --logout", FALSE);
1236+}
1237+
1238+static void
1239+do_eject_action_cb (GDrive *drive,
1240+ GAsyncResult *res,
1241+ GsdMediaKeysManager *manager)
1242+{
1243+ g_drive_eject_with_operation_finish (drive, res, NULL);
1244+}
1245+
1246+#define NO_SCORE 0
1247+#define SCORE_CAN_EJECT 50
1248+#define SCORE_HAS_MEDIA 100
1249+static void
1250+do_eject_action (GsdMediaKeysManager *manager)
1251+{
1252+ GList *drives, *l;
1253+ GDrive *fav_drive;
1254+ guint score;
1255+ GVolumeMonitor *volume_monitor;
1256+
1257+ volume_monitor = g_volume_monitor_get ();
1258+
1259+ /* Find the best drive to eject */
1260+ fav_drive = NULL;
1261+ score = NO_SCORE;
1262+ drives = g_volume_monitor_get_connected_drives (volume_monitor);
1263+ for (l = drives; l != NULL; l = l->next) {
1264+ GDrive *drive = l->data;
1265+
1266+ if (g_drive_can_eject (drive) == FALSE)
1267+ continue;
1268+ if (g_drive_is_media_removable (drive) == FALSE)
1269+ continue;
1270+ if (score < SCORE_CAN_EJECT) {
1271+ fav_drive = drive;
1272+ score = SCORE_CAN_EJECT;
1273+ }
1274+ if (g_drive_has_media (drive) == FALSE)
1275+ continue;
1276+ if (score < SCORE_HAS_MEDIA) {
1277+ fav_drive = drive;
1278+ score = SCORE_HAS_MEDIA;
1279+ break;
1280+ }
1281+ }
1282+
1283+ /* Show the dialogue */
1284+ if (!ubuntu_osd_notification_show_icon ("notification-device-eject", "Eject")) {
1285+ dialog_init (manager);
1286+ gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
1287+ "media-eject-symbolic",
1288+ FALSE);
1289+ dialog_show (manager);
1290+ }
1291+
1292+ /* Clean up the drive selection and exit if no suitable
1293+ * drives are found */
1294+ if (fav_drive != NULL)
1295+ fav_drive = g_object_ref (fav_drive);
1296+
1297+ g_list_foreach (drives, (GFunc) g_object_unref, NULL);
1298+ if (fav_drive == NULL)
1299+ return;
1300+
1301+ /* Eject! */
1302+ g_drive_eject_with_operation (fav_drive, G_MOUNT_UNMOUNT_FORCE,
1303+ NULL, NULL,
1304+ (GAsyncReadyCallback) do_eject_action_cb,
1305+ manager);
1306+ g_object_unref (fav_drive);
1307+ g_object_unref (volume_monitor);
1308+}
1309+
1310+static void
1311+do_home_key_action (GsdMediaKeysManager *manager,
1312+ gint64 timestamp)
1313+{
1314+ GFile *file;
1315+ GError *error = NULL;
1316+ char *uri;
1317+
1318+ file = g_file_new_for_path (g_get_home_dir ());
1319+ uri = g_file_get_uri (file);
1320+ g_object_unref (file);
1321+
1322+ if (gtk_show_uri (NULL, uri, timestamp, &error) == FALSE) {
1323+ g_warning ("Failed to launch '%s': %s", uri, error->message);
1324+ g_error_free (error);
1325+ }
1326+ g_free (uri);
1327+}
1328+
1329+static void
1330+do_execute_desktop (GsdMediaKeysManager *manager,
1331+ const char *desktop,
1332+ gint64 timestamp)
1333+{
1334+ GDesktopAppInfo *app_info;
1335+
1336+ app_info = g_desktop_app_info_new (desktop);
1337+ if (app_info != NULL) {
1338+ launch_app (G_APP_INFO (app_info), timestamp);
1339+ g_object_unref (app_info);
1340+ } else {
1341+ g_warning ("Could not find application '%s'", desktop);
1342+ }
1343+}
1344+
1345+static void
1346+do_touchpad_osd_action (GsdMediaKeysManager *manager, gboolean state)
1347+{
1348+ if (!ubuntu_osd_notification_show_icon ((!state) ? "touchpad-disabled-symbolic" : "input-touchpad-symbolic", "Touchpad")) {
1349+ dialog_init (manager);
1350+ gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
1351+ state ? "input-touchpad-symbolic" : "touchpad-disabled-symbolic",
1352+ FALSE);
1353+ dialog_show (manager);
1354+ }
1355+}
1356+
1357+static void
1358+do_touchpad_action (GsdMediaKeysManager *manager)
1359+{
1360+ GSettings *settings;
1361+ gboolean state;
1362+
1363+ if (touchpad_is_present () == FALSE) {
1364+ do_touchpad_osd_action (manager, FALSE);
1365+ return;
1366+ }
1367+
1368+ settings = g_settings_new (SETTINGS_TOUCHPAD_DIR);
1369+ state = g_settings_get_boolean (settings, TOUCHPAD_ENABLED_KEY);
1370+
1371+ do_touchpad_osd_action (manager, !state);
1372+
1373+ g_settings_set_boolean (settings, TOUCHPAD_ENABLED_KEY, !state);
1374+ g_object_unref (settings);
1375+}
1376+
1377+static void
1378+update_dialog (GsdMediaKeysManager *manager,
1379+ GvcMixerStream *stream,
1380+ guint vol,
1381+ gboolean muted,
1382+ gboolean sound_changed,
1383+ gboolean quiet)
1384+{
1385+ if (ubuntu_osd_notification_show_volume (manager, vol, muted))
1386+ goto done;
1387+
1388+ vol = CLAMP (vol, 0, 100);
1389+
1390+ dialog_init (manager);
1391+ gsd_media_keys_window_set_volume_muted (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
1392+ muted);
1393+ gsd_media_keys_window_set_volume_level (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog), vol);
1394+ gsd_media_keys_window_set_action (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
1395+ GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME);
1396+ dialog_show (manager);
1397+
1398+done:
1399+ if (quiet == FALSE && sound_changed != FALSE && muted == FALSE) {
1400+ ca_context_change_device (manager->priv->ca,
1401+ gvc_mixer_stream_get_name (stream));
1402+ ca_context_play (manager->priv->ca, 1,
1403+ CA_PROP_EVENT_ID, "audio-volume-change",
1404+ CA_PROP_EVENT_DESCRIPTION, "volume changed through key press",
1405+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
1406+ NULL);
1407+ }
1408+}
1409+
1410+#ifdef HAVE_GUDEV
1411+/* PulseAudio gives us /devices/... paths, when udev
1412+ * expects /sys/devices/... paths. */
1413+static GUdevDevice *
1414+get_udev_device_for_sysfs_path (GsdMediaKeysManager *manager,
1415+ const char *sysfs_path)
1416+{
1417+ char *path;
1418+ GUdevDevice *dev;
1419+
1420+ path = g_strdup_printf ("/sys%s", sysfs_path);
1421+ dev = g_udev_client_query_by_sysfs_path (manager->priv->udev_client, path);
1422+ g_free (path);
1423+
1424+ return dev;
1425+}
1426+
1427+static GvcMixerStream *
1428+get_stream_for_device_id (GsdMediaKeysManager *manager,
1429+ guint deviceid)
1430+{
1431+ char *devnode;
1432+ gpointer id_ptr;
1433+ GvcMixerStream *res;
1434+ GUdevDevice *dev, *parent;
1435+ GSList *sinks, *l;
1436+
1437+ id_ptr = g_hash_table_lookup (manager->priv->streams, GUINT_TO_POINTER (deviceid));
1438+ if (id_ptr != NULL) {
1439+ if (GPOINTER_TO_UINT (id_ptr) == (guint) -1)
1440+ return NULL;
1441+ else
1442+ return gvc_mixer_control_lookup_stream_id (manager->priv->volume, GPOINTER_TO_UINT (id_ptr));
1443+ }
1444+
1445+ devnode = xdevice_get_device_node (deviceid);
1446+ if (devnode == NULL) {
1447+ g_debug ("Could not find device node for XInput device %d", deviceid);
1448+ return NULL;
1449+ }
1450+
1451+ dev = g_udev_client_query_by_device_file (manager->priv->udev_client, devnode);
1452+ if (dev == NULL) {
1453+ g_debug ("Could not find udev device for device path '%s'", devnode);
1454+ g_free (devnode);
1455+ return NULL;
1456+ }
1457+ g_free (devnode);
1458+
1459+ if (g_strcmp0 (g_udev_device_get_property (dev, "ID_BUS"), "usb") != 0) {
1460+ g_debug ("Not handling XInput device %d, not USB", deviceid);
1461+ g_hash_table_insert (manager->priv->streams,
1462+ GUINT_TO_POINTER (deviceid),
1463+ GUINT_TO_POINTER ((guint) -1));
1464+ g_object_unref (dev);
1465+ return NULL;
1466+ }
1467+
1468+ parent = g_udev_device_get_parent_with_subsystem (dev, "usb", "usb_device");
1469+ if (parent == NULL) {
1470+ g_warning ("No USB device parent for XInput device %d even though it's USB", deviceid);
1471+ g_object_unref (dev);
1472+ return NULL;
1473+ }
1474+
1475+ res = NULL;
1476+ sinks = gvc_mixer_control_get_sinks (manager->priv->volume);
1477+ for (l = sinks; l; l = l->next) {
1478+ GvcMixerStream *stream = l->data;
1479+ const char *sysfs_path;
1480+ GUdevDevice *sink_dev, *sink_parent;
1481+
1482+ sysfs_path = gvc_mixer_stream_get_sysfs_path (stream);
1483+ sink_dev = get_udev_device_for_sysfs_path (manager, sysfs_path);
1484+ if (sink_dev == NULL)
1485+ continue;
1486+ sink_parent = g_udev_device_get_parent_with_subsystem (sink_dev, "usb", "usb_device");
1487+ g_object_unref (sink_dev);
1488+ if (sink_parent == NULL)
1489+ continue;
1490+
1491+ if (g_strcmp0 (g_udev_device_get_sysfs_path (sink_parent),
1492+ g_udev_device_get_sysfs_path (parent)) == 0) {
1493+ res = stream;
1494+ }
1495+ g_object_unref (sink_parent);
1496+ if (res != NULL)
1497+ break;
1498+ }
1499+
1500+ if (res)
1501+ g_hash_table_insert (manager->priv->streams,
1502+ GUINT_TO_POINTER (deviceid),
1503+ GUINT_TO_POINTER (gvc_mixer_stream_get_id (res)));
1504+ else
1505+ g_hash_table_insert (manager->priv->streams,
1506+ GUINT_TO_POINTER (deviceid),
1507+ GUINT_TO_POINTER ((guint) -1));
1508+
1509+ return res;
1510+}
1511+#endif /* HAVE_GUDEV */
1512+
1513+static void
1514+do_sound_action (GsdMediaKeysManager *manager,
1515+ guint deviceid,
1516+ int type,
1517+ gboolean quiet)
1518+{
1519+ GvcMixerStream *stream;
1520+ gboolean old_muted, new_muted;
1521+ guint old_vol, new_vol, norm_vol_step, osd_vol;
1522+ gboolean sound_changed;
1523+
1524+ /* Find the stream that corresponds to the device, if any */
1525+#ifdef HAVE_GUDEV
1526+ stream = get_stream_for_device_id (manager, deviceid);
1527+ if (stream == NULL)
1528+#endif /* HAVE_GUDEV */
1529+ stream = manager->priv->stream;
1530+ if (stream == NULL)
1531+ return;
1532+
1533+ norm_vol_step = PA_VOLUME_NORM * VOLUME_STEP / 100;
1534+
1535+ /* FIXME: this is racy */
1536+ new_vol = old_vol = gvc_mixer_stream_get_volume (stream);
1537+ new_muted = old_muted = gvc_mixer_stream_get_is_muted (stream);
1538+ sound_changed = FALSE;
1539+
1540+ switch (type) {
1541+ case MUTE_KEY:
1542+ new_muted = !old_muted;
1543+ break;
1544+ case VOLUME_DOWN_KEY:
1545+ if (old_vol <= norm_vol_step) {
1546+ new_vol = 0;
1547+ new_muted = TRUE;
1548+ } else {
1549+ new_vol = old_vol - norm_vol_step;
1550+ }
1551+ break;
1552+ case VOLUME_UP_KEY:
1553+ new_muted = FALSE;
1554+ /* When coming out of mute only increase the volume if it was 0 */
1555+ if (!old_muted || old_vol == 0)
1556+ new_vol = MIN (old_vol + norm_vol_step, MAX_VOLUME);
1557+ break;
1558+ }
1559+
1560+ if (old_muted != new_muted) {
1561+ gvc_mixer_stream_change_is_muted (stream, new_muted);
1562+ sound_changed = TRUE;
1563+ }
1564+
1565+ if (old_vol != new_vol) {
1566+ if (gvc_mixer_stream_set_volume (stream, new_vol) != FALSE) {
1567+ gvc_mixer_stream_push_volume (stream);
1568+ sound_changed = TRUE;
1569+ }
1570+ }
1571+
1572+ if (type == VOLUME_DOWN_KEY && old_vol == 0 && old_muted)
1573+ osd_vol = -1;
1574+ else if (type == VOLUME_UP_KEY && old_vol == PA_VOLUME_NORM && !old_muted)
1575+ osd_vol = 101;
1576+ else if (!new_muted)
1577+ osd_vol = (int) (100 * (double) new_vol / PA_VOLUME_NORM);
1578+ else
1579+ osd_vol = 0;
1580+
1581+ update_dialog (manager, stream, osd_vol, new_muted, sound_changed, quiet);
1582+}
1583+
1584+static void
1585+sound_theme_changed (GtkSettings *settings,
1586+ GParamSpec *pspec,
1587+ GsdMediaKeysManager *manager)
1588+{
1589+ char *theme_name;
1590+
1591+ g_object_get (G_OBJECT (manager->priv->gtksettings), "gtk-sound-theme-name", &theme_name, NULL);
1592+ if (theme_name)
1593+ ca_context_change_props (manager->priv->ca, CA_PROP_CANBERRA_XDG_THEME_NAME, theme_name, NULL);
1594+ g_free (theme_name);
1595+}
1596+
1597+static void
1598+update_default_sink (GsdMediaKeysManager *manager)
1599+{
1600+ GvcMixerStream *stream;
1601+
1602+ stream = gvc_mixer_control_get_default_sink (manager->priv->volume);
1603+ if (stream == manager->priv->stream)
1604+ return;
1605+
1606+ if (manager->priv->stream != NULL) {
1607+ g_object_unref (manager->priv->stream);
1608+ manager->priv->stream = NULL;
1609+ }
1610+
1611+ if (stream != NULL) {
1612+ manager->priv->stream = g_object_ref (stream);
1613+ } else {
1614+ g_warning ("Unable to get default sink");
1615+ }
1616+}
1617+
1618+static void
1619+on_control_state_changed (GvcMixerControl *control,
1620+ GvcMixerControlState new_state,
1621+ GsdMediaKeysManager *manager)
1622+{
1623+ update_default_sink (manager);
1624+}
1625+
1626+static void
1627+on_control_default_sink_changed (GvcMixerControl *control,
1628+ guint id,
1629+ GsdMediaKeysManager *manager)
1630+{
1631+ update_default_sink (manager);
1632+}
1633+
1634+#ifdef HAVE_GUDEV
1635+static gboolean
1636+remove_stream (gpointer key,
1637+ gpointer value,
1638+ gpointer id)
1639+{
1640+ if (GPOINTER_TO_UINT (value) == GPOINTER_TO_UINT (id))
1641+ return TRUE;
1642+ return FALSE;
1643+}
1644+#endif /* HAVE_GUDEV */
1645+
1646+static void
1647+on_control_stream_removed (GvcMixerControl *control,
1648+ guint id,
1649+ GsdMediaKeysManager *manager)
1650+{
1651+ if (manager->priv->stream != NULL) {
1652+ if (gvc_mixer_stream_get_id (manager->priv->stream) == id) {
1653+ g_object_unref (manager->priv->stream);
1654+ manager->priv->stream = NULL;
1655+ }
1656+ }
1657+
1658+#ifdef HAVE_GUDEV
1659+ g_hash_table_foreach_remove (manager->priv->streams, (GHRFunc) remove_stream, GUINT_TO_POINTER (id));
1660+#endif
1661+}
1662+
1663+static void
1664+free_media_player (MediaPlayer *player)
1665+{
1666+ if (player->watch_id > 0) {
1667+ g_bus_unwatch_name (player->watch_id);
1668+ player->watch_id = 0;
1669+ }
1670+ g_free (player->application);
1671+ g_free (player->name);
1672+ g_free (player);
1673+}
1674+
1675+static gint
1676+find_by_application (gconstpointer a,
1677+ gconstpointer b)
1678+{
1679+ return strcmp (((MediaPlayer *)a)->application, b);
1680+}
1681+
1682+static gint
1683+find_by_name (gconstpointer a,
1684+ gconstpointer b)
1685+{
1686+ return strcmp (((MediaPlayer *)a)->name, b);
1687+}
1688+
1689+static gint
1690+find_by_time (gconstpointer a,
1691+ gconstpointer b)
1692+{
1693+ return ((MediaPlayer *)a)->time < ((MediaPlayer *)b)->time;
1694+}
1695+
1696+static void
1697+name_vanished_handler (GDBusConnection *connection,
1698+ const gchar *name,
1699+ GsdMediaKeysManager *manager)
1700+{
1701+ GList *iter;
1702+
1703+ iter = g_list_find_custom (manager->priv->media_players,
1704+ name,
1705+ find_by_name);
1706+
1707+ if (iter != NULL) {
1708+ MediaPlayer *player;
1709+
1710+ player = iter->data;
1711+ g_debug ("Deregistering vanished %s (name: %s)", player->application, player->name);
1712+ free_media_player (player);
1713+ manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter);
1714+ }
1715+}
1716+
1717+/*
1718+ * Register a new media player. Most applications will want to call
1719+ * this with time = GDK_CURRENT_TIME. This way, the last registered
1720+ * player will receive media events. In some cases, applications
1721+ * may want to register with a lower priority (usually 1), to grab
1722+ * events only nobody is interested.
1723+ */
1724+static void
1725+gsd_media_keys_manager_grab_media_player_keys (GsdMediaKeysManager *manager,
1726+ const char *application,
1727+ const char *name,
1728+ guint32 time)
1729+{
1730+ GList *iter;
1731+ MediaPlayer *media_player;
1732+ guint watch_id;
1733+
1734+ if (time == GDK_CURRENT_TIME) {
1735+ GTimeVal tv;
1736+
1737+ g_get_current_time (&tv);
1738+ time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
1739+ }
1740+
1741+ iter = g_list_find_custom (manager->priv->media_players,
1742+ application,
1743+ find_by_application);
1744+
1745+ if (iter != NULL) {
1746+ if (((MediaPlayer *)iter->data)->time < time) {
1747+ MediaPlayer *player = iter->data;
1748+ free_media_player (player);
1749+ manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter);
1750+ } else {
1751+ return;
1752+ }
1753+ }
1754+
1755+ watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
1756+ name,
1757+ G_BUS_NAME_WATCHER_FLAGS_NONE,
1758+ NULL,
1759+ (GBusNameVanishedCallback) name_vanished_handler,
1760+ manager,
1761+ NULL);
1762+
1763+ g_debug ("Registering %s at %u", application, time);
1764+ media_player = g_new0 (MediaPlayer, 1);
1765+ media_player->application = g_strdup (application);
1766+ media_player->name = g_strdup (name);
1767+ media_player->time = time;
1768+ media_player->watch_id = watch_id;
1769+
1770+ manager->priv->media_players = g_list_insert_sorted (manager->priv->media_players,
1771+ media_player,
1772+ find_by_time);
1773+}
1774+
1775+static void
1776+gsd_media_keys_manager_release_media_player_keys (GsdMediaKeysManager *manager,
1777+ const char *application,
1778+ const char *name)
1779+{
1780+ GList *iter = NULL;
1781+
1782+ g_return_if_fail (application != NULL || name != NULL);
1783+
1784+ if (application != NULL) {
1785+ iter = g_list_find_custom (manager->priv->media_players,
1786+ application,
1787+ find_by_application);
1788+ }
1789+
1790+ if (iter == NULL && name != NULL) {
1791+ iter = g_list_find_custom (manager->priv->media_players,
1792+ name,
1793+ find_by_name);
1794+ }
1795+
1796+ if (iter != NULL) {
1797+ MediaPlayer *player;
1798+
1799+ player = iter->data;
1800+ g_debug ("Deregistering %s (name: %s)", application, player->name);
1801+ free_media_player (player);
1802+ manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter);
1803+ }
1804+}
1805+
1806+static gboolean
1807+gsd_media_player_key_pressed (GsdMediaKeysManager *manager,
1808+ const char *key)
1809+{
1810+ const char *application;
1811+ gboolean have_listeners;
1812+ GError *error = NULL;
1813+ MediaPlayer *player;
1814+
1815+ g_return_val_if_fail (key != NULL, FALSE);
1816+
1817+ g_debug ("Media key '%s' pressed", key);
1818+
1819+ have_listeners = (manager->priv->media_players != NULL);
1820+
1821+ if (!have_listeners) {
1822+ /* Popup a dialog with an (/) icon */
1823+ dialog_init (manager);
1824+ gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
1825+ "action-unavailable-symbolic",
1826+ FALSE);
1827+ dialog_show (manager);
1828+ return TRUE;
1829+ }
1830+
1831+ player = manager->priv->media_players->data;
1832+ application = player->application;
1833+
1834+ if (g_dbus_connection_emit_signal (manager->priv->connection,
1835+ player->name,
1836+ GSD_MEDIA_KEYS_DBUS_PATH,
1837+ GSD_MEDIA_KEYS_DBUS_NAME,
1838+ "MediaPlayerKeyPressed",
1839+ g_variant_new ("(ss)", application ? application : "", key),
1840+ &error) == FALSE) {
1841+ g_debug ("Error emitting signal: %s", error->message);
1842+ g_error_free (error);
1843+ }
1844+
1845+ return !have_listeners;
1846+}
1847+
1848+static void
1849+handle_method_call (GDBusConnection *connection,
1850+ const gchar *sender,
1851+ const gchar *object_path,
1852+ const gchar *interface_name,
1853+ const gchar *method_name,
1854+ GVariant *parameters,
1855+ GDBusMethodInvocation *invocation,
1856+ gpointer user_data)
1857+{
1858+ GsdMediaKeysManager *manager = (GsdMediaKeysManager *) user_data;
1859+
1860+ g_debug ("Calling method '%s' for media-keys", method_name);
1861+
1862+ if (g_strcmp0 (method_name, "ReleaseMediaPlayerKeys") == 0) {
1863+ const char *app_name;
1864+
1865+ g_variant_get (parameters, "(&s)", &app_name);
1866+ gsd_media_keys_manager_release_media_player_keys (manager, app_name, sender);
1867+ g_dbus_method_invocation_return_value (invocation, NULL);
1868+ } else if (g_strcmp0 (method_name, "GrabMediaPlayerKeys") == 0) {
1869+ const char *app_name;
1870+ guint32 time;
1871+
1872+ g_variant_get (parameters, "(&su)", &app_name, &time);
1873+ gsd_media_keys_manager_grab_media_player_keys (manager, app_name, sender, time);
1874+ g_dbus_method_invocation_return_value (invocation, NULL);
1875+ }
1876+}
1877+
1878+static const GDBusInterfaceVTable interface_vtable =
1879+{
1880+ handle_method_call,
1881+ NULL, /* Get Property */
1882+ NULL, /* Set Property */
1883+};
1884+
1885+static gboolean
1886+do_multimedia_player_action (GsdMediaKeysManager *manager,
1887+ const char *icon,
1888+ const char *key)
1889+{
1890+ if (icon != NULL)
1891+ ubuntu_osd_notification_show_icon (icon, key);
1892+ return gsd_media_player_key_pressed (manager, key);
1893+}
1894+
1895+static void
1896+on_xrandr_action_call_finished (GObject *source_object,
1897+ GAsyncResult *res,
1898+ GsdMediaKeysManager *manager)
1899+{
1900+ GError *error = NULL;
1901+ GVariant *variant;
1902+ char *action;
1903+
1904+ action = g_object_get_data (G_OBJECT (source_object),
1905+ "gsd-media-keys-manager-xrandr-action");
1906+
1907+ variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error);
1908+
1909+ g_object_unref (manager->priv->cancellable);
1910+ manager->priv->cancellable = NULL;
1911+
1912+ if (error != NULL) {
1913+ g_warning ("Unable to call '%s': %s", action, error->message);
1914+ g_error_free (error);
1915+ } else {
1916+ g_variant_unref (variant);
1917+ }
1918+
1919+ g_free (action);
1920+}
1921+
1922+static void
1923+do_xrandr_action (GsdMediaKeysManager *manager,
1924+ const char *action,
1925+ gint64 timestamp)
1926+{
1927+ GsdMediaKeysManagerPrivate *priv = manager->priv;
1928+
1929+ if (priv->connection == NULL || priv->xrandr_proxy == NULL) {
1930+ g_warning ("No existing D-Bus connection trying to handle XRANDR keys");
1931+ return;
1932+ }
1933+
1934+ if (priv->cancellable != NULL) {
1935+ g_debug ("xrandr action already in flight");
1936+ return;
1937+ }
1938+
1939+ priv->cancellable = g_cancellable_new ();
1940+
1941+ g_object_set_data (G_OBJECT (priv->xrandr_proxy),
1942+ "gsd-media-keys-manager-xrandr-action",
1943+ g_strdup (action));
1944+
1945+ g_dbus_proxy_call (priv->xrandr_proxy,
1946+ action,
1947+ g_variant_new ("(x)", timestamp),
1948+ G_DBUS_CALL_FLAGS_NONE,
1949+ -1,
1950+ priv->cancellable,
1951+ (GAsyncReadyCallback) on_xrandr_action_call_finished,
1952+ manager);
1953+}
1954+
1955+static gboolean
1956+do_video_out_action (GsdMediaKeysManager *manager,
1957+ gint64 timestamp)
1958+{
1959+ do_xrandr_action (manager, "VideoModeSwitch", timestamp);
1960+ return FALSE;
1961+}
1962+
1963+static gboolean
1964+do_video_rotate_action (GsdMediaKeysManager *manager,
1965+ gint64 timestamp)
1966+{
1967+ do_xrandr_action (manager, "Rotate", timestamp);
1968+ return FALSE;
1969+}
1970+
1971+static void
1972+do_toggle_accessibility_key (const char *key)
1973+{
1974+ GSettings *settings;
1975+ gboolean state;
1976+
1977+ settings = g_settings_new ("org.gnome.desktop.a11y.applications");
1978+ state = g_settings_get_boolean (settings, key);
1979+ g_settings_set_boolean (settings, key, !state);
1980+ g_object_unref (settings);
1981+}
1982+
1983+static void
1984+do_magnifier_action (GsdMediaKeysManager *manager)
1985+{
1986+ do_toggle_accessibility_key ("screen-magnifier-enabled");
1987+}
1988+
1989+static void
1990+do_screenreader_action (GsdMediaKeysManager *manager)
1991+{
1992+ do_toggle_accessibility_key ("screen-reader-enabled");
1993+}
1994+
1995+static void
1996+do_on_screen_keyboard_action (GsdMediaKeysManager *manager)
1997+{
1998+ do_toggle_accessibility_key ("screen-keyboard-enabled");
1999+}
2000+
2001+static void
2002+do_text_size_action (GsdMediaKeysManager *manager,
2003+ MediaKeyType type)
2004+{
2005+ gdouble factor, best, distance;
2006+ guint i;
2007+
2008+ /* Same values used in the Seeing tab of the Universal Access panel */
2009+ static gdouble factors[] = {
2010+ 0.75,
2011+ 1.0,
2012+ 1.25,
2013+ 1.5
2014+ };
2015+
2016+ /* Figure out the current DPI scaling factor */
2017+ factor = g_settings_get_double (manager->priv->interface_settings, "text-scaling-factor");
2018+ factor += (type == INCREASE_TEXT_KEY ? 0.25 : -0.25);
2019+
2020+ /* Try to find a matching value */
2021+ distance = 1e6;
2022+ best = 1.0;
2023+ for (i = 0; i < G_N_ELEMENTS(factors); i++) {
2024+ gdouble d;
2025+ d = fabs (factor - factors[i]);
2026+ if (d < distance) {
2027+ best = factors[i];
2028+ distance = d;
2029+ }
2030+ }
2031+
2032+ if (best == 1.0)
2033+ g_settings_reset (manager->priv->interface_settings, "text-scaling-factor");
2034+ else
2035+ g_settings_set_double (manager->priv->interface_settings, "text-scaling-factor", best);
2036+}
2037+
2038+static void
2039+do_magnifier_zoom_action (GsdMediaKeysManager *manager,
2040+ MediaKeyType type)
2041+{
2042+ GSettings *settings;
2043+ gdouble offset, value;
2044+
2045+ if (type == MAGNIFIER_ZOOM_IN_KEY)
2046+ offset = 1.0;
2047+ else
2048+ offset = -1.0;
2049+
2050+ settings = g_settings_new ("org.gnome.desktop.a11y.magnifier");
2051+ value = g_settings_get_double (settings, "mag-factor");
2052+ value += offset;
2053+ value = roundl (value);
2054+ g_settings_set_double (settings, "mag-factor", value);
2055+ g_object_unref (settings);
2056+}
2057+
2058+static void
2059+do_toggle_contrast_action (GsdMediaKeysManager *manager)
2060+{
2061+ gboolean high_contrast;
2062+ char *theme;
2063+
2064+ /* Are we using HighContrast now? */
2065+ theme = g_settings_get_string (manager->priv->interface_settings, "gtk-theme");
2066+ high_contrast = g_str_equal (theme, HIGH_CONTRAST);
2067+ g_free (theme);
2068+
2069+ if (high_contrast != FALSE) {
2070+ if (manager->priv->gtk_theme == NULL)
2071+ g_settings_reset (manager->priv->interface_settings, "gtk-theme");
2072+ else
2073+ g_settings_set (manager->priv->interface_settings, "gtk-theme", manager->priv->gtk_theme);
2074+ g_settings_set (manager->priv->interface_settings, "icon-theme", manager->priv->icon_theme);
2075+ } else {
2076+ g_settings_set (manager->priv->interface_settings, "gtk-theme", HIGH_CONTRAST);
2077+ g_settings_set (manager->priv->interface_settings, "icon-theme", HIGH_CONTRAST);
2078+ }
2079+}
2080+
2081+static void
2082+upower_sleep_cb (GObject *source_object,
2083+ GAsyncResult *res,
2084+ gpointer user_data)
2085+{
2086+ GVariant *result;
2087+ GError *error = NULL;
2088+
2089+ result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
2090+ res,
2091+ &error);
2092+ if (result == NULL) {
2093+ g_warning ("couldn't sleep using UPower: %s",
2094+ error->message);
2095+ g_error_free (error);
2096+ } else {
2097+ g_variant_unref (result);
2098+ }
2099+}
2100+
2101+static void
2102+do_config_power_action (GsdMediaKeysManager *manager,
2103+ const gchar *config_key)
2104+{
2105+ GsdPowerActionType action_type;
2106+
2107+ action_type = g_settings_get_enum (manager->priv->power_settings,
2108+ config_key);
2109+ switch (action_type) {
2110+ case GSD_POWER_ACTION_SUSPEND:
2111+ g_dbus_proxy_call (manager->priv->upower_proxy,
2112+ "Suspend",
2113+ NULL,
2114+ G_DBUS_CALL_FLAGS_NONE,
2115+ -1, NULL,
2116+ upower_sleep_cb, NULL);
2117+ break;
2118+ case GSD_POWER_ACTION_INTERACTIVE:
2119+ case GSD_POWER_ACTION_SHUTDOWN:
2120+ gnome_session_shutdown (manager);
2121+ break;
2122+ case GSD_POWER_ACTION_HIBERNATE:
2123+ g_dbus_proxy_call (manager->priv->upower_proxy,
2124+ "Hibernate",
2125+ NULL,
2126+ G_DBUS_CALL_FLAGS_NONE,
2127+ -1, NULL,
2128+ upower_sleep_cb, NULL);
2129+ break;
2130+ case GSD_POWER_ACTION_BLANK:
2131+ case GSD_POWER_ACTION_NOTHING:
2132+ /* these actions cannot be handled by media-keys and
2133+ * are not used in this context */
2134+ break;
2135+ }
2136+}
2137+
2138+static void
2139+update_screen_cb (GObject *source_object,
2140+ GAsyncResult *res,
2141+ gpointer user_data)
2142+{
2143+ GError *error = NULL;
2144+ guint percentage;
2145+ GVariant *new_percentage;
2146+ GsdBrightnessActionData *data = (GsdBrightnessActionData *) user_data;
2147+ GsdMediaKeysManager *manager = data->manager;
2148+
2149+ new_percentage = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
2150+ res, &error);
2151+ if (new_percentage == NULL) {
2152+ g_warning ("Failed to set new screen percentage: %s",
2153+ error->message);
2154+ g_error_free (error);
2155+ g_free (data);
2156+ return;
2157+ }
2158+
2159+ /* update the dialog with the new value */
2160+ g_variant_get (new_percentage, "(u)", &percentage);
2161+
2162+ guint osd_percentage;
2163+ if (data->old_percentage == 100 && data->type == SCREEN_BRIGHTNESS_UP_KEY)
2164+ osd_percentage = 101;
2165+ else if (data->old_percentage == 0 && data->type == SCREEN_BRIGHTNESS_DOWN_KEY)
2166+ osd_percentage = -1;
2167+ else
2168+ osd_percentage = CLAMP (percentage, 0, 100);
2169+
2170+ if (!ubuntu_osd_notification_show_brightness (manager, osd_percentage)) {
2171+ dialog_init (manager);
2172+ gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
2173+ "display-brightness-symbolic",
2174+ TRUE);
2175+ gsd_media_keys_window_set_volume_level (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
2176+ percentage);
2177+ dialog_show (manager);
2178+ }
2179+ g_free (data);
2180+ g_variant_unref (new_percentage);
2181+}
2182+
2183+static void
2184+do_screen_brightness_action_real (GObject *source_object,
2185+ GAsyncResult *res,
2186+ gpointer user_data)
2187+{
2188+ GsdBrightnessActionData *data = (GsdBrightnessActionData *) user_data;
2189+ GsdMediaKeysManager *manager = data->manager;
2190+ GError *error = NULL;
2191+
2192+ GVariant *old_percentage = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
2193+ res, &error);
2194+ if (old_percentage == NULL) {
2195+ g_warning ("Failed to get old screen percentage: %s", error->message);
2196+ g_error_free (error);
2197+ g_free (data);
2198+ return;
2199+ }
2200+
2201+ g_variant_get (old_percentage, "(u)", &data->old_percentage);
2202+
2203+ /* call into the power plugin */
2204+ g_dbus_proxy_call (manager->priv->power_screen_proxy,
2205+ data->type == SCREEN_BRIGHTNESS_UP_KEY ? "StepUp" : "StepDown",
2206+ NULL,
2207+ G_DBUS_CALL_FLAGS_NONE,
2208+ -1,
2209+ NULL,
2210+ update_screen_cb,
2211+ data);
2212+
2213+ g_variant_unref (old_percentage);
2214+}
2215+
2216+static void
2217+do_screen_brightness_action (GsdMediaKeysManager *manager,
2218+ MediaKeyType type)
2219+{
2220+ if (manager->priv->connection == NULL ||
2221+ manager->priv->power_screen_proxy == NULL) {
2222+ g_warning ("No existing D-Bus connection trying to handle power keys");
2223+ return;
2224+ }
2225+
2226+ GsdBrightnessActionData *data = g_new0 (GsdBrightnessActionData, 1);
2227+ data->manager = manager;
2228+ data->type = type;
2229+
2230+ g_dbus_proxy_call (manager->priv->power_screen_proxy,
2231+ "GetPercentage",
2232+ NULL,
2233+ G_DBUS_CALL_FLAGS_NONE,
2234+ -1,
2235+ NULL,
2236+ do_screen_brightness_action_real,
2237+ data);
2238+}
2239+
2240+static void
2241+update_keyboard_cb (GObject *source_object,
2242+ GAsyncResult *res,
2243+ gpointer user_data)
2244+{
2245+ GError *error = NULL;
2246+ guint percentage;
2247+ GVariant *new_percentage;
2248+ GsdMediaKeysManager *manager = GSD_MEDIA_KEYS_MANAGER (user_data);
2249+
2250+ new_percentage = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
2251+ res, &error);
2252+ if (new_percentage == NULL) {
2253+ g_warning ("Failed to set new keyboard percentage: %s",
2254+ error->message);
2255+ g_error_free (error);
2256+ return;
2257+ }
2258+
2259+ /* update the dialog with the new value */
2260+ g_variant_get (new_percentage, "(u)", &percentage);
2261+
2262+ /* FIXME: No overshoot effect for keyboard, as the power plugin has no interface
2263+ * to get the old brightness */
2264+ if (!ubuntu_osd_notification_show_kb_backlight (manager, CLAMP (percentage, 0, 100))) {
2265+ dialog_init (manager);
2266+ gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
2267+ "keyboard-brightness-symbolic",
2268+ TRUE);
2269+ gsd_media_keys_window_set_volume_level (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
2270+ percentage);
2271+ dialog_show (manager);
2272+ }
2273+ g_variant_unref (new_percentage);
2274+}
2275+
2276+static void
2277+do_keyboard_brightness_action (GsdMediaKeysManager *manager,
2278+ MediaKeyType type)
2279+{
2280+ if (manager->priv->connection == NULL ||
2281+ manager->priv->power_keyboard_proxy == NULL) {
2282+ g_warning ("No existing D-Bus connection trying to handle power keys");
2283+ return;
2284+ }
2285+
2286+ /* call into the power plugin */
2287+ g_dbus_proxy_call (manager->priv->power_keyboard_proxy,
2288+ type == KEYBOARD_BRIGHTNESS_UP_KEY ? "StepUp" : "StepDown",
2289+ NULL,
2290+ G_DBUS_CALL_FLAGS_NONE,
2291+ -1,
2292+ NULL,
2293+ update_keyboard_cb,
2294+ manager);
2295+}
2296+
2297+static void
2298+do_custom_action (GsdMediaKeysManager *manager,
2299+ MediaKey *key,
2300+ gint64 timestamp)
2301+{
2302+ execute (manager, key->custom_command, FALSE);
2303+}
2304+
2305+static gboolean
2306+do_action (GsdMediaKeysManager *manager,
2307+ guint deviceid,
2308+ MediaKeyType type,
2309+ gint64 timestamp)
2310+{
2311+ char *cmd;
2312+
2313+ g_debug ("Launching action for key type '%d' (on device id %d)", type, deviceid);
2314+
2315+ switch (type) {
2316+ case TOUCHPAD_KEY:
2317+ do_touchpad_action (manager);
2318+ break;
2319+ case TOUCHPAD_ON_KEY:
2320+ do_touchpad_osd_action (manager, TRUE);
2321+ break;
2322+ case TOUCHPAD_OFF_KEY:
2323+ do_touchpad_osd_action (manager, FALSE);
2324+ break;
2325+ case MUTE_KEY:
2326+ case VOLUME_DOWN_KEY:
2327+ case VOLUME_UP_KEY:
2328+ do_sound_action (manager, deviceid, type, FALSE);
2329+ break;
2330+ case MUTE_QUIET_KEY:
2331+ do_sound_action (manager, deviceid, MUTE_KEY, TRUE);
2332+ break;
2333+ case VOLUME_DOWN_QUIET_KEY:
2334+ do_sound_action (manager, deviceid, VOLUME_DOWN_KEY, TRUE);
2335+ break;
2336+ case VOLUME_UP_QUIET_KEY:
2337+ do_sound_action (manager, deviceid, VOLUME_UP_KEY, TRUE);
2338+ break;
2339+ case LOGOUT_KEY:
2340+ do_logout_action (manager);
2341+ break;
2342+ case EJECT_KEY:
2343+ do_eject_action (manager);
2344+ break;
2345+ case HOME_KEY:
2346+ do_home_key_action (manager, timestamp);
2347+ break;
2348+ case SEARCH_KEY:
2349+ cmd = NULL;
2350+ if ((cmd = g_find_program_in_path ("tracker-search-tool")))
2351+ do_execute_desktop (manager, "tracker-needle.desktop", timestamp);
2352+ else
2353+ do_execute_desktop (manager, "gnome-search-tool.desktop", timestamp);
2354+ g_free (cmd);
2355+ break;
2356+ case EMAIL_KEY:
2357+ do_url_action (manager, "mailto", timestamp);
2358+ break;
2359+ case SCREENSAVER_KEY:
2360+ execute (manager, "gnome-screensaver-command --lock", FALSE);
2361+ break;
2362+ case HELP_KEY:
2363+ do_url_action (manager, "ghelp", timestamp);
2364+ break;
2365+ case SCREENSHOT_KEY:
2366+ execute (manager, "gnome-screenshot", FALSE);
2367+ break;
2368+ case WINDOW_SCREENSHOT_KEY:
2369+ execute (manager, "gnome-screenshot --window", FALSE);
2370+ break;
2371+ case AREA_SCREENSHOT_KEY:
2372+ execute (manager, "gnome-screenshot --area", FALSE);
2373+ break;
2374+ case SCREENSHOT_CLIP_KEY:
2375+ execute (manager, "gnome-screenshot --clipboard", FALSE);
2376+ break;
2377+ case WINDOW_SCREENSHOT_CLIP_KEY:
2378+ execute (manager, "gnome-screenshot --window --clipboard", FALSE);
2379+ break;
2380+ case AREA_SCREENSHOT_CLIP_KEY:
2381+ execute (manager, "gnome-screenshot --area --clipboard", FALSE);
2382+ break;
2383+ case WWW_KEY:
2384+ do_url_action (manager, "http", timestamp);
2385+ break;
2386+ case MEDIA_KEY:
2387+ do_media_action (manager, timestamp);
2388+ break;
2389+ case CALCULATOR_KEY:
2390+ do_execute_desktop (manager, "gcalctool.desktop", timestamp);
2391+ break;
2392+ case PLAY_KEY:
2393+ return do_multimedia_player_action (manager, NULL, "Play");
2394+ case PAUSE_KEY:
2395+ return do_multimedia_player_action (manager, NULL, "Pause");
2396+ case STOP_KEY:
2397+ return do_multimedia_player_action (manager, NULL, "Stop");
2398+ case PREVIOUS_KEY:
2399+ return do_multimedia_player_action (manager, NULL, "Previous");
2400+ case NEXT_KEY:
2401+ return do_multimedia_player_action (manager, NULL, "Next");
2402+ case REWIND_KEY:
2403+ return do_multimedia_player_action (manager, NULL, "Rewind");
2404+ case FORWARD_KEY:
2405+ return do_multimedia_player_action (manager, NULL, "FastForward");
2406+ case REPEAT_KEY:
2407+ return do_multimedia_player_action (manager, NULL, "Repeat");
2408+ case RANDOM_KEY:
2409+ return do_multimedia_player_action (manager, NULL, "Shuffle");
2410+ case VIDEO_OUT_KEY:
2411+ do_video_out_action (manager, timestamp);
2412+ break;
2413+ case ROTATE_VIDEO_KEY:
2414+ do_video_rotate_action (manager, timestamp);
2415+ break;
2416+ case MAGNIFIER_KEY:
2417+ do_magnifier_action (manager);
2418+ break;
2419+ case SCREENREADER_KEY:
2420+ do_screenreader_action (manager);
2421+ break;
2422+ case ON_SCREEN_KEYBOARD_KEY:
2423+ do_on_screen_keyboard_action (manager);
2424+ break;
2425+ case INCREASE_TEXT_KEY:
2426+ case DECREASE_TEXT_KEY:
2427+ do_text_size_action (manager, type);
2428+ break;
2429+ case MAGNIFIER_ZOOM_IN_KEY:
2430+ case MAGNIFIER_ZOOM_OUT_KEY:
2431+ do_magnifier_zoom_action (manager, type);
2432+ break;
2433+ case TOGGLE_CONTRAST_KEY:
2434+ do_toggle_contrast_action (manager);
2435+ break;
2436+ case POWER_KEY:
2437+ do_config_power_action (manager, "button-power");
2438+ break;
2439+ case SLEEP_KEY:
2440+ do_config_power_action (manager, "button-sleep");
2441+ break;
2442+ case SUSPEND_KEY:
2443+ do_config_power_action (manager, "button-suspend");
2444+ break;
2445+ case HIBERNATE_KEY:
2446+ do_config_power_action (manager, "button-hibernate");
2447+ break;
2448+ case SCREEN_BRIGHTNESS_UP_KEY:
2449+ case SCREEN_BRIGHTNESS_DOWN_KEY:
2450+ do_screen_brightness_action (manager, type);
2451+ break;
2452+ case KEYBOARD_BRIGHTNESS_UP_KEY:
2453+ case KEYBOARD_BRIGHTNESS_DOWN_KEY:
2454+ case KEYBOARD_BRIGHTNESS_TOGGLE_KEY:
2455+ do_keyboard_brightness_action (manager, type);
2456+ break;
2457+ case BATTERY_KEY:
2458+ do_execute_desktop (manager, "gnome-power-statistics.desktop", timestamp);
2459+ break;
2460+ /* Note, no default so compiler catches missing keys */
2461+ case CUSTOM_KEY:
2462+ g_assert_not_reached ();
2463+ }
2464+
2465+ return FALSE;
2466+}
2467+
2468+static GdkScreen *
2469+get_screen_from_root (GsdMediaKeysManager *manager,
2470+ Window root)
2471+{
2472+ GSList *l;
2473+
2474+ /* Look for which screen we're receiving events */
2475+ for (l = manager->priv->screens; l != NULL; l = l->next) {
2476+ GdkScreen *screen = (GdkScreen *) l->data;
2477+ GdkWindow *window = gdk_screen_get_root_window (screen);
2478+
2479+ if (GDK_WINDOW_XID (window) == root)
2480+ return screen;
2481+ }
2482+
2483+ return NULL;
2484+}
2485+
2486+static GdkFilterReturn
2487+filter_key_events (XEvent *xevent,
2488+ GdkEvent *event,
2489+ GsdMediaKeysManager *manager)
2490+{
2491+ XIEvent *xiev;
2492+ XIDeviceEvent *xev;
2493+ XGenericEventCookie *cookie;
2494+ guint i;
2495+ guint deviceid;
2496+
2497+ /* verify we have a key event */
2498+ if (xevent->type != GenericEvent)
2499+ return GDK_FILTER_CONTINUE;
2500+ cookie = &xevent->xcookie;
2501+ if (cookie->extension != manager->priv->opcode)
2502+ return GDK_FILTER_CONTINUE;
2503+
2504+ xiev = (XIEvent *) xevent->xcookie.data;
2505+
2506+ if (xiev->evtype != XI_KeyPress &&
2507+ xiev->evtype != XI_KeyRelease)
2508+ return GDK_FILTER_CONTINUE;
2509+
2510+ xev = (XIDeviceEvent *) xiev;
2511+
2512+ deviceid = xev->sourceid;
2513+
2514+ for (i = 0; i < manager->priv->keys->len; i++) {
2515+ MediaKey *key;
2516+
2517+ key = g_ptr_array_index (manager->priv->keys, i);
2518+
2519+ if (match_xi2_key (key->key, xev)) {
2520+ switch (key->key_type) {
2521+ case VOLUME_DOWN_KEY:
2522+ case VOLUME_UP_KEY:
2523+ case VOLUME_DOWN_QUIET_KEY:
2524+ case VOLUME_UP_QUIET_KEY:
2525+ /* auto-repeatable keys */
2526+ if (xiev->evtype != XI_KeyPress)
2527+ return GDK_FILTER_CONTINUE;
2528+ break;
2529+ default:
2530+ if (xiev->evtype != XI_KeyRelease) {
2531+ return GDK_FILTER_CONTINUE;
2532+ }
2533+ }
2534+
2535+ manager->priv->current_screen = get_screen_from_root (manager, xev->root);
2536+
2537+ if (key->key_type == CUSTOM_KEY) {
2538+ do_custom_action (manager, key, xev->time);
2539+ return GDK_FILTER_REMOVE;
2540+ }
2541+
2542+ if (do_action (manager, deviceid, key->key_type, xev->time) == FALSE) {
2543+ return GDK_FILTER_REMOVE;
2544+ } else {
2545+ return GDK_FILTER_CONTINUE;
2546+ }
2547+ }
2548+ }
2549+
2550+ return GDK_FILTER_CONTINUE;
2551+}
2552+
2553+static void
2554+update_theme_settings (GSettings *settings,
2555+ const char *key,
2556+ GsdMediaKeysManager *manager)
2557+{
2558+ char *theme;
2559+
2560+ theme = g_settings_get_string (manager->priv->interface_settings, key);
2561+ if (g_str_equal (theme, HIGH_CONTRAST)) {
2562+ g_free (theme);
2563+ } else {
2564+ if (g_str_equal (key, "gtk-theme")) {
2565+ g_free (manager->priv->gtk_theme);
2566+ manager->priv->gtk_theme = theme;
2567+ } else {
2568+ g_free (manager->priv->icon_theme);
2569+ manager->priv->icon_theme = theme;
2570+ }
2571+ }
2572+}
2573+
2574+static gboolean
2575+start_media_keys_idle_cb (GsdMediaKeysManager *manager)
2576+{
2577+ GSList *l;
2578+ char *theme_name;
2579+
2580+ g_debug ("Starting media_keys manager");
2581+ gnome_settings_profile_start (NULL);
2582+
2583+
2584+ gvc_mixer_control_open (manager->priv->volume);
2585+
2586+ manager->priv->settings = g_settings_new (SETTINGS_BINDING_DIR);
2587+ g_signal_connect (G_OBJECT (manager->priv->settings), "changed",
2588+ G_CALLBACK (gsettings_changed_cb), manager);
2589+
2590+ manager->priv->gconf = gconf_client_get_default ();
2591+ gconf_client_add_dir (manager->priv->gconf, GCONF_BINDING_DIR, GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
2592+ manager->priv->gconf_id = gconf_client_notify_add (manager->priv->gconf,
2593+ GCONF_BINDING_DIR,
2594+ (GConfClientNotifyFunc) gconf_changed_cb,
2595+ manager,
2596+ NULL,
2597+ NULL);
2598+
2599+ /* Sound events */
2600+ ca_context_create (&manager->priv->ca);
2601+ ca_context_set_driver (manager->priv->ca, "pulse");
2602+ ca_context_change_props (manager->priv->ca, 0,
2603+ CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl",
2604+ NULL);
2605+ manager->priv->gtksettings = gtk_settings_get_for_screen (gdk_screen_get_default ());
2606+ g_object_get (G_OBJECT (manager->priv->gtksettings), "gtk-sound-theme-name", &theme_name, NULL);
2607+ if (theme_name)
2608+ ca_context_change_props (manager->priv->ca, CA_PROP_CANBERRA_XDG_THEME_NAME, theme_name, NULL);
2609+ g_free (theme_name);
2610+ g_signal_connect (manager->priv->gtksettings, "notify::gtk-sound-theme-name",
2611+ G_CALLBACK (sound_theme_changed), manager);
2612+
2613+ /* for the power plugin interface code */
2614+ manager->priv->power_settings = g_settings_new (SETTINGS_POWER_DIR);
2615+
2616+ /* Logic from http://git.gnome.org/browse/gnome-shell/tree/js/ui/status/accessibility.js#n163 */
2617+ manager->priv->interface_settings = g_settings_new (SETTINGS_INTERFACE_DIR);
2618+ g_signal_connect (G_OBJECT (manager->priv->interface_settings), "changed::gtk-theme",
2619+ G_CALLBACK (update_theme_settings), manager);
2620+ g_signal_connect (G_OBJECT (manager->priv->interface_settings), "changed::icon-theme",
2621+ G_CALLBACK (update_theme_settings), manager);
2622+ manager->priv->gtk_theme = g_settings_get_string (manager->priv->interface_settings, "gtk-theme");
2623+ if (g_str_equal (manager->priv->gtk_theme, HIGH_CONTRAST)) {
2624+ g_free (manager->priv->gtk_theme);
2625+ manager->priv->gtk_theme = NULL;
2626+ }
2627+ manager->priv->icon_theme = g_settings_get_string (manager->priv->interface_settings, "icon-theme");
2628+
2629+ init_screens (manager);
2630+ init_kbd (manager);
2631+
2632+ /* Start filtering the events */
2633+ for (l = manager->priv->screens; l != NULL; l = l->next) {
2634+ gnome_settings_profile_start ("gdk_window_add_filter");
2635+
2636+ g_debug ("adding key filter for screen: %d",
2637+ gdk_screen_get_number (l->data));
2638+
2639+ gdk_window_add_filter (gdk_screen_get_root_window (l->data),
2640+ (GdkFilterFunc) filter_key_events,
2641+ manager);
2642+ gnome_settings_profile_end ("gdk_window_add_filter");
2643+ }
2644+
2645+ gnome_settings_profile_end (NULL);
2646+
2647+ manager->priv->start_idle_id = 0;
2648+
2649+ return FALSE;
2650+}
2651+
2652+gboolean
2653+gsd_media_keys_manager_start (GsdMediaKeysManager *manager,
2654+ GError **error)
2655+{
2656+ const char * const subsystems[] = { "input", "usb", "sound", NULL };
2657+
2658+ gnome_settings_profile_start (NULL);
2659+
2660+ if (supports_xinput2_devices (&manager->priv->opcode) == FALSE) {
2661+ g_debug ("No Xinput2 support, disabling plugin");
2662+ return TRUE;
2663+ }
2664+
2665+#ifdef HAVE_GUDEV
2666+ manager->priv->streams = g_hash_table_new (g_direct_hash, g_direct_equal);
2667+ manager->priv->udev_client = g_udev_client_new (subsystems);
2668+#endif
2669+
2670+ /* initialise Volume handler
2671+ *
2672+ * We do this one here to force checking gstreamer cache, etc.
2673+ * The rest (grabbing and setting the keys) can happen in an
2674+ * idle.
2675+ */
2676+ gnome_settings_profile_start ("gvc_mixer_control_new");
2677+
2678+ manager->priv->volume = gvc_mixer_control_new ("GNOME Volume Control Media Keys");
2679+
2680+ g_signal_connect (manager->priv->volume,
2681+ "state-changed",
2682+ G_CALLBACK (on_control_state_changed),
2683+ manager);
2684+ g_signal_connect (manager->priv->volume,
2685+ "default-sink-changed",
2686+ G_CALLBACK (on_control_default_sink_changed),
2687+ manager);
2688+ g_signal_connect (manager->priv->volume,
2689+ "stream-removed",
2690+ G_CALLBACK (on_control_stream_removed),
2691+ manager);
2692+
2693+ gnome_settings_profile_end ("gvc_mixer_control_new");
2694+
2695+ manager->priv->start_idle_id = g_idle_add ((GSourceFunc) start_media_keys_idle_cb, manager);
2696+
2697+ register_manager (manager_object);
2698+
2699+ gnome_settings_profile_end (NULL);
2700+
2701+ return TRUE;
2702+}
2703+
2704+void
2705+gsd_media_keys_manager_stop (GsdMediaKeysManager *manager)
2706+{
2707+ GsdMediaKeysManagerPrivate *priv = manager->priv;
2708+ GSList *ls;
2709+ GList *l;
2710+ int i;
2711+
2712+ g_debug ("Stopping media_keys manager");
2713+
2714+ if (priv->bus_cancellable != NULL) {
2715+ g_cancellable_cancel (priv->bus_cancellable);
2716+ g_object_unref (priv->bus_cancellable);
2717+ priv->bus_cancellable = NULL;
2718+ }
2719+
2720+ for (ls = priv->screens; ls != NULL; ls = ls->next) {
2721+ gdk_window_remove_filter (gdk_screen_get_root_window (ls->data),
2722+ (GdkFilterFunc) filter_key_events,
2723+ manager);
2724+ }
2725+
2726+ if (manager->priv->gtksettings != NULL) {
2727+ g_signal_handlers_disconnect_by_func (manager->priv->gtksettings, sound_theme_changed, manager);
2728+ manager->priv->gtksettings = NULL;
2729+ }
2730+
2731+ if (manager->priv->ca) {
2732+ ca_context_destroy (manager->priv->ca);
2733+ manager->priv->ca = NULL;
2734+ }
2735+
2736+#ifdef HAVE_GUDEV
2737+ if (priv->streams) {
2738+ g_hash_table_destroy (priv->streams);
2739+ priv->streams = NULL;
2740+ }
2741+ if (priv->udev_client) {
2742+ g_object_unref (priv->udev_client);
2743+ priv->udev_client = NULL;
2744+ }
2745+#endif /* HAVE_GUDEV */
2746+
2747+ if (priv->settings) {
2748+ g_object_unref (priv->settings);
2749+ priv->settings = NULL;
2750+ }
2751+
2752+ if (priv->power_settings) {
2753+ g_object_unref (priv->power_settings);
2754+ priv->power_settings = NULL;
2755+ }
2756+
2757+ if (priv->power_screen_proxy) {
2758+ g_object_unref (priv->power_screen_proxy);
2759+ priv->power_screen_proxy = NULL;
2760+ }
2761+
2762+ if (priv->power_keyboard_proxy) {
2763+ g_object_unref (priv->power_keyboard_proxy);
2764+ priv->power_keyboard_proxy = NULL;
2765+ }
2766+
2767+ if (priv->upower_proxy) {
2768+ g_object_unref (priv->upower_proxy);
2769+ priv->upower_proxy = NULL;
2770+ }
2771+
2772+ if (priv->cancellable != NULL) {
2773+ g_cancellable_cancel (priv->cancellable);
2774+ g_object_unref (priv->cancellable);
2775+ priv->cancellable = NULL;
2776+ }
2777+
2778+ if (priv->introspection_data) {
2779+ g_dbus_node_info_unref (priv->introspection_data);
2780+ priv->introspection_data = NULL;
2781+ }
2782+
2783+ if (priv->connection != NULL) {
2784+ g_object_unref (priv->connection);
2785+ priv->connection = NULL;
2786+ }
2787+
2788+ if (priv->volume_notification != NULL) {
2789+ notify_notification_close (priv->volume_notification, NULL);
2790+ g_object_unref (priv->volume_notification);
2791+ priv->volume_notification = NULL;
2792+ }
2793+
2794+ if (priv->brightness_notification != NULL) {
2795+ notify_notification_close (priv->brightness_notification, NULL);
2796+ g_object_unref (priv->brightness_notification);
2797+ priv->brightness_notification = NULL;
2798+ }
2799+
2800+ if (priv->kb_backlight_notification != NULL) {
2801+ notify_notification_close (priv->kb_backlight_notification, NULL);
2802+ g_object_unref (priv->kb_backlight_notification);
2803+ priv->kb_backlight_notification = NULL;
2804+ }
2805+
2806+ if (priv->keys != NULL) {
2807+ gdk_error_trap_push ();
2808+ for (i = 0; i < priv->keys->len; ++i) {
2809+ MediaKey *key;
2810+
2811+ key = g_ptr_array_index (manager->priv->keys, i);
2812+
2813+ if (key->key)
2814+ grab_key_unsafe (key->key, FALSE, priv->screens);
2815+ }
2816+ g_ptr_array_free (priv->keys, TRUE);
2817+ priv->keys = NULL;
2818+
2819+ gdk_flush ();
2820+ gdk_error_trap_pop_ignored ();
2821+ }
2822+
2823+ if (priv->gconf_id) {
2824+ gconf_client_remove_dir (priv->gconf, GCONF_BINDING_DIR, NULL);
2825+ gconf_client_notify_remove (priv->gconf, priv->gconf_id);
2826+ priv->gconf_id = 0;
2827+ }
2828+
2829+ if (priv->gconf) {
2830+ g_object_unref (priv->gconf);
2831+ priv->gconf = NULL;
2832+ }
2833+
2834+ if (priv->screens != NULL) {
2835+ g_slist_free (priv->screens);
2836+ priv->screens = NULL;
2837+ }
2838+
2839+ if (priv->stream) {
2840+ g_object_unref (priv->stream);
2841+ priv->stream = NULL;
2842+ }
2843+
2844+ if (priv->volume) {
2845+ g_object_unref (priv->volume);
2846+ priv->volume = NULL;
2847+ }
2848+
2849+ if (priv->dialog != NULL) {
2850+ gtk_widget_destroy (priv->dialog);
2851+ priv->dialog = NULL;
2852+ }
2853+
2854+ if (priv->media_players != NULL) {
2855+ for (l = priv->media_players; l; l = l->next) {
2856+ MediaPlayer *mp = l->data;
2857+ g_free (mp->application);
2858+ g_free (mp);
2859+ }
2860+ g_list_free (priv->media_players);
2861+ priv->media_players = NULL;
2862+ }
2863+}
2864+
2865+static GObject *
2866+gsd_media_keys_manager_constructor (GType type,
2867+ guint n_construct_properties,
2868+ GObjectConstructParam *construct_properties)
2869+{
2870+ GsdMediaKeysManager *media_keys_manager;
2871+
2872+ media_keys_manager = GSD_MEDIA_KEYS_MANAGER (G_OBJECT_CLASS (gsd_media_keys_manager_parent_class)->constructor (type,
2873+ n_construct_properties,
2874+ construct_properties));
2875+
2876+ return G_OBJECT (media_keys_manager);
2877+}
2878+
2879+static void
2880+gsd_media_keys_manager_class_init (GsdMediaKeysManagerClass *klass)
2881+{
2882+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
2883+
2884+ object_class->constructor = gsd_media_keys_manager_constructor;
2885+ object_class->finalize = gsd_media_keys_manager_finalize;
2886+
2887+ g_type_class_add_private (klass, sizeof (GsdMediaKeysManagerPrivate));
2888+}
2889+
2890+static void
2891+gsd_media_keys_manager_init (GsdMediaKeysManager *manager)
2892+{
2893+ manager->priv = GSD_MEDIA_KEYS_MANAGER_GET_PRIVATE (manager);
2894+}
2895+
2896+static void
2897+gsd_media_keys_manager_finalize (GObject *object)
2898+{
2899+ GsdMediaKeysManager *media_keys_manager;
2900+
2901+ g_return_if_fail (object != NULL);
2902+ g_return_if_fail (GSD_IS_MEDIA_KEYS_MANAGER (object));
2903+
2904+ media_keys_manager = GSD_MEDIA_KEYS_MANAGER (object);
2905+
2906+ g_return_if_fail (media_keys_manager->priv != NULL);
2907+
2908+ if (media_keys_manager->priv->start_idle_id != 0)
2909+ g_source_remove (media_keys_manager->priv->start_idle_id);
2910+
2911+ G_OBJECT_CLASS (gsd_media_keys_manager_parent_class)->finalize (object);
2912+}
2913+
2914+static void
2915+xrandr_ready_cb (GObject *source_object,
2916+ GAsyncResult *res,
2917+ GsdMediaKeysManager *manager)
2918+{
2919+ GError *error = NULL;
2920+
2921+ manager->priv->xrandr_proxy = g_dbus_proxy_new_finish (res, &error);
2922+ if (manager->priv->xrandr_proxy == NULL) {
2923+ g_warning ("Failed to get proxy for XRandR operations: %s", error->message);
2924+ g_error_free (error);
2925+ }
2926+}
2927+
2928+static void
2929+upower_ready_cb (GObject *source_object,
2930+ GAsyncResult *res,
2931+ GsdMediaKeysManager *manager)
2932+{
2933+ GError *error = NULL;
2934+
2935+ manager->priv->upower_proxy = g_dbus_proxy_new_finish (res, &error);
2936+ if (manager->priv->upower_proxy == NULL) {
2937+ g_warning ("Failed to get proxy for upower: %s",
2938+ error->message);
2939+ g_error_free (error);
2940+ }
2941+}
2942+
2943+static void
2944+power_screen_ready_cb (GObject *source_object,
2945+ GAsyncResult *res,
2946+ GsdMediaKeysManager *manager)
2947+{
2948+ GError *error = NULL;
2949+
2950+ manager->priv->power_screen_proxy = g_dbus_proxy_new_finish (res, &error);
2951+ if (manager->priv->power_screen_proxy == NULL) {
2952+ g_warning ("Failed to get proxy for power (screen): %s",
2953+ error->message);
2954+ g_error_free (error);
2955+ }
2956+}
2957+
2958+static void
2959+power_keyboard_ready_cb (GObject *source_object,
2960+ GAsyncResult *res,
2961+ GsdMediaKeysManager *manager)
2962+{
2963+ GError *error = NULL;
2964+
2965+ manager->priv->power_keyboard_proxy = g_dbus_proxy_new_finish (res, &error);
2966+ if (manager->priv->power_keyboard_proxy == NULL) {
2967+ g_warning ("Failed to get proxy for power (keyboard): %s",
2968+ error->message);
2969+ g_error_free (error);
2970+ }
2971+}
2972+
2973+static void
2974+on_bus_gotten (GObject *source_object,
2975+ GAsyncResult *res,
2976+ GsdMediaKeysManager *manager)
2977+{
2978+ GDBusConnection *connection;
2979+ GError *error = NULL;
2980+
2981+ if (manager->priv->bus_cancellable == NULL ||
2982+ g_cancellable_is_cancelled (manager->priv->bus_cancellable)) {
2983+ g_warning ("Operation has been cancelled, so not retrieving session bus");
2984+ return;
2985+ }
2986+
2987+ connection = g_bus_get_finish (res, &error);
2988+ if (connection == NULL) {
2989+ g_warning ("Could not get session bus: %s", error->message);
2990+ g_error_free (error);
2991+ return;
2992+ }
2993+ manager->priv->connection = connection;
2994+
2995+ g_dbus_connection_register_object (connection,
2996+ GSD_MEDIA_KEYS_DBUS_PATH,
2997+ manager->priv->introspection_data->interfaces[0],
2998+ &interface_vtable,
2999+ manager,
3000+ NULL,
3001+ NULL);
3002+
3003+ g_dbus_proxy_new (manager->priv->connection,
3004+ G_DBUS_PROXY_FLAGS_NONE,
3005+ NULL,
3006+ "org.gnome.SettingsDaemon",
3007+ "/org/gnome/SettingsDaemon/XRANDR",
3008+ "org.gnome.SettingsDaemon.XRANDR_2",
3009+ NULL,
3010+ (GAsyncReadyCallback) xrandr_ready_cb,
3011+ manager);
3012+
3013+ g_dbus_proxy_new (manager->priv->connection,
3014+ G_DBUS_PROXY_FLAGS_NONE,
3015+ NULL,
3016+ "org.gnome.SettingsDaemon",
3017+ "/org/gnome/SettingsDaemon/Power",
3018+ "org.gnome.SettingsDaemon.Power.Screen",
3019+ NULL,
3020+ (GAsyncReadyCallback) power_screen_ready_cb,
3021+ manager);
3022+
3023+ g_dbus_proxy_new (manager->priv->connection,
3024+ G_DBUS_PROXY_FLAGS_NONE,
3025+ NULL,
3026+ "org.gnome.SettingsDaemon",
3027+ "/org/gnome/SettingsDaemon/Power",
3028+ "org.gnome.SettingsDaemon.Power.Keyboard",
3029+ NULL,
3030+ (GAsyncReadyCallback) power_keyboard_ready_cb,
3031+ manager);
3032+}
3033+
3034+static void
3035+register_manager (GsdMediaKeysManager *manager)
3036+{
3037+ manager->priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
3038+ manager->priv->bus_cancellable = g_cancellable_new ();
3039+ g_assert (manager->priv->introspection_data != NULL);
3040+
3041+ g_bus_get (G_BUS_TYPE_SESSION,
3042+ manager->priv->bus_cancellable,
3043+ (GAsyncReadyCallback) on_bus_gotten,
3044+ manager);
3045+
3046+ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
3047+ G_DBUS_PROXY_FLAGS_NONE,
3048+ NULL,
3049+ "org.freedesktop.UPower",
3050+ "/org/freedesktop/UPower",
3051+ "org.freedesktop.UPower",
3052+ NULL,
3053+ (GAsyncReadyCallback) upower_ready_cb,
3054+ manager);
3055+}
3056+
3057+GsdMediaKeysManager *
3058+gsd_media_keys_manager_new (void)
3059+{
3060+ if (manager_object != NULL) {
3061+ g_object_ref (manager_object);
3062+ } else {
3063+ manager_object = g_object_new (GSD_TYPE_MEDIA_KEYS_MANAGER, NULL);
3064+ g_object_add_weak_pointer (manager_object,
3065+ (gpointer *) &manager_object);
3066+ }
3067+
3068+ return GSD_MEDIA_KEYS_MANAGER (manager_object);
3069+}
3070
3071=== added file '.pc/64_micmute.patch/plugins/media-keys/shortcuts-list.h'
3072--- .pc/64_micmute.patch/plugins/media-keys/shortcuts-list.h 1970-01-01 00:00:00 +0000
3073+++ .pc/64_micmute.patch/plugins/media-keys/shortcuts-list.h 2013-10-01 15:38:46 +0000
3074@@ -0,0 +1,152 @@
3075+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3076+ *
3077+ * Copyright (C) 2001 Bastien Nocera <hadess@hadess.net>
3078+ *
3079+ * This program is free software; you can redistribute it and/or modify
3080+ * it under the terms of the GNU General Public License as published by
3081+ * the Free Software Foundation; either version 2 of the License, or
3082+ * (at your option) any later version.
3083+ *
3084+ * This program is distributed in the hope that it will be useful,
3085+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3086+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3087+ * GNU General Public License for more details.
3088+ *
3089+ * You should have received a copy of the GNU General Public License
3090+ * along with this program; if not, write to the Free Software
3091+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
3092+ * USA.
3093+ */
3094+
3095+#ifndef __ACME_H__
3096+#define __ACME_H__
3097+
3098+#include "gsd-keygrab.h"
3099+
3100+#define SETTINGS_BINDING_DIR "org.gnome.settings-daemon.plugins.media-keys"
3101+
3102+typedef enum {
3103+ TOUCHPAD_KEY,
3104+ TOUCHPAD_ON_KEY,
3105+ TOUCHPAD_OFF_KEY,
3106+ MUTE_KEY,
3107+ VOLUME_DOWN_KEY,
3108+ VOLUME_UP_KEY,
3109+ MUTE_QUIET_KEY,
3110+ VOLUME_DOWN_QUIET_KEY,
3111+ VOLUME_UP_QUIET_KEY,
3112+ LOGOUT_KEY,
3113+ EJECT_KEY,
3114+ HOME_KEY,
3115+ MEDIA_KEY,
3116+ CALCULATOR_KEY,
3117+ SEARCH_KEY,
3118+ EMAIL_KEY,
3119+ SCREENSAVER_KEY,
3120+ HELP_KEY,
3121+ SCREENSHOT_KEY,
3122+ WINDOW_SCREENSHOT_KEY,
3123+ AREA_SCREENSHOT_KEY,
3124+ SCREENSHOT_CLIP_KEY,
3125+ WINDOW_SCREENSHOT_CLIP_KEY,
3126+ AREA_SCREENSHOT_CLIP_KEY,
3127+ WWW_KEY,
3128+ PLAY_KEY,
3129+ PAUSE_KEY,
3130+ STOP_KEY,
3131+ PREVIOUS_KEY,
3132+ NEXT_KEY,
3133+ REWIND_KEY,
3134+ FORWARD_KEY,
3135+ REPEAT_KEY,
3136+ RANDOM_KEY,
3137+ VIDEO_OUT_KEY,
3138+ ROTATE_VIDEO_KEY,
3139+ MAGNIFIER_KEY,
3140+ SCREENREADER_KEY,
3141+ ON_SCREEN_KEYBOARD_KEY,
3142+ INCREASE_TEXT_KEY,
3143+ DECREASE_TEXT_KEY,
3144+ TOGGLE_CONTRAST_KEY,
3145+ MAGNIFIER_ZOOM_IN_KEY,
3146+ MAGNIFIER_ZOOM_OUT_KEY,
3147+ POWER_KEY,
3148+ SLEEP_KEY,
3149+ SUSPEND_KEY,
3150+ HIBERNATE_KEY,
3151+ SCREEN_BRIGHTNESS_UP_KEY,
3152+ SCREEN_BRIGHTNESS_DOWN_KEY,
3153+ KEYBOARD_BRIGHTNESS_UP_KEY,
3154+ KEYBOARD_BRIGHTNESS_DOWN_KEY,
3155+ KEYBOARD_BRIGHTNESS_TOGGLE_KEY,
3156+ BATTERY_KEY,
3157+ CUSTOM_KEY
3158+} MediaKeyType;
3159+
3160+static struct {
3161+ MediaKeyType key_type;
3162+ const char *settings_key;
3163+ const char *hard_coded;
3164+} media_keys[] = {
3165+ { TOUCHPAD_KEY, NULL, "XF86TouchpadToggle" },
3166+ { TOUCHPAD_ON_KEY, NULL, "XF86TouchpadOn" },
3167+ { TOUCHPAD_OFF_KEY, NULL, "XF86TouchpadOff" },
3168+ { MUTE_KEY, "volume-mute", NULL },
3169+ { VOLUME_DOWN_KEY, "volume-down", NULL },
3170+ { VOLUME_UP_KEY, "volume-up", NULL },
3171+ { MUTE_QUIET_KEY, NULL, "<Alt>XF86AudioMute" },
3172+ { VOLUME_DOWN_QUIET_KEY, NULL, "<Alt>XF86AudioLowerVolume" },
3173+ { VOLUME_UP_QUIET_KEY, NULL, "<Alt>XF86AudioRaiseVolume" },
3174+ { LOGOUT_KEY, "logout", NULL },
3175+ { EJECT_KEY, "eject", NULL },
3176+ { HOME_KEY, "home", NULL },
3177+ { MEDIA_KEY, "media", NULL },
3178+ { CALCULATOR_KEY, "calculator", NULL },
3179+ { SEARCH_KEY, "search", NULL },
3180+ { EMAIL_KEY, "email", NULL },
3181+ { SCREENSAVER_KEY, "screensaver", NULL },
3182+ { SCREENSAVER_KEY, NULL, "XF86ScreenSaver" },
3183+ { HELP_KEY, "help", NULL },
3184+ { SCREENSHOT_KEY, "screenshot", NULL },
3185+ { WINDOW_SCREENSHOT_KEY, "window-screenshot", NULL },
3186+ { AREA_SCREENSHOT_KEY, "area-screenshot", NULL },
3187+ { SCREENSHOT_CLIP_KEY, "screenshot-clip", NULL },
3188+ { WINDOW_SCREENSHOT_CLIP_KEY, "window-screenshot-clip", NULL },
3189+ { AREA_SCREENSHOT_CLIP_KEY, "area-screenshot-clip", NULL },
3190+ { WWW_KEY, "www", NULL },
3191+ { PLAY_KEY, "play", NULL },
3192+ { PAUSE_KEY, "pause", NULL },
3193+ { STOP_KEY, "stop", NULL },
3194+ { PREVIOUS_KEY, "previous", NULL },
3195+ { NEXT_KEY, "next", NULL },
3196+ { REWIND_KEY, NULL, "XF86AudioRewind" },
3197+ { FORWARD_KEY, NULL, "XF86AudioForward" },
3198+ { REPEAT_KEY, NULL, "XF86AudioRepeat" },
3199+ { RANDOM_KEY, NULL, "XF86AudioRandomPlay"},
3200+ { VIDEO_OUT_KEY, NULL, "<Super>p" },
3201+ /* Key code of the XF86Display key (Fn-F7 on Thinkpads, Fn-F4 on HP machines, etc.) */
3202+ { VIDEO_OUT_KEY, NULL, "XF86Display" },
3203+ /* Key code of the XF86RotateWindows key (present on some tablets) */
3204+ { ROTATE_VIDEO_KEY, NULL, "XF86RotateWindows" },
3205+ { MAGNIFIER_KEY, "magnifier", NULL },
3206+ { SCREENREADER_KEY, "screenreader", NULL },
3207+ { ON_SCREEN_KEYBOARD_KEY, "on-screen-keyboard", NULL },
3208+ { INCREASE_TEXT_KEY, "increase-text-size", NULL },
3209+ { DECREASE_TEXT_KEY, "decrease-text-size", NULL },
3210+ { TOGGLE_CONTRAST_KEY, "toggle-contrast", NULL },
3211+ { MAGNIFIER_ZOOM_IN_KEY, "magnifier-zoom-in", NULL },
3212+ { MAGNIFIER_ZOOM_OUT_KEY, "magnifier-zoom-out", NULL },
3213+ { POWER_KEY, NULL, "XF86PowerOff" },
3214+ /* the kernel / Xorg names really are like this... */
3215+ { SLEEP_KEY, NULL, "XF86Suspend" },
3216+ { SUSPEND_KEY, NULL, "XF86Sleep" },
3217+ { HIBERNATE_KEY, NULL, "XF86Hibernate" },
3218+ { SCREEN_BRIGHTNESS_UP_KEY, NULL, "XF86MonBrightnessUp" },
3219+ { SCREEN_BRIGHTNESS_DOWN_KEY, NULL, "XF86MonBrightnessDown" },
3220+ { KEYBOARD_BRIGHTNESS_UP_KEY, NULL, "XF86KbdBrightnessUp" },
3221+ { KEYBOARD_BRIGHTNESS_DOWN_KEY, NULL, "XF86KbdBrightnessDown" },
3222+ { KEYBOARD_BRIGHTNESS_TOGGLE_KEY, NULL, "XF86KbdLightOnOff" },
3223+ { BATTERY_KEY, NULL, "XF86Battery" },
3224+};
3225+
3226+#endif /* __ACME_H__ */
3227
3228=== modified file '.pc/applied-patches'
3229--- .pc/applied-patches 2012-04-16 15:55:26 +0000
3230+++ .pc/applied-patches 2013-10-01 15:38:46 +0000
3231@@ -23,5 +23,14 @@
3232 revert_git_a11y_gsettings.patch
3233 bugzilla_segfault_dpms.patch
3234 correct_logout_action.patch
3235-git_keyring_environment.patch
3236 power-no-fallback-notifications.patch
3237+power-check-null-devices.patch
3238+power-ignore-bad-dbus-requests.patch
3239+xsettings_signal_handling.patch
3240+git_xrandr_explicitly_set_clone_state.patch
3241+git-mask-out-virtual-modifiers.patch
3242+dont_overwrite_gconf_keys.patch
3243+git_no_numlock_eating_cpu_loop.patch
3244+git_new_xinput_handle.patch
3245+git-smartcard-crash.patch
3246+64_micmute.patch
3247
3248=== modified file '.pc/correct_logout_action.patch/plugins/media-keys/gsd-media-keys-manager.c'
3249--- .pc/correct_logout_action.patch/plugins/media-keys/gsd-media-keys-manager.c 2012-04-03 17:28:40 +0000
3250+++ .pc/correct_logout_action.patch/plugins/media-keys/gsd-media-keys-manager.c 2013-10-01 15:38:46 +0000
3251@@ -69,6 +69,10 @@
3252 #define GNOME_SESSION_DBUS_PATH "/org/gnome/SessionManager"
3253 #define GNOME_SESSION_DBUS_INTERFACE "org.gnome.SessionManager"
3254
3255+#define GNOME_KEYRING_DBUS_NAME "org.gnome.keyring"
3256+#define GNOME_KEYRING_DBUS_PATH "/org/gnome/keyring/daemon"
3257+#define GNOME_KEYRING_DBUS_INTERFACE "org.gnome.keyring.Daemon"
3258+
3259 #define GCONF_BINDING_DIR "/desktop/gnome/keybindings"
3260
3261 static const gchar introspection_xml[] =
3262@@ -360,6 +364,57 @@
3263 return cmd;
3264 }
3265
3266+static char **
3267+get_keyring_env (GsdMediaKeysManager *manager)
3268+{
3269+ GError *error = NULL;
3270+ GVariant *variant, *item;
3271+ GVariantIter *iter;
3272+ char **envp;
3273+
3274+ variant = g_dbus_connection_call_sync (manager->priv->connection,
3275+ GNOME_KEYRING_DBUS_NAME,
3276+ GNOME_KEYRING_DBUS_PATH,
3277+ GNOME_KEYRING_DBUS_INTERFACE,
3278+ "GetEnvironment",
3279+ NULL,
3280+ NULL,
3281+ G_DBUS_CALL_FLAGS_NONE,
3282+ -1,
3283+ NULL,
3284+ &error);
3285+ if (variant == NULL) {
3286+ g_warning ("Failed to call GetEnvironment on keyring daemon: %s", error->message);
3287+ g_error_free (error);
3288+ return NULL;
3289+ }
3290+
3291+ envp = g_get_environ ();
3292+
3293+ g_variant_get (variant, "(a{ss})", &iter);
3294+
3295+ while ((item = g_variant_iter_next_value (iter))) {
3296+ char *key;
3297+ char *value;
3298+
3299+ g_variant_get (item,
3300+ "{ss}",
3301+ &key,
3302+ &value);
3303+
3304+ envp = g_environ_setenv (envp, key, value, TRUE);
3305+
3306+ g_variant_unref (item);
3307+ g_free (key);
3308+ g_free (value);
3309+ }
3310+
3311+ g_variant_iter_free (iter);
3312+ g_variant_unref (variant);
3313+
3314+ return envp;
3315+}
3316+
3317 static void
3318 execute (GsdMediaKeysManager *manager,
3319 char *cmd,
3320@@ -385,15 +440,21 @@
3321 }
3322
3323 if (g_shell_parse_argv (exec, &argc, &argv, NULL)) {
3324+ char **envp;
3325+
3326+ envp = get_keyring_env (manager);
3327+
3328 retval = g_spawn_async (g_get_home_dir (),
3329 argv,
3330- NULL,
3331+ envp,
3332 G_SPAWN_SEARCH_PATH,
3333 NULL,
3334 NULL,
3335 NULL,
3336 &error);
3337+
3338 g_strfreev (argv);
3339+ g_strfreev (envp);
3340 }
3341
3342 if (retval == FALSE) {
3343
3344=== modified file '.pc/disable_three_touch_tap.patch/plugins/mouse/gsd-mouse-manager.c'
3345--- .pc/disable_three_touch_tap.patch/plugins/mouse/gsd-mouse-manager.c 2012-04-16 15:55:26 +0000
3346+++ .pc/disable_three_touch_tap.patch/plugins/mouse/gsd-mouse-manager.c 2013-10-01 15:38:46 +0000
3347@@ -317,8 +317,6 @@
3348 gint n_buttons;
3349 const char *name;
3350
3351- buttons = g_new (guchar, buttons_capacity);
3352-
3353 name = gdk_device_get_name (device);
3354 if (name != NULL && g_str_equal ("Virtual core XTEST pointer", name))
3355 return;
3356@@ -329,6 +327,8 @@
3357 if (xdevice == NULL)
3358 return;
3359
3360+ buttons = g_new (guchar, buttons_capacity);
3361+
3362 /* If the device is a touchpad, swap tap buttons
3363 * around too, otherwise a tap would be a right-click */
3364 if (device_is_touchpad (xdevice)) {
3365@@ -515,6 +515,18 @@
3366 #endif
3367 }
3368
3369+static gboolean
3370+have_program_in_path (const char *name)
3371+{
3372+ gchar *path;
3373+ gboolean result;
3374+
3375+ path = g_find_program_in_path (name);
3376+ result = (path != NULL);
3377+ g_free (path);
3378+ return result;
3379+}
3380+
3381 static void
3382 syndaemon_died (GPid pid, gint status, gpointer user_data)
3383 {
3384@@ -530,7 +542,7 @@
3385 {
3386 if (state && touchpad_is_present ()) {
3387 GError *error = NULL;
3388- char *args[6];
3389+ char *args[7];
3390
3391 if (manager->priv->syndaemon_spawned)
3392 return 0;
3393@@ -543,7 +555,7 @@
3394 args[5] = "-t";
3395 args[6] = NULL;
3396
3397- if (!g_find_program_in_path (args[0]))
3398+ if (!have_program_in_path (args[0]))
3399 return 0;
3400
3401 /* we must use G_SPAWN_DO_NOT_REAP_CHILD to avoid
3402
3403=== added directory '.pc/dont_overwrite_gconf_keys.patch'
3404=== added directory '.pc/dont_overwrite_gconf_keys.patch/plugins'
3405=== added directory '.pc/dont_overwrite_gconf_keys.patch/plugins/gconf'
3406=== added file '.pc/dont_overwrite_gconf_keys.patch/plugins/gconf/conf-watcher.c'
3407--- .pc/dont_overwrite_gconf_keys.patch/plugins/gconf/conf-watcher.c 1970-01-01 00:00:00 +0000
3408+++ .pc/dont_overwrite_gconf_keys.patch/plugins/gconf/conf-watcher.c 2013-10-01 15:38:46 +0000
3409@@ -0,0 +1,150 @@
3410+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3411+ *
3412+ * Copyright (C) 2010 Rodrigo Moya <rodrigo@gnome.org>
3413+ *
3414+ * This program is free software; you can redistribute it and/or modify
3415+ * it under the terms of the GNU General Public License as published by
3416+ * the Free Software Foundation; either version 2 of the License, or
3417+ * (at your option) any later version.
3418+ *
3419+ * This program is distributed in the hope that it will be useful,
3420+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3421+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3422+ * GNU General Public License for more details.
3423+ *
3424+ * You should have received a copy of the GNU General Public License
3425+ * along with this program; if not, write to the Free Software
3426+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3427+ *
3428+ */
3429+
3430+#include "config.h"
3431+#include "conf-watcher.h"
3432+
3433+G_DEFINE_TYPE(ConfWatcher, conf_watcher, G_TYPE_OBJECT)
3434+
3435+static void settings_changed_cb (GSettings *settings,
3436+ const gchar *key,
3437+ ConfWatcher *watcher);
3438+
3439+static void
3440+conf_watcher_finalize (GObject *object)
3441+{
3442+ ConfWatcher *watcher = CONF_WATCHER (object);
3443+
3444+ if (watcher->settings != NULL) {
3445+ g_signal_handlers_disconnect_by_func (watcher->settings, settings_changed_cb, watcher);
3446+ g_object_unref (watcher->settings);
3447+ }
3448+
3449+ if (watcher->conf_client != NULL)
3450+ g_object_unref (watcher->conf_client);
3451+
3452+ if (watcher->settings_id != NULL)
3453+ g_free (watcher->settings_id);
3454+
3455+ if (watcher->keys_hash != NULL)
3456+ g_hash_table_destroy (watcher->keys_hash);
3457+
3458+ G_OBJECT_CLASS (conf_watcher_parent_class)->finalize (object);
3459+}
3460+
3461+static void
3462+conf_watcher_class_init (ConfWatcherClass *klass)
3463+{
3464+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
3465+
3466+ object_class->finalize = conf_watcher_finalize;
3467+}
3468+
3469+static void
3470+conf_watcher_init (ConfWatcher *watcher)
3471+{
3472+}
3473+
3474+static void
3475+settings_changed_cb (GSettings *settings,
3476+ const gchar *key,
3477+ ConfWatcher *watcher)
3478+{
3479+ const gchar *gconf_key_name;
3480+
3481+ gconf_key_name = g_hash_table_lookup (watcher->keys_hash, key);
3482+ if (gconf_key_name != NULL) {
3483+ GVariant *value;
3484+
3485+ value = g_settings_get_value (settings, key);
3486+ if (g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)) {
3487+ gconf_client_set_bool (watcher->conf_client,
3488+ gconf_key_name,
3489+ g_variant_get_boolean (value),
3490+ NULL);
3491+ } else if (g_variant_is_of_type (value, G_VARIANT_TYPE_BYTE) ||
3492+ g_variant_is_of_type (value, G_VARIANT_TYPE_INT16) ||
3493+ g_variant_is_of_type (value, G_VARIANT_TYPE_UINT16) ||
3494+ g_variant_is_of_type (value, G_VARIANT_TYPE_INT32) ||
3495+ g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32) ||
3496+ g_variant_is_of_type (value, G_VARIANT_TYPE_INT64) ||
3497+ g_variant_is_of_type (value, G_VARIANT_TYPE_UINT64)) {
3498+ gconf_client_set_int (watcher->conf_client,
3499+ gconf_key_name,
3500+ g_settings_get_int (settings, key),
3501+ NULL);
3502+ } else if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) {
3503+ gconf_client_set_string (watcher->conf_client,
3504+ gconf_key_name,
3505+ g_variant_get_string (value, NULL),
3506+ NULL);
3507+ } else if (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE)) {
3508+ gconf_client_set_float (watcher->conf_client,
3509+ gconf_key_name,
3510+ g_variant_get_double (value),
3511+ NULL);
3512+ } else if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING_ARRAY)) {
3513+ const gchar **items;
3514+ gsize len, i;
3515+ GSList *gconf_list = NULL;
3516+
3517+ items = g_variant_get_strv (value, &len);
3518+ for (i = 0; i < len; i++) {
3519+ gconf_list = g_slist_append (gconf_list, (gpointer) items[i]);
3520+ }
3521+
3522+ gconf_client_set_list (watcher->conf_client,
3523+ gconf_key_name,
3524+ GCONF_VALUE_STRING,
3525+ gconf_list,
3526+ NULL);
3527+
3528+ g_slist_free (gconf_list);
3529+ g_free (items);
3530+ }
3531+ }
3532+}
3533+
3534+static void
3535+setup_watcher (ConfWatcher *watcher)
3536+{
3537+ watcher->settings = g_settings_new (watcher->settings_id);
3538+ g_signal_connect (watcher->settings, "changed",
3539+ G_CALLBACK (settings_changed_cb), watcher);
3540+
3541+ watcher->conf_client = gconf_client_get_default ();
3542+}
3543+
3544+ConfWatcher *
3545+conf_watcher_new (const gchar *settings_id, GHashTable *keys_hash)
3546+{
3547+ ConfWatcher *watcher;
3548+
3549+ g_return_val_if_fail (settings_id != NULL, NULL);
3550+ g_return_val_if_fail (keys_hash != NULL, NULL);
3551+
3552+ watcher = g_object_new (TYPE_CONF_WATCHER, NULL);
3553+
3554+ watcher->settings_id = g_strdup (settings_id);
3555+ watcher->keys_hash = keys_hash;
3556+ setup_watcher (watcher);
3557+
3558+ return watcher;
3559+}
3560
3561=== added directory '.pc/git-mask-out-virtual-modifiers.patch'
3562=== added directory '.pc/git-mask-out-virtual-modifiers.patch/plugins'
3563=== added directory '.pc/git-mask-out-virtual-modifiers.patch/plugins/common'
3564=== added file '.pc/git-mask-out-virtual-modifiers.patch/plugins/common/gsd-keygrab.c'
3565--- .pc/git-mask-out-virtual-modifiers.patch/plugins/common/gsd-keygrab.c 1970-01-01 00:00:00 +0000
3566+++ .pc/git-mask-out-virtual-modifiers.patch/plugins/common/gsd-keygrab.c 2013-10-01 15:38:46 +0000
3567@@ -0,0 +1,433 @@
3568+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3569+ *
3570+ * Copyright (C) 2001-2003 Bastien Nocera <hadess@hadess.net>
3571+ * Copyright (C) 2006-2007 William Jon McCann <mccann@jhu.edu>
3572+ * Copyright (C) 2008 Jens Granseuer <jensgr@gmx.net>
3573+ *
3574+ * This program is free software; you can redistribute it and/or modify
3575+ * it under the terms of the GNU General Public License as published by
3576+ * the Free Software Foundation; either version 2 of the License, or
3577+ * (at your option) any later version.
3578+ *
3579+ * This program is distributed in the hope that it will be useful,
3580+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3581+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3582+ * GNU General Public License for more details.
3583+ *
3584+ * You should have received a copy of the GNU General Public License
3585+ * along with this program; if not, write to the Free Software
3586+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3587+ *
3588+ */
3589+
3590+#include "config.h"
3591+
3592+#include <string.h>
3593+#include <gdk/gdk.h>
3594+#include <gdk/gdkx.h>
3595+#include <gtk/gtk.h>
3596+#include <X11/XKBlib.h>
3597+#include <X11/extensions/XInput2.h>
3598+#include <X11/extensions/XKB.h>
3599+#include <gdk/gdkkeysyms.h>
3600+
3601+#include "gsd-keygrab.h"
3602+
3603+/* these are the mods whose combinations are ignored by the keygrabbing code */
3604+static GdkModifierType gsd_ignored_mods = 0;
3605+
3606+/* these are the ones we actually use for global keys, we always only check
3607+ * for these set */
3608+static GdkModifierType gsd_used_mods = 0;
3609+
3610+/* Taken from a comment in XF86keysym.h */
3611+#define XF86KEYS_RANGE_MIN 0x10080001
3612+#define XF86KEYS_RANGE_MAX 0x1008FFFF
3613+
3614+#define FKEYS_RANGE_MIN GDK_KEY_F1
3615+#define FKEYS_RANGE_MAX GDK_KEY_F35
3616+
3617+#define IN_RANGE(x, min, max) (x >= min && x <= max)
3618+
3619+static void
3620+setup_modifiers (void)
3621+{
3622+ if (gsd_used_mods == 0 || gsd_ignored_mods == 0) {
3623+ GdkModifierType dynmods;
3624+
3625+ /* default modifiers */
3626+ gsd_ignored_mods = \
3627+ 0x2000 /*Xkb modifier*/ | GDK_LOCK_MASK | GDK_HYPER_MASK;
3628+ gsd_used_mods = \
3629+ GDK_SHIFT_MASK | GDK_CONTROL_MASK |\
3630+ GDK_MOD1_MASK | GDK_MOD2_MASK | GDK_MOD3_MASK | GDK_MOD4_MASK |\
3631+ GDK_MOD5_MASK | GDK_SUPER_MASK | GDK_META_MASK;
3632+
3633+ /* NumLock can be assigned to varying keys so we need to
3634+ * resolve and ignore it specially */
3635+ dynmods = XkbKeysymToModifiers (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), GDK_KEY_Num_Lock);
3636+
3637+ gsd_ignored_mods |= dynmods;
3638+ gsd_used_mods &= ~dynmods;
3639+ }
3640+}
3641+
3642+static void
3643+grab_key_real (guint keycode,
3644+ GdkWindow *root,
3645+ gboolean grab,
3646+ XIGrabModifiers *mods,
3647+ int num_mods)
3648+{
3649+ XIEventMask evmask;
3650+ unsigned char mask[(XI_LASTEVENT + 7)/8];
3651+
3652+ memset (mask, 0, sizeof (mask));
3653+ XISetMask (mask, XI_KeyPress);
3654+ XISetMask (mask, XI_KeyRelease);
3655+
3656+ evmask.deviceid = XIAllMasterDevices;
3657+ evmask.mask_len = sizeof (mask);
3658+ evmask.mask = mask;
3659+
3660+ if (grab) {
3661+ XIGrabKeycode (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
3662+ XIAllMasterDevices,
3663+ keycode,
3664+ GDK_WINDOW_XID (root),
3665+ GrabModeAsync,
3666+ GrabModeAsync,
3667+ False,
3668+ &evmask,
3669+ num_mods,
3670+ mods);
3671+ } else {
3672+ XIUngrabKeycode (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
3673+ XIAllMasterDevices,
3674+ keycode,
3675+ GDK_WINDOW_XID (root),
3676+ num_mods,
3677+ mods);
3678+ }
3679+}
3680+
3681+/* Grab the key. In order to ignore GSD_IGNORED_MODS we need to grab
3682+ * all combinations of the ignored modifiers and those actually used
3683+ * for the binding (if any).
3684+ *
3685+ * inspired by all_combinations from gnome-panel/gnome-panel/global-keys.c
3686+ *
3687+ * This may generate X errors. The correct way to use this is like:
3688+ *
3689+ * gdk_error_trap_push ();
3690+ *
3691+ * grab_key_unsafe (key, grab, screens);
3692+ *
3693+ * gdk_flush ();
3694+ * if (gdk_error_trap_pop ())
3695+ * g_warning ("Grab failed, another application may already have access to key '%u'",
3696+ * key->keycode);
3697+ *
3698+ * This is not done in the function itself, to allow doing multiple grab_key
3699+ * operations with one flush only.
3700+ */
3701+#define N_BITS 32
3702+void
3703+grab_key_unsafe (Key *key,
3704+ gboolean grab,
3705+ GSList *screens)
3706+{
3707+ int indexes[N_BITS]; /* indexes of bits we need to flip */
3708+ int i;
3709+ int bit;
3710+ int bits_set_cnt;
3711+ int uppervalue;
3712+ guint mask, modifiers;
3713+ GArray *all_mods;
3714+ GSList *l;
3715+
3716+ setup_modifiers ();
3717+
3718+ mask = gsd_ignored_mods & ~key->state & GDK_MODIFIER_MASK;
3719+
3720+ /* XGrabKey requires real modifiers, not virtual ones */
3721+ modifiers = key->state;
3722+ gdk_keymap_map_virtual_modifiers (gdk_keymap_get_default (), &modifiers);
3723+
3724+ /* If key doesn't have a usable modifier, we don't want
3725+ * to grab it, since the user might lose a useful key.
3726+ *
3727+ * The exception is the XFree86 keys and the Function keys
3728+ * (which are useful to grab without a modifier).
3729+ */
3730+ if ((modifiers & gsd_used_mods) == 0 &&
3731+ !IN_RANGE(key->keysym, XF86KEYS_RANGE_MIN, XF86KEYS_RANGE_MAX) &&
3732+ !IN_RANGE(key->keysym, FKEYS_RANGE_MIN, FKEYS_RANGE_MAX) &&
3733+ key->keysym != GDK_KEY_Pause &&
3734+ key->keysym != GDK_KEY_Print) {
3735+ GString *keycodes;
3736+
3737+ keycodes = g_string_new ("");
3738+ if (key->keycodes != NULL) {
3739+ guint *c;
3740+
3741+ for (c = key->keycodes; *c; ++c) {
3742+ g_string_printf (keycodes, " %u", *c);
3743+ }
3744+ }
3745+ g_warning ("Key 0x%x (keycodes: %s) with state 0x%x (resolved to 0x%x) "
3746+ " has no usable modifiers (usable modifiers are 0x%x)",
3747+ key->keysym, keycodes->str, key->state, modifiers, gsd_used_mods);
3748+ g_string_free (keycodes, TRUE);
3749+
3750+ return;
3751+ }
3752+
3753+ bit = 0;
3754+ /* store the indexes of all set bits in mask in the array */
3755+ for (i = 0; mask; ++i, mask >>= 1) {
3756+ if (mask & 0x1) {
3757+ indexes[bit++] = i;
3758+ }
3759+ }
3760+
3761+ bits_set_cnt = bit;
3762+
3763+ all_mods = g_array_new (FALSE, TRUE, sizeof(XIGrabModifiers));
3764+ uppervalue = 1 << bits_set_cnt;
3765+ /* store all possible modifier combinations for our mask into all_mods */
3766+ for (i = 0; i < uppervalue; ++i) {
3767+ int j;
3768+ int result = 0;
3769+ XIGrabModifiers *mod;
3770+
3771+ /* map bits in the counter to those in the mask */
3772+ for (j = 0; j < bits_set_cnt; ++j) {
3773+ if (i & (1 << j)) {
3774+ result |= (1 << indexes[j]);
3775+ }
3776+ }
3777+
3778+ /* Grow the array by one, to fit our new XIGrabModifiers item */
3779+ g_array_set_size (all_mods, all_mods->len + 1);
3780+ mod = &g_array_index (all_mods, XIGrabModifiers, all_mods->len - 1);
3781+ mod->modifiers = result | modifiers;
3782+ }
3783+
3784+ /* Capture the actual keycodes with the modifier array */
3785+ for (l = screens; l; l = l->next) {
3786+ GdkScreen *screen = l->data;
3787+ guint *code;
3788+
3789+ for (code = key->keycodes; *code; ++code) {
3790+ grab_key_real (*code,
3791+ gdk_screen_get_root_window (screen),
3792+ grab,
3793+ (XIGrabModifiers *) all_mods->data,
3794+ all_mods->len);
3795+ }
3796+ }
3797+ g_array_free (all_mods, TRUE);
3798+}
3799+
3800+static gboolean
3801+have_xkb (Display *dpy)
3802+{
3803+ static int have_xkb = -1;
3804+
3805+ if (have_xkb == -1) {
3806+ int opcode, error_base, major, minor, xkb_event_base;
3807+
3808+ have_xkb = XkbQueryExtension (dpy,
3809+ &opcode,
3810+ &xkb_event_base,
3811+ &error_base,
3812+ &major,
3813+ &minor)
3814+ && XkbUseExtension (dpy, &major, &minor);
3815+ }
3816+
3817+ return have_xkb;
3818+}
3819+
3820+gboolean
3821+key_uses_keycode (const Key *key, guint keycode)
3822+{
3823+ if (key->keycodes != NULL) {
3824+ guint *c;
3825+
3826+ for (c = key->keycodes; *c; ++c) {
3827+ if (*c == keycode)
3828+ return TRUE;
3829+ }
3830+ }
3831+ return FALSE;
3832+}
3833+
3834+/* Adapted from _gdk_x11_device_xi2_translate_state()
3835+ * in gtk+/gdk/x11/gdkdevice-xi2.c */
3836+static guint
3837+device_xi2_translate_state (XIModifierState *mods_state,
3838+ XIGroupState *group_state)
3839+{
3840+ guint state;
3841+ gint group;
3842+
3843+ state = (guint) mods_state->base | mods_state->latched | mods_state->locked;
3844+
3845+ group = group_state->base | group_state->latched | group_state->locked;
3846+ /* FIXME: do we need the XKB complications for this ? */
3847+ group = CLAMP(group, 0, 3);
3848+ state |= group << 13;
3849+
3850+ return state;
3851+}
3852+
3853+gboolean
3854+match_xi2_key (Key *key, XIDeviceEvent *event)
3855+{
3856+ guint keyval;
3857+ GdkModifierType consumed;
3858+ gint group;
3859+ guint keycode, state;
3860+
3861+ if (key == NULL)
3862+ return FALSE;
3863+
3864+ setup_modifiers ();
3865+
3866+ state = device_xi2_translate_state (&event->mods, &event->group);
3867+
3868+ if (have_xkb (event->display))
3869+ group = XkbGroupForCoreState (state);
3870+ else
3871+ group = (state & GDK_KEY_Mode_switch) ? 1 : 0;
3872+
3873+ keycode = event->detail;
3874+
3875+ /* Check if we find a keysym that matches our current state */
3876+ if (gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (), keycode,
3877+ state, group,
3878+ &keyval, NULL, NULL, &consumed)) {
3879+ guint lower, upper;
3880+ guint mask;
3881+
3882+ /* HACK: we don't want to use SysRq as a keybinding, so we avoid
3883+ * its translation from Alt+Print. */
3884+ if (keyval == GDK_KEY_Sys_Req &&
3885+ (state & GDK_MOD1_MASK) != 0) {
3886+ consumed = 0;
3887+ keyval = GDK_KEY_Print;
3888+ }
3889+
3890+ /* The Key structure contains virtual modifiers, whereas
3891+ * the XEvent will be using the real modifier, so translate those */
3892+ mask = key->state;
3893+ gdk_keymap_map_virtual_modifiers (gdk_keymap_get_default (), &mask);
3894+
3895+ gdk_keyval_convert_case (keyval, &lower, &upper);
3896+
3897+ /* If we are checking against the lower version of the
3898+ * keysym, we might need the Shift state for matching,
3899+ * so remove it from the consumed modifiers */
3900+ if (lower == key->keysym)
3901+ consumed &= ~GDK_SHIFT_MASK;
3902+
3903+ return ((lower == key->keysym || upper == key->keysym)
3904+ && (state & ~consumed & gsd_used_mods) == mask);
3905+ }
3906+
3907+ /* The key we passed doesn't have a keysym, so try with just the keycode */
3908+ return (key != NULL
3909+ && key->state == (state & gsd_used_mods)
3910+ && key_uses_keycode (key, keycode));
3911+}
3912+
3913+Key *
3914+parse_key (const char *str)
3915+{
3916+ Key *key;
3917+
3918+ if (str == NULL ||
3919+ *str == '\0' ||
3920+ g_str_equal (str, "disabled")) {
3921+ return NULL;
3922+ }
3923+
3924+ key = g_new0 (Key, 1);
3925+ gtk_accelerator_parse_with_keycode (str, &key->keysym, &key->keycodes, &key->state);
3926+ if (key->keysym == 0 &&
3927+ key->keycodes == NULL &&
3928+ key->state == 0) {
3929+ g_free (key);
3930+ return NULL;
3931+ }
3932+
3933+ return key;
3934+}
3935+
3936+void
3937+free_key (Key *key)
3938+{
3939+ if (key == NULL)
3940+ return;
3941+ g_free (key->keycodes);
3942+ g_free (key);
3943+}
3944+
3945+static void
3946+grab_button_real (int deviceid,
3947+ gboolean grab,
3948+ GdkWindow *root)
3949+{
3950+ XIGrabModifiers mods;
3951+
3952+ mods.modifiers = XIAnyModifier;
3953+
3954+ if (grab) {
3955+ XIEventMask evmask;
3956+ unsigned char mask[(XI_LASTEVENT + 7)/8];
3957+
3958+ memset (mask, 0, sizeof (mask));
3959+ XISetMask (mask, XI_ButtonRelease);
3960+ XISetMask (mask, XI_ButtonPress);
3961+
3962+ evmask.deviceid = deviceid;
3963+ evmask.mask_len = sizeof (mask);
3964+ evmask.mask = mask;
3965+
3966+ XIGrabButton (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
3967+ deviceid,
3968+ XIAnyButton,
3969+ GDK_WINDOW_XID (root),
3970+ None,
3971+ GrabModeAsync,
3972+ GrabModeAsync,
3973+ False,
3974+ &evmask,
3975+ 1,
3976+ &mods);
3977+ } else {
3978+ XIUngrabButton (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
3979+ deviceid,
3980+ XIAnyButton,
3981+ GDK_WINDOW_XID (root),
3982+ 1, &mods);
3983+ }
3984+}
3985+
3986+void
3987+grab_button (int deviceid,
3988+ gboolean grab,
3989+ GSList *screens)
3990+{
3991+ GSList *l;
3992+
3993+ for (l = screens; l; l = l->next) {
3994+ GdkScreen *screen = l->data;
3995+
3996+ grab_button_real (deviceid,
3997+ grab,
3998+ gdk_screen_get_root_window (screen));
3999+ }
4000+}
4001
4002=== added directory '.pc/git-smartcard-crash.patch'
4003=== added directory '.pc/git-smartcard-crash.patch/plugins'
4004=== added directory '.pc/git-smartcard-crash.patch/plugins/smartcard'
4005=== added file '.pc/git-smartcard-crash.patch/plugins/smartcard/gsd-smartcard-manager.c'
4006--- .pc/git-smartcard-crash.patch/plugins/smartcard/gsd-smartcard-manager.c 1970-01-01 00:00:00 +0000
4007+++ .pc/git-smartcard-crash.patch/plugins/smartcard/gsd-smartcard-manager.c 2013-10-01 15:38:46 +0000
4008@@ -0,0 +1,1515 @@
4009+/* gsd-smartcard-manager.c - object for monitoring smartcard insertion and
4010+ * removal events
4011+ *
4012+ * Copyright (C) 2006, 2009 Red Hat, Inc.
4013+ *
4014+ * This program is free software; you can redistribute it and/or modify
4015+ * it under the terms of the GNU General Public License as published by
4016+ * the Free Software Foundation; either version 2, or (at your option)
4017+ * any later version.
4018+ *
4019+ * This program is distributed in the hope that it will be useful,
4020+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4021+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4022+ * GNU General Public License for more details.
4023+ *
4024+ * You should have received a copy of the GNU General Public License
4025+ * along with this program; if not, write to the Free Software
4026+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
4027+ * 02111-1307, USA.
4028+ *
4029+ * Written By: Ray Strode
4030+ */
4031+#include "config.h"
4032+
4033+#include "gsd-smartcard-manager.h"
4034+
4035+#define SMARTCARD_ENABLE_INTERNAL_API
4036+#include "gsd-smartcard.h"
4037+
4038+#include <dirent.h>
4039+#include <errno.h>
4040+#include <fcntl.h>
4041+#include <limits.h>
4042+#include <poll.h>
4043+#include <signal.h>
4044+#include <stdlib.h>
4045+#include <string.h>
4046+#include <sys/resource.h>
4047+#include <sys/time.h>
4048+#include <sys/wait.h>
4049+#include <unistd.h>
4050+
4051+#include <glib.h>
4052+#include <glib/gi18n.h>
4053+
4054+#include <prerror.h>
4055+#include <prinit.h>
4056+#include <nss.h>
4057+#include <pk11func.h>
4058+#include <secmod.h>
4059+#include <secerr.h>
4060+
4061+#ifndef GSD_SMARTCARD_MANAGER_DRIVER
4062+#define GSD_SMARTCARD_MANAGER_DRIVER LIBDIR"/pkcs11/libcoolkeypk11.so"
4063+#endif
4064+
4065+#ifndef GSD_SMARTCARD_MANAGER_NSS_DB
4066+#define GSD_SMARTCARD_MANAGER_NSS_DB SYSCONFDIR"/pki/nssdb"
4067+#endif
4068+
4069+#ifndef GSD_MAX_OPEN_FILE_DESCRIPTORS
4070+#define GSD_MAX_OPEN_FILE_DESCRIPTORS 1024
4071+#endif
4072+
4073+#ifndef GSD_OPEN_FILE_DESCRIPTORS_DIR
4074+#define GSD_OPEN_FILE_DESCRIPTORS_DIR "/proc/self/fd"
4075+#endif
4076+
4077+typedef enum _GsdSmartcardManagerState GsdSmartcardManagerState;
4078+typedef struct _GsdSmartcardManagerWorker GsdSmartcardManagerWorker;
4079+
4080+enum _GsdSmartcardManagerState {
4081+ GSD_SMARTCARD_MANAGER_STATE_STOPPED = 0,
4082+ GSD_SMARTCARD_MANAGER_STATE_STARTING,
4083+ GSD_SMARTCARD_MANAGER_STATE_STARTED,
4084+ GSD_SMARTCARD_MANAGER_STATE_STOPPING,
4085+};
4086+
4087+struct _GsdSmartcardManagerPrivate {
4088+ GsdSmartcardManagerState state;
4089+ GList *modules;
4090+ char *module_path;
4091+
4092+ GList *workers;
4093+
4094+ GPid smartcard_event_watcher_pid;
4095+ GHashTable *smartcards;
4096+
4097+ guint poll_timeout_id;
4098+
4099+ guint32 is_unstoppable : 1;
4100+ guint32 nss_is_loaded : 1;
4101+};
4102+
4103+struct _GsdSmartcardManagerWorker {
4104+ GsdSmartcardManager *manager;
4105+ int manager_fd;
4106+
4107+ GThread *thread;
4108+ SECMODModule *module;
4109+ GHashTable *smartcards;
4110+ int fd;
4111+ GSource *event_source;
4112+
4113+ guint32 nss_is_loaded : 1;
4114+};
4115+
4116+static void gsd_smartcard_manager_finalize (GObject *object);
4117+static void gsd_smartcard_manager_class_install_signals (GsdSmartcardManagerClass *service_class);
4118+static void gsd_smartcard_manager_class_install_properties (GsdSmartcardManagerClass *service_class);
4119+static void gsd_smartcard_manager_set_property (GObject *object,
4120+ guint prop_id,
4121+ const GValue *value,
4122+ GParamSpec *pspec);
4123+static void gsd_smartcard_manager_get_property (GObject *object,
4124+ guint prop_id,
4125+ GValue *value,
4126+ GParamSpec *pspec);
4127+static void gsd_smartcard_manager_set_module_path (GsdSmartcardManager *manager,
4128+ const char *module_path);
4129+static void gsd_smartcard_manager_card_removed_handler (GsdSmartcardManager *manager,
4130+ GsdSmartcard *card);
4131+static void gsd_smartcard_manager_card_inserted_handler (GsdSmartcardManager *manager_class,
4132+ GsdSmartcard *card);
4133+static gboolean gsd_smartcard_manager_stop_now (GsdSmartcardManager *manager);
4134+static void gsd_smartcard_manager_queue_stop (GsdSmartcardManager *manager);
4135+
4136+static GsdSmartcardManagerWorker *gsd_smartcard_manager_create_worker (GsdSmartcardManager *manager,
4137+ SECMODModule *module);
4138+
4139+static GsdSmartcardManagerWorker * gsd_smartcard_manager_worker_new (GsdSmartcardManager *manager,
4140+ int worker_fd,
4141+ int manager_fd,
4142+ SECMODModule *module);
4143+static void gsd_smartcard_manager_worker_free (GsdSmartcardManagerWorker *worker);
4144+static gboolean open_pipe (int *write_fd, int *read_fd);
4145+static gboolean read_bytes (int fd, gpointer bytes, gsize num_bytes);
4146+static gboolean write_bytes (int fd, gconstpointer bytes, gsize num_bytes);
4147+static GsdSmartcard *read_smartcard (int fd, SECMODModule *module);
4148+static gboolean write_smartcard (int fd, GsdSmartcard *card);
4149+
4150+enum {
4151+ PROP_0 = 0,
4152+ PROP_MODULE_PATH,
4153+ NUMBER_OF_PROPERTIES
4154+};
4155+
4156+enum {
4157+ SMARTCARD_INSERTED = 0,
4158+ SMARTCARD_REMOVED,
4159+ ERROR,
4160+ NUMBER_OF_SIGNALS
4161+};
4162+
4163+static guint gsd_smartcard_manager_signals[NUMBER_OF_SIGNALS];
4164+
4165+G_DEFINE_TYPE (GsdSmartcardManager,
4166+ gsd_smartcard_manager,
4167+ G_TYPE_OBJECT);
4168+
4169+static void
4170+gsd_smartcard_manager_class_init (GsdSmartcardManagerClass *manager_class)
4171+{
4172+ GObjectClass *gobject_class;
4173+
4174+ gobject_class = G_OBJECT_CLASS (manager_class);
4175+
4176+ gobject_class->finalize = gsd_smartcard_manager_finalize;
4177+
4178+ gsd_smartcard_manager_class_install_signals (manager_class);
4179+ gsd_smartcard_manager_class_install_properties (manager_class);
4180+
4181+ g_type_class_add_private (manager_class,
4182+ sizeof (GsdSmartcardManagerPrivate));
4183+}
4184+
4185+static void
4186+gsd_smartcard_manager_class_install_properties (GsdSmartcardManagerClass *card_class)
4187+{
4188+ GObjectClass *object_class;
4189+ GParamSpec *param_spec;
4190+
4191+ object_class = G_OBJECT_CLASS (card_class);
4192+ object_class->set_property = gsd_smartcard_manager_set_property;
4193+ object_class->get_property = gsd_smartcard_manager_get_property;
4194+
4195+ param_spec = g_param_spec_string ("module-path", "Module Path",
4196+ "path to smartcard PKCS #11 driver",
4197+ NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
4198+ g_object_class_install_property (object_class, PROP_MODULE_PATH, param_spec);
4199+}
4200+
4201+static void
4202+gsd_smartcard_manager_set_property (GObject *object,
4203+ guint prop_id,
4204+ const GValue *value,
4205+ GParamSpec *pspec)
4206+{
4207+ GsdSmartcardManager *manager = GSD_SMARTCARD_MANAGER (object);
4208+
4209+ switch (prop_id) {
4210+ case PROP_MODULE_PATH:
4211+ gsd_smartcard_manager_set_module_path (manager,
4212+ g_value_get_string (value));
4213+ break;
4214+
4215+ default:
4216+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4217+ break;
4218+ }
4219+}
4220+
4221+static void
4222+gsd_smartcard_manager_get_property (GObject *object,
4223+ guint prop_id,
4224+ GValue *value,
4225+ GParamSpec *pspec)
4226+{
4227+ GsdSmartcardManager *manager = GSD_SMARTCARD_MANAGER (object);
4228+ char *module_path;
4229+
4230+ switch (prop_id) {
4231+ case PROP_MODULE_PATH:
4232+ module_path = gsd_smartcard_manager_get_module_path (manager);
4233+ g_value_set_string (value, module_path);
4234+ g_free (module_path);
4235+ break;
4236+
4237+ default:
4238+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4239+ break;
4240+ }
4241+}
4242+
4243+char *
4244+gsd_smartcard_manager_get_module_path (GsdSmartcardManager *manager)
4245+{
4246+ return manager->priv->module_path;
4247+}
4248+
4249+static void
4250+gsd_smartcard_manager_set_module_path (GsdSmartcardManager *manager,
4251+ const char *module_path)
4252+{
4253+ if ((manager->priv->module_path == NULL) && (module_path == NULL)) {
4254+ return;
4255+ }
4256+
4257+ if (((manager->priv->module_path == NULL) ||
4258+ (module_path == NULL) ||
4259+ (strcmp (manager->priv->module_path, module_path) != 0))) {
4260+ g_free (manager->priv->module_path);
4261+ manager->priv->module_path = g_strdup (module_path);
4262+ g_object_notify (G_OBJECT (manager), "module-path");
4263+ }
4264+}
4265+
4266+static void
4267+gsd_smartcard_manager_card_removed_handler (GsdSmartcardManager *manager,
4268+ GsdSmartcard *card)
4269+{
4270+ g_debug ("informing smartcard of its removal");
4271+ _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_REMOVED);
4272+ g_debug ("done");
4273+}
4274+
4275+static void
4276+gsd_smartcard_manager_card_inserted_handler (GsdSmartcardManager *manager,
4277+ GsdSmartcard *card)
4278+{
4279+ g_debug ("informing smartcard of its insertion");
4280+
4281+ _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_INSERTED);
4282+ g_debug ("done");
4283+
4284+}
4285+
4286+static void
4287+gsd_smartcard_manager_class_install_signals (GsdSmartcardManagerClass *manager_class)
4288+{
4289+ GObjectClass *object_class;
4290+
4291+ object_class = G_OBJECT_CLASS (manager_class);
4292+
4293+ gsd_smartcard_manager_signals[SMARTCARD_INSERTED] =
4294+ g_signal_new ("smartcard-inserted",
4295+ G_OBJECT_CLASS_TYPE (object_class),
4296+ G_SIGNAL_RUN_FIRST,
4297+ G_STRUCT_OFFSET (GsdSmartcardManagerClass,
4298+ smartcard_inserted),
4299+ NULL, NULL, g_cclosure_marshal_VOID__POINTER,
4300+ G_TYPE_NONE, 1, G_TYPE_POINTER);
4301+ manager_class->smartcard_inserted = gsd_smartcard_manager_card_inserted_handler;
4302+
4303+ gsd_smartcard_manager_signals[SMARTCARD_REMOVED] =
4304+ g_signal_new ("smartcard-removed",
4305+ G_OBJECT_CLASS_TYPE (object_class),
4306+ G_SIGNAL_RUN_FIRST,
4307+ G_STRUCT_OFFSET (GsdSmartcardManagerClass,
4308+ smartcard_removed),
4309+ NULL, NULL, g_cclosure_marshal_VOID__POINTER,
4310+ G_TYPE_NONE, 1, G_TYPE_POINTER);
4311+ manager_class->smartcard_removed = gsd_smartcard_manager_card_removed_handler;
4312+
4313+ gsd_smartcard_manager_signals[ERROR] =
4314+ g_signal_new ("error",
4315+ G_OBJECT_CLASS_TYPE (object_class),
4316+ G_SIGNAL_RUN_LAST,
4317+ G_STRUCT_OFFSET (GsdSmartcardManagerClass, error),
4318+ NULL, NULL, g_cclosure_marshal_VOID__POINTER,
4319+ G_TYPE_NONE, 1, G_TYPE_POINTER);
4320+ manager_class->error = NULL;
4321+}
4322+
4323+static gboolean
4324+slot_id_equal (CK_SLOT_ID *slot_id_1,
4325+ CK_SLOT_ID *slot_id_2)
4326+{
4327+ g_assert (slot_id_1 != NULL);
4328+ g_assert (slot_id_2 != NULL);
4329+
4330+ return *slot_id_1 == *slot_id_2;
4331+}
4332+
4333+static gboolean
4334+slot_id_hash (CK_SLOT_ID *slot_id)
4335+{
4336+ guint32 upper_bits, lower_bits;
4337+ int temp;
4338+
4339+ if (sizeof (CK_SLOT_ID) == sizeof (int)) {
4340+ return g_int_hash (slot_id);
4341+ }
4342+
4343+ upper_bits = ((*slot_id) >> 31) - 1;
4344+ lower_bits = (*slot_id) & 0xffffffff;
4345+
4346+ /* The upper bits are almost certainly always zero,
4347+ * so let's degenerate to g_int_hash for the
4348+ * (very) common case
4349+ */
4350+ temp = lower_bits + upper_bits;
4351+ return upper_bits + g_int_hash (&temp);
4352+}
4353+
4354+static void
4355+gsd_smartcard_manager_init (GsdSmartcardManager *manager)
4356+{
4357+ g_debug ("initializing smartcard manager");
4358+
4359+ manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
4360+ GSD_TYPE_SMARTCARD_MANAGER,
4361+ GsdSmartcardManagerPrivate);
4362+ manager->priv->poll_timeout_id = 0;
4363+ manager->priv->is_unstoppable = FALSE;
4364+
4365+ manager->priv->smartcards =
4366+ g_hash_table_new_full (g_str_hash,
4367+ g_str_equal,
4368+ (GDestroyNotify) g_free,
4369+ (GDestroyNotify) g_object_unref);
4370+}
4371+
4372+static void
4373+gsd_smartcard_manager_finalize (GObject *object)
4374+{
4375+ GsdSmartcardManager *manager;
4376+ GObjectClass *gobject_class;
4377+
4378+ manager = GSD_SMARTCARD_MANAGER (object);
4379+ gobject_class =
4380+ G_OBJECT_CLASS (gsd_smartcard_manager_parent_class);
4381+
4382+ gsd_smartcard_manager_stop_now (manager);
4383+
4384+ g_hash_table_destroy (manager->priv->smartcards);
4385+ manager->priv->smartcards = NULL;
4386+
4387+ gobject_class->finalize (object);
4388+}
4389+
4390+GQuark
4391+gsd_smartcard_manager_error_quark (void)
4392+{
4393+ static GQuark error_quark = 0;
4394+
4395+ if (error_quark == 0) {
4396+ error_quark = g_quark_from_static_string ("gsd-smartcard-manager-error-quark");
4397+ }
4398+
4399+ return error_quark;
4400+}
4401+
4402+GsdSmartcardManager *
4403+gsd_smartcard_manager_new (const char *module_path)
4404+{
4405+ GsdSmartcardManager *instance;
4406+
4407+ instance = GSD_SMARTCARD_MANAGER (g_object_new (GSD_TYPE_SMARTCARD_MANAGER,
4408+ "module-path", module_path,
4409+ NULL));
4410+
4411+ return instance;
4412+}
4413+
4414+static void
4415+gsd_smartcard_manager_emit_error (GsdSmartcardManager *manager,
4416+ GError *error)
4417+{
4418+ manager->priv->is_unstoppable = TRUE;
4419+ g_signal_emit (manager, gsd_smartcard_manager_signals[ERROR], 0,
4420+ error);
4421+ manager->priv->is_unstoppable = FALSE;
4422+}
4423+
4424+static void
4425+gsd_smartcard_manager_emit_smartcard_inserted (GsdSmartcardManager *manager,
4426+ GsdSmartcard *card)
4427+{
4428+ manager->priv->is_unstoppable = TRUE;
4429+ g_signal_emit (manager, gsd_smartcard_manager_signals[SMARTCARD_INSERTED], 0,
4430+ card);
4431+ manager->priv->is_unstoppable = FALSE;
4432+}
4433+
4434+static void
4435+gsd_smartcard_manager_emit_smartcard_removed (GsdSmartcardManager *manager,
4436+ GsdSmartcard *card)
4437+{
4438+ manager->priv->is_unstoppable = TRUE;
4439+ g_signal_emit (manager, gsd_smartcard_manager_signals[SMARTCARD_REMOVED], 0,
4440+ card);
4441+ manager->priv->is_unstoppable = FALSE;
4442+}
4443+
4444+static gboolean
4445+gsd_smartcard_manager_check_for_and_process_events (GIOChannel *io_channel,
4446+ GIOCondition condition,
4447+ GsdSmartcardManagerWorker *worker)
4448+{
4449+ GsdSmartcard *card;
4450+ GsdSmartcardManager *manager;
4451+ gboolean should_stop;
4452+ guchar event_type;
4453+ char *card_name;
4454+ int fd;
4455+
4456+ manager = worker->manager;
4457+
4458+ g_debug ("event!");
4459+ card = NULL;
4460+ should_stop = (condition & G_IO_HUP) || (condition & G_IO_ERR);
4461+
4462+ if (should_stop) {
4463+ g_debug ("received %s on event socket, stopping "
4464+ "manager...",
4465+ (condition & G_IO_HUP) && (condition & G_IO_ERR)?
4466+ "error and hangup" :
4467+ (condition & G_IO_HUP)?
4468+ "hangup" : "error");
4469+ }
4470+
4471+ if (!(condition & G_IO_IN)) {
4472+ g_debug ("nevermind outta here!");
4473+ goto out;
4474+ }
4475+
4476+ fd = g_io_channel_unix_get_fd (io_channel);
4477+
4478+ event_type = '\0';
4479+ if (!read_bytes (fd, &event_type, 1)) {
4480+ g_debug ("could not read event type, stopping");
4481+ should_stop = TRUE;
4482+ goto out;
4483+ }
4484+
4485+ card = read_smartcard (fd, worker->module);
4486+
4487+ if (card == NULL) {
4488+ g_debug ("could not read card, stopping");
4489+ should_stop = TRUE;
4490+ goto out;
4491+ }
4492+
4493+ card_name = gsd_smartcard_get_name (card);
4494+ g_debug ("card '%s' had event %c", card_name, event_type);
4495+
4496+ switch (event_type) {
4497+ case 'I':
4498+ g_hash_table_replace (manager->priv->smartcards,
4499+ card_name, card);
4500+ card_name = NULL;
4501+
4502+ gsd_smartcard_manager_emit_smartcard_inserted (manager, card);
4503+ card = NULL;
4504+ break;
4505+
4506+ case 'R':
4507+ gsd_smartcard_manager_emit_smartcard_removed (manager, card);
4508+ if (!g_hash_table_remove (manager->priv->smartcards, card_name)) {
4509+ g_debug ("got removal event of unknown card!");
4510+ }
4511+ g_free (card_name);
4512+ card_name = NULL;
4513+ card = NULL;
4514+ break;
4515+
4516+ default:
4517+ g_free (card_name);
4518+ card_name = NULL;
4519+ g_object_unref (card);
4520+
4521+ should_stop = TRUE;
4522+ break;
4523+ }
4524+
4525+out:
4526+ if (should_stop) {
4527+ GError *error;
4528+
4529+ error = g_error_new (GSD_SMARTCARD_MANAGER_ERROR,
4530+ GSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS,
4531+ "%s", (condition & G_IO_IN) ? g_strerror (errno) : _("received error or hang up from event source"));
4532+
4533+ gsd_smartcard_manager_emit_error (manager, error);
4534+ g_error_free (error);
4535+ gsd_smartcard_manager_stop_now (manager);
4536+ return FALSE;
4537+ }
4538+
4539+ return TRUE;
4540+}
4541+
4542+static void
4543+stop_manager (GsdSmartcardManager *manager)
4544+{
4545+ manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STOPPED;
4546+
4547+ if (manager->priv->nss_is_loaded) {
4548+ NSS_Shutdown ();
4549+ manager->priv->nss_is_loaded = FALSE;
4550+ }
4551+ g_debug ("smartcard manager stopped");
4552+}
4553+
4554+static void
4555+stop_worker (GsdSmartcardManagerWorker *worker)
4556+{
4557+ GsdSmartcardManager *manager;
4558+
4559+ manager = worker->manager;
4560+
4561+ if (worker->event_source != NULL) {
4562+ g_source_destroy (worker->event_source);
4563+ worker->event_source = NULL;
4564+ }
4565+
4566+ if (worker->thread != NULL) {
4567+ SECMOD_CancelWait (worker->module);
4568+ worker->thread = NULL;
4569+ }
4570+
4571+ SECMOD_DestroyModule (worker->module);
4572+ manager->priv->workers = g_list_remove (manager->priv->workers, worker);
4573+
4574+ if (manager->priv->workers == NULL && manager->priv->state != GSD_SMARTCARD_MANAGER_STATE_STOPPED) {
4575+ stop_manager (manager);
4576+ }
4577+}
4578+
4579+static void
4580+gsd_smartcard_manager_event_processing_stopped_handler (GsdSmartcardManagerWorker *worker)
4581+{
4582+ worker->event_source = NULL;
4583+
4584+ stop_worker (worker);
4585+}
4586+
4587+static gboolean
4588+open_pipe (int *write_fd,
4589+ int *read_fd)
4590+{
4591+ int pipe_fds[2] = { -1, -1 };
4592+
4593+ g_assert (write_fd != NULL);
4594+ g_assert (read_fd != NULL);
4595+
4596+ if (pipe (pipe_fds) < 0) {
4597+ return FALSE;
4598+ }
4599+
4600+ if (fcntl (pipe_fds[0], F_SETFD, FD_CLOEXEC) < 0) {
4601+ close (pipe_fds[0]);
4602+ close (pipe_fds[1]);
4603+ return FALSE;
4604+ }
4605+
4606+ if (fcntl (pipe_fds[1], F_SETFD, FD_CLOEXEC) < 0) {
4607+ close (pipe_fds[0]);
4608+ close (pipe_fds[1]);
4609+ return FALSE;
4610+ }
4611+
4612+ *read_fd = pipe_fds[0];
4613+ *write_fd = pipe_fds[1];
4614+
4615+ return TRUE;
4616+}
4617+
4618+static void
4619+gsd_smartcard_manager_stop_watching_for_events (GsdSmartcardManager *manager)
4620+{
4621+ GList *node;
4622+
4623+ node = manager->priv->workers;
4624+ while (node != NULL) {
4625+ GsdSmartcardManagerWorker *worker;
4626+ GList *next_node;
4627+
4628+ worker = (GsdSmartcardManagerWorker *) node->data;
4629+ next_node = node->next;
4630+
4631+ stop_worker (worker);
4632+
4633+ node = next_node;
4634+ }
4635+}
4636+
4637+static gboolean
4638+load_nss (GError **error)
4639+{
4640+ SECStatus status = SECSuccess;
4641+ static const guint32 flags =
4642+ NSS_INIT_READONLY |
4643+ NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT |
4644+ NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD;
4645+
4646+ g_debug ("attempting to load NSS database '%s'",
4647+ GSD_SMARTCARD_MANAGER_NSS_DB);
4648+
4649+ PR_Init (PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
4650+
4651+ status = NSS_Initialize (GSD_SMARTCARD_MANAGER_NSS_DB,
4652+ "", "", SECMOD_DB, flags);
4653+
4654+ if (status != SECSuccess) {
4655+ gsize error_message_size;
4656+ char *error_message;
4657+
4658+ error_message_size = PR_GetErrorTextLength ();
4659+
4660+ if (error_message_size == 0) {
4661+ g_debug ("NSS security system could not be initialized");
4662+ g_set_error (error,
4663+ GSD_SMARTCARD_MANAGER_ERROR,
4664+ GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS,
4665+ _("NSS security system could not be initialized"));
4666+ goto out;
4667+ }
4668+
4669+ error_message = g_slice_alloc0 (error_message_size);
4670+ PR_GetErrorText (error_message);
4671+
4672+ g_set_error (error,
4673+ GSD_SMARTCARD_MANAGER_ERROR,
4674+ GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS,
4675+ "%s", error_message);
4676+ g_debug ("NSS security system could not be initialized - %s",
4677+ error_message);
4678+
4679+ g_slice_free1 (error_message_size, error_message);
4680+
4681+ goto out;
4682+ }
4683+
4684+ g_debug ("NSS database sucessfully loaded");
4685+ return TRUE;
4686+
4687+out:
4688+ g_debug ("NSS database couldn't be sucessfully loaded");
4689+ return FALSE;
4690+}
4691+
4692+static GList *
4693+get_available_modules (GsdSmartcardManager *manager)
4694+{
4695+ SECMODModuleList *module_list, *tmp;
4696+ GList *modules;
4697+
4698+ g_debug ("Getting list of suitable modules");
4699+
4700+ module_list = SECMOD_GetDefaultModuleList ();
4701+ modules = NULL;
4702+ for (tmp = module_list; tmp != NULL; tmp = tmp->next) {
4703+ if (!SECMOD_HasRemovableSlots (tmp->module) ||
4704+ !tmp->module->loaded)
4705+ continue;
4706+
4707+ g_debug ("Using module '%s'", tmp->module->commonName);
4708+
4709+ modules = g_list_prepend (modules,
4710+ SECMOD_ReferenceModule (tmp->module));
4711+ }
4712+
4713+ return modules;
4714+}
4715+
4716+static gboolean
4717+load_driver (GsdSmartcardManager *manager,
4718+ char *module_path,
4719+ GError **error)
4720+{
4721+ GList *modules;
4722+ char *module_spec;
4723+ gboolean module_explicitly_specified;
4724+
4725+ g_debug ("attempting to load driver...");
4726+
4727+ modules = NULL;
4728+ module_explicitly_specified = module_path != NULL;
4729+ if (module_explicitly_specified) {
4730+ SECMODModule *module;
4731+
4732+ module_spec = g_strdup_printf ("library=\"%s\"", module_path);
4733+ g_debug ("loading smartcard driver using spec '%s'",
4734+ module_spec);
4735+
4736+ module = SECMOD_LoadUserModule (module_spec,
4737+ NULL /* parent */,
4738+ FALSE /* recurse */);
4739+ g_free (module_spec);
4740+ module_spec = NULL;
4741+
4742+ if (!SECMOD_HasRemovableSlots (module) ||
4743+ !module->loaded) {
4744+ modules = g_list_prepend (modules, module);
4745+ } else {
4746+ g_debug ("fallback module found but not %s",
4747+ SECMOD_HasRemovableSlots (module)?
4748+ "removable" : "loaded");
4749+ SECMOD_DestroyModule (module);
4750+ }
4751+
4752+ } else {
4753+ SECMODListLock *lock;
4754+
4755+ lock = SECMOD_GetDefaultModuleListLock ();
4756+
4757+ if (lock != NULL) {
4758+ SECMOD_GetReadLock (lock);
4759+ modules = get_available_modules (manager);
4760+ SECMOD_ReleaseReadLock (lock);
4761+ }
4762+
4763+ /* fallback to compiled in driver path
4764+ */
4765+ if (modules == NULL) {
4766+ SECMODModule *module;
4767+ module_path = GSD_SMARTCARD_MANAGER_DRIVER;
4768+ module_spec = g_strdup_printf ("library=\"%s\"", module_path);
4769+ g_debug ("loading smartcard driver using spec '%s'",
4770+ module_spec);
4771+
4772+ module = SECMOD_LoadUserModule (module_spec,
4773+ NULL /* parent */,
4774+ FALSE /* recurse */);
4775+ g_free (module_spec);
4776+ module_spec = NULL;
4777+
4778+ if (!SECMOD_HasRemovableSlots (module) ||
4779+ !module->loaded) {
4780+ modules = g_list_prepend (modules, module);
4781+ } else {
4782+ g_debug ("fallback module found but not loaded");
4783+ SECMOD_DestroyModule (module);
4784+ }
4785+ }
4786+
4787+ }
4788+
4789+ if (!module_explicitly_specified && modules == NULL) {
4790+ g_set_error (error,
4791+ GSD_SMARTCARD_MANAGER_ERROR,
4792+ GSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER,
4793+ _("no suitable smartcard driver could be found"));
4794+ } else if (modules == NULL) {
4795+
4796+ gsize error_message_size;
4797+ char *error_message;
4798+
4799+ error_message_size = PR_GetErrorTextLength ();
4800+
4801+ if (error_message_size == 0) {
4802+ g_debug ("smartcard driver '%s' could not be loaded",
4803+ module_path);
4804+ g_set_error (error,
4805+ GSD_SMARTCARD_MANAGER_ERROR,
4806+ GSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER,
4807+ _("smartcard driver '%s' could not be "
4808+ "loaded"), module_path);
4809+ goto out;
4810+ }
4811+
4812+ error_message = g_slice_alloc0 (error_message_size);
4813+ PR_GetErrorText (error_message);
4814+
4815+ g_set_error (error,
4816+ GSD_SMARTCARD_MANAGER_ERROR,
4817+ GSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER,
4818+ "%s", error_message);
4819+
4820+ g_debug ("smartcard driver '%s' could not be loaded - %s",
4821+ module_path, error_message);
4822+ g_slice_free1 (error_message_size, error_message);
4823+ }
4824+
4825+ manager->priv->modules = modules;
4826+out:
4827+ return manager->priv->modules != NULL;
4828+}
4829+
4830+static void
4831+gsd_smartcard_manager_get_all_cards (GsdSmartcardManager *manager)
4832+{
4833+ GList *node;
4834+ int i;
4835+
4836+ node = manager->priv->workers;
4837+ while (node != NULL) {
4838+
4839+ GsdSmartcardManagerWorker *worker;
4840+
4841+ worker = (GsdSmartcardManagerWorker *) node->data;
4842+
4843+ for (i = 0; i < worker->module->slotCount; i++) {
4844+ GsdSmartcard *card;
4845+ CK_SLOT_ID slot_id;
4846+ int slot_series;
4847+ char *card_name;
4848+
4849+ slot_id = PK11_GetSlotID (worker->module->slots[i]);
4850+ slot_series = PK11_GetSlotSeries (worker->module->slots[i]);
4851+
4852+ card = _gsd_smartcard_new (worker->module,
4853+ slot_id, slot_series);
4854+
4855+ card_name = gsd_smartcard_get_name (card);
4856+
4857+ g_hash_table_replace (manager->priv->smartcards,
4858+ card_name, card);
4859+ }
4860+ node = node->next;
4861+ }
4862+}
4863+
4864+static GsdSmartcardManagerWorker *
4865+start_worker (GsdSmartcardManager *manager,
4866+ SECMODModule *module,
4867+ GError **error)
4868+{
4869+ GIOChannel *io_channel;
4870+ GSource *source;
4871+ GsdSmartcardManagerWorker *worker;
4872+
4873+ worker = gsd_smartcard_manager_create_worker (manager, module);
4874+
4875+ if (worker == NULL) {
4876+ g_set_error (error,
4877+ GSD_SMARTCARD_MANAGER_ERROR,
4878+ GSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS,
4879+ _("could not watch for incoming card events - %s"),
4880+ g_strerror (errno));
4881+
4882+ goto out;
4883+ }
4884+
4885+ io_channel = g_io_channel_unix_new (worker->manager_fd);
4886+
4887+ source = g_io_create_watch (io_channel, G_IO_IN | G_IO_HUP);
4888+ g_io_channel_unref (io_channel);
4889+ io_channel = NULL;
4890+
4891+ worker->event_source = source;
4892+
4893+ g_source_set_callback (worker->event_source,
4894+ (GSourceFunc) (GIOFunc)
4895+ gsd_smartcard_manager_check_for_and_process_events,
4896+ worker,
4897+ (GDestroyNotify)
4898+ gsd_smartcard_manager_event_processing_stopped_handler);
4899+ g_source_attach (worker->event_source, NULL);
4900+ g_source_unref (worker->event_source);
4901+out:
4902+ return worker;
4903+}
4904+
4905+static void
4906+start_workers (GsdSmartcardManager *manager)
4907+{
4908+ GList *node;
4909+
4910+ node = manager->priv->modules;
4911+ while (node != NULL) {
4912+ SECMODModule *module;
4913+ GsdSmartcardManagerWorker *worker;
4914+ GError *error;
4915+
4916+ module = (SECMODModule *) node->data;
4917+
4918+ error = NULL;
4919+ worker = start_worker (manager, module, &error);
4920+ if (worker == NULL) {
4921+ g_warning ("%s", error->message);
4922+ g_error_free (error);
4923+ } else {
4924+ manager->priv->workers = g_list_prepend (manager->priv->workers,
4925+ worker);
4926+ }
4927+ node = node->next;
4928+ }
4929+}
4930+
4931+gboolean
4932+gsd_smartcard_manager_start (GsdSmartcardManager *manager,
4933+ GError **error)
4934+{
4935+ GError *nss_error;
4936+
4937+ if (manager->priv->state == GSD_SMARTCARD_MANAGER_STATE_STARTED) {
4938+ g_debug ("smartcard manager already started");
4939+ return TRUE;
4940+ }
4941+
4942+ manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STARTING;
4943+
4944+ nss_error = NULL;
4945+ if (!manager->priv->nss_is_loaded && !load_nss (&nss_error)) {
4946+ g_propagate_error (error, nss_error);
4947+ goto out;
4948+ }
4949+ manager->priv->nss_is_loaded = TRUE;
4950+
4951+ if (manager->priv->modules == NULL) {
4952+ if (!load_driver (manager, manager->priv->module_path, &nss_error)) {
4953+ g_propagate_error (error, nss_error);
4954+ goto out;
4955+ }
4956+ }
4957+
4958+ start_workers (manager);
4959+
4960+ /* populate the hash with cards that are already inserted
4961+ */
4962+ gsd_smartcard_manager_get_all_cards (manager);
4963+
4964+ manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STARTED;
4965+
4966+out:
4967+ /* don't leave it in a half started state
4968+ */
4969+ if (manager->priv->state != GSD_SMARTCARD_MANAGER_STATE_STARTED) {
4970+ g_debug ("smartcard manager could not be completely started");
4971+ gsd_smartcard_manager_stop (manager);
4972+ } else {
4973+ g_debug ("smartcard manager started");
4974+ }
4975+
4976+ return manager->priv->state == GSD_SMARTCARD_MANAGER_STATE_STARTED;
4977+}
4978+
4979+static gboolean
4980+gsd_smartcard_manager_stop_now (GsdSmartcardManager *manager)
4981+{
4982+ if (manager->priv->state == GSD_SMARTCARD_MANAGER_STATE_STOPPED) {
4983+ return FALSE;
4984+ }
4985+
4986+ gsd_smartcard_manager_stop_watching_for_events (manager);
4987+
4988+ return FALSE;
4989+}
4990+
4991+static void
4992+gsd_smartcard_manager_queue_stop (GsdSmartcardManager *manager)
4993+{
4994+
4995+ manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STOPPING;
4996+
4997+ g_idle_add ((GSourceFunc) gsd_smartcard_manager_stop_now, manager);
4998+}
4999+
5000+void
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches