[gnome-settings-daemon] media-keys: Implement GConf keyboard shortcuts



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]