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