[gnome-settings-daemon] media-keys: Implement GConf keyboard shortcuts
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-settings-daemon] media-keys: Implement GConf keyboard shortcuts
- Date: Wed, 2 Nov 2011 20:13:42 +0000 (UTC)
commit 3bf59d722474d480d49d4172664b2a33a9de2bb6
Author: Bastien Nocera <hadess hadess net>
Date: Wed Nov 2 19:40:41 2011 +0000
media-keys: Implement GConf keyboard shortcuts
Including ungrabbing them.
https://bugzilla.gnome.org/show_bug.cgi?id=625228
Note that some of the keybindings seem to fail at unbinding (even though
they get ungrabbed correctly), no idea why.
configure.ac | 2 +-
plugins/media-keys/gsd-media-keys-manager.c | 207 ++++++++++++++++++++++++++-
2 files changed, 202 insertions(+), 7 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index b26d4d6..29db86c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -217,7 +217,7 @@ dnl ---------------------------------------------------------------------------
dnl - media-keys plugin stuff
dnl ---------------------------------------------------------------------------
-PKG_CHECK_MODULES(MEDIA_KEYS, [gio-unix-2.0 libpulse >= $PA_REQUIRED_VERSION $GUDEV_PKG libpulse-mainloop-glib >= $PA_REQUIRED_VERSION libcanberra])
+PKG_CHECK_MODULES(MEDIA_KEYS, [gio-unix-2.0 libpulse >= $PA_REQUIRED_VERSION $GUDEV_PKG libpulse-mainloop-glib >= $PA_REQUIRED_VERSION libcanberra gconf-2.0 >= $GCONF_REQUIRED_VERSION])
dnl ---------------------------------------------------------------------------
dnl - color
diff --git a/plugins/media-keys/gsd-media-keys-manager.c b/plugins/media-keys/gsd-media-keys-manager.c
index 2e842f2..bd1d4d2 100644
--- a/plugins/media-keys/gsd-media-keys-manager.c
+++ b/plugins/media-keys/gsd-media-keys-manager.c
@@ -39,6 +39,7 @@
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#include <gio/gdesktopappinfo.h>
+#include <gconf/gconf-client.h>
#ifdef HAVE_GUDEV
#include <gudev/gudev.h>
@@ -67,6 +68,8 @@
#define GNOME_SESSION_DBUS_PATH "/org/gnome/SessionManager"
#define GNOME_SESSION_DBUS_INTERFACE "org.gnome.SessionManager"
+#define GCONF_BINDING_DIR "/desktop/gnome/keybindings"
+
static const gchar introspection_xml[] =
"<node>"
" <interface name='org.gnome.SettingsDaemon.MediaKeys'>"
@@ -108,6 +111,8 @@ typedef struct {
MediaKeyType key_type;
const char *settings_key;
const char *hard_coded;
+ char *gconf_dir;
+ char *custom_command;
Key *key;
} MediaKey;
@@ -127,6 +132,8 @@ struct GsdMediaKeysManagerPrivate
GSettings *settings;
GPtrArray *keys;
+ GConfClient *gconf;
+ guint gconf_id;
/* HighContrast theme settings */
GSettings *interface_settings;
@@ -189,6 +196,8 @@ media_key_free (MediaKey *key)
{
if (key == NULL)
return;
+ g_free (key->gconf_dir);
+ g_free (key->custom_command);
free_key (key->key);
g_free (key);
}
@@ -295,8 +304,17 @@ get_key_string (GsdMediaKeysManager *manager,
{
if (key->settings_key != NULL)
return g_settings_get_string (manager->priv->settings, key->settings_key);
- else
+ else if (key->hard_coded != NULL)
return g_strdup (key->hard_coded);
+ else if (key->gconf_dir != NULL) {
+ char *entry, *str;
+
+ entry = g_strdup_printf ("%s/binding", key->gconf_dir);
+ str = gconf_client_get_string (manager->priv->gconf, entry, NULL);
+ g_free (entry);
+ return str;
+ } else
+ g_assert_not_reached ();
}
static gboolean
@@ -334,9 +352,9 @@ grab_media_key (MediaKey *key,
}
static void
-update_kbd_cb (GSettings *settings,
- const gchar *settings_key,
- GsdMediaKeysManager *manager)
+gsettings_changed_cb (GSettings *settings,
+ const gchar *settings_key,
+ GsdMediaKeysManager *manager)
{
int i;
gboolean need_flush = TRUE;
@@ -349,7 +367,7 @@ update_kbd_cb (GSettings *settings,
key = g_ptr_array_index (manager->priv->keys, i);
- /* Skip over hard-coded keys */
+ /* Skip over hard-coded and GConf keys */
if (key->settings_key == NULL)
continue;
if (strcmp (settings_key, key->settings_key) == 0) {
@@ -365,10 +383,148 @@ update_kbd_cb (GSettings *settings,
g_warning ("Grab failed for some keys, another application may already have access the them.");
}
+static char *
+entry_get_string (GConfEntry *entry)
+{
+ GConfValue *value = gconf_entry_get_value (entry);
+
+ if (value == NULL || value->type != GCONF_VALUE_STRING) {
+ return NULL;
+ }
+
+ return g_strdup (gconf_value_get_string (value));
+}
+
+static MediaKey *
+media_key_new_for_gconf (GsdMediaKeysManager *manager,
+ char *dir)
+{
+ GSList *list, *l;
+ char *action, *binding;
+ MediaKey *key;
+
+ /* Get entries for this binding */
+ list = gconf_client_all_entries (manager->priv->gconf, dir, NULL);
+ action = NULL;
+ binding = NULL;
+
+ for (l = list; l != NULL; l = l->next) {
+ GConfEntry *entry = l->data;
+ char *key_name;
+
+ key_name = g_path_get_basename (gconf_entry_get_key (entry));
+
+ if (key_name == NULL) {
+ /* ignore entry */
+ } else if (strcmp (key_name, "action") == 0) {
+ action = entry_get_string (entry);
+ } else if (strcmp (key_name, "binding") == 0) {
+ binding = entry_get_string (entry);
+ }
+
+ g_free (key_name);
+ gconf_entry_free (entry);
+ }
+
+ g_slist_free (list);
+
+ if (action == NULL && binding == NULL) {
+ g_debug ("Key binding (%s) is incomplete", dir);
+ return NULL;
+ }
+ g_free (binding);
+
+ key = g_new0 (MediaKey, 1);
+ key->key_type = CUSTOM_KEY;
+ key->gconf_dir = dir;
+ key->custom_command = action;
+
+ return key;
+}
+
+static void
+gconf_changed_cb (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ GsdMediaKeysManager *manager)
+{
+ char *gconf_key, **key_elems;
+ int i;
+ MediaKey *key;
+
+ g_return_if_fail (entry != NULL);
+ g_return_if_fail (entry->key[0] == '/');
+
+ /* Look for the dir that changed, thus the MediaKey */
+ key_elems = g_strsplit (entry->key + 1, "/", -1);
+ if (key_elems == NULL ||
+ (g_strv_length (key_elems) != 4 &&
+ g_strv_length (key_elems) != 5)) {
+ g_warning ("Unexpected GConf notification for key '%s'", entry->key);
+ g_strfreev (key_elems);
+ return;
+ }
+
+ if (g_strv_length (key_elems) == 5 &&
+ g_str_equal (key_elems[4], "binding") == FALSE &&
+ g_str_equal (key_elems[4], "action") == FALSE) {
+ g_debug ("Not interested in notification for key '%s'", entry->key);
+ g_strfreev (key_elems);
+ return;
+ }
+ gconf_key = g_strdup_printf ("/%s/%s/%s/%s",
+ key_elems[0],
+ key_elems[1],
+ key_elems[2],
+ key_elems[3]);
+ g_strfreev (key_elems);
+
+ g_debug ("Got notification for key '%s' (dir: '%s')",
+ entry->key, gconf_key);
+
+ /* Remove the existing key */
+ for (i = 0; i < manager->priv->keys->len; i++) {
+ key = g_ptr_array_index (manager->priv->keys, i);
+
+ if (key->gconf_dir == NULL)
+ continue;
+ if (strcmp (key->gconf_dir, gconf_key) == 0) {
+ if (key->key) {
+ gdk_error_trap_push ();
+
+ grab_key_unsafe (key->key, FALSE, manager->priv->screens);
+
+ gdk_flush ();
+ if (gdk_error_trap_pop ())
+ g_warning ("Ungrab failed for GConf key '%s'", gconf_key);
+ }
+ g_ptr_array_remove_index_fast (manager->priv->keys, i);
+ break;
+ }
+ }
+
+ /* And create a new one! */
+ key = media_key_new_for_gconf (manager, gconf_key);
+ if (key) {
+ g_ptr_array_add (manager->priv->keys, key);
+
+ gdk_error_trap_push ();
+
+ grab_media_key (key, manager);
+
+ gdk_flush ();
+ if (gdk_error_trap_pop ())
+ g_warning ("Grab failed for GConf key '%s'", key->gconf_dir);
+ } else {
+ g_free (gconf_key);
+ }
+}
+
static void
init_kbd (GsdMediaKeysManager *manager)
{
int i;
+ GSList *list, *l;
gnome_settings_profile_start (NULL);
@@ -376,6 +532,7 @@ init_kbd (GsdMediaKeysManager *manager)
manager->priv->keys = g_ptr_array_new_with_free_func ((GDestroyNotify) media_key_free);
+ /* Media keys */
for (i = 0; i < G_N_ELEMENTS (media_keys); i++) {
MediaKey *key;
@@ -389,6 +546,22 @@ init_kbd (GsdMediaKeysManager *manager)
grab_media_key (key, manager);
}
+ /* Custom shortcuts */
+ list = gconf_client_all_dirs (manager->priv->gconf, GCONF_BINDING_DIR, NULL);
+ for (l = list; l != NULL; l = l->next) {
+ MediaKey *key;
+
+ key = media_key_new_for_gconf (manager, l->data);
+ if (!key) {
+ g_free (l->data);
+ continue;
+ }
+ g_ptr_array_add (manager->priv->keys, key);
+
+ grab_media_key (key, manager);
+ }
+ g_slist_free (list);
+
gdk_flush ();
if (gdk_error_trap_pop ())
g_warning ("Grab failed for some keys, another application may already have access the them.");
@@ -1545,6 +1718,7 @@ do_custom_action (GsdMediaKeysManager *manager,
MediaKey *key,
gint64 timestamp)
{
+ execute (manager, key->custom_command, FALSE);
}
static gboolean
@@ -1806,9 +1980,19 @@ start_media_keys_idle_cb (GsdMediaKeysManager *manager)
g_debug ("Starting media_keys manager");
gnome_settings_profile_start (NULL);
+
manager->priv->settings = g_settings_new (SETTINGS_BINDING_DIR);
g_signal_connect (G_OBJECT (manager->priv->settings), "changed",
- G_CALLBACK (update_kbd_cb), manager);
+ G_CALLBACK (gsettings_changed_cb), manager);
+
+ manager->priv->gconf = gconf_client_get_default ();
+ gconf_client_add_dir (manager->priv->gconf, GCONF_BINDING_DIR, GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
+ manager->priv->gconf_id = gconf_client_notify_add (manager->priv->gconf,
+ GCONF_BINDING_DIR,
+ (GConfClientNotifyFunc) gconf_changed_cb,
+ manager,
+ NULL,
+ NULL);
/* Sound events */
ca_context_create (&manager->priv->ca);
@@ -2015,6 +2199,17 @@ gsd_media_keys_manager_stop (GsdMediaKeysManager *manager)
gdk_flush ();
gdk_error_trap_pop_ignored ();
+ if (priv->gconf_id) {
+ gconf_client_remove_dir (priv->gconf, GCONF_BINDING_DIR, NULL);
+ gconf_client_notify_remove (priv->gconf, priv->gconf_id);
+ priv->gconf_id = 0;
+ }
+
+ if (priv->gconf) {
+ g_object_unref (priv->gconf);
+ priv->gconf = NULL;
+ }
+
if (priv->screens != NULL) {
g_slist_free (priv->screens);
priv->screens = NULL;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]