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

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
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.

To post a comment you must log in.
Revision history for this message
Sebastien Bacher (seb128) wrote :

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)

review: Needs Fixing

Preview Diff

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

Subscribers

People subscribed via source and target branches