gnome-settings-daemon r610 - in trunk: . plugins/common plugins/keybindings plugins/media-keys



Author: jensg
Date: Mon Nov 24 20:48:15 2008
New Revision: 610
URL: http://svn.gnome.org/viewvc/gnome-settings-daemon?rev=610&view=rev

Log:
2008-11-24  Jens Granseuer  <jensgr gmx net>

	When multiple keys (keycodes) were mapped to the same keysym, g-s-d
	would only accept the first of those keycodes in the keymap as a
	valid shortcut. To fix this, instead of checking against a single
	keycode, we need to grab all keycodes that match the respective
	keysym (bug #561275).

	With thanks to Mario Limonciello <mario_limonciello dell com>

	* plugins/common/eggaccelerators.c:
	(egg_accelerator_parse_virtual):
	* plugins/common/eggaccelerators.h: possibly return multiple keycodes
	* plugins/common/gsd-keygrab.c: (grab_key_unsafe),
	(key_uses_keycode), (match_key): grab all matching keys
	* plugins/common/gsd-keygrab.h:
	* plugins/keybindings/gsd-keybindings-manager.c: (parse_binding),
	(bindings_get_entry), (same_keycode), (same_key),
	(key_already_used), (binding_register_keys),
	(gsd_keybindings_manager_stop):
	* plugins/media-keys/gsd-media-keys-manager.c: (update_kbd_cb),
	(init_kbd), (gsd_media_keys_manager_stop): update to handle changes
	in data structures


Modified:
   trunk/ChangeLog
   trunk/plugins/common/eggaccelerators.c
   trunk/plugins/common/eggaccelerators.h
   trunk/plugins/common/gsd-keygrab.c
   trunk/plugins/common/gsd-keygrab.h
   trunk/plugins/keybindings/gsd-keybindings-manager.c
   trunk/plugins/media-keys/gsd-media-keys-manager.c

Modified: trunk/plugins/common/eggaccelerators.c
==============================================================================
--- trunk/plugins/common/eggaccelerators.c	(original)
+++ trunk/plugins/common/eggaccelerators.c	Mon Nov 24 20:48:15 2008
@@ -188,6 +188,8 @@
  * egg_accelerator_parse_virtual:
  * @accelerator:      string representing an accelerator
  * @accelerator_key:  return location for accelerator keyval
+ * @accelerator_codes: return location for a 0-terminated array
+ *                     of accelerator keycodes
  * @accelerator_mods: return location for accelerator modifier mask
  *
  * Parses a string representing a virtual accelerator. The format
@@ -212,7 +214,7 @@
 gboolean
 egg_accelerator_parse_virtual (const gchar            *accelerator,
                                guint                  *accelerator_key,
-			       guint                  *keycode,
+			       guint                 **accelerator_codes,
                                EggVirtualModifierType *accelerator_mods)
 {
   guint keyval;
@@ -224,8 +226,8 @@
     *accelerator_key = 0;
   if (accelerator_mods)
     *accelerator_mods = 0;
-  if (keycode)
-    *keycode = 0;
+  if (accelerator_codes)
+    *accelerator_codes = NULL;
 
   g_return_val_if_fail (accelerator != NULL, FALSE);
 
@@ -345,20 +347,40 @@
 		    {
 		      bad_keyval = TRUE;
 		    }
-		  else if (keycode != NULL)
+		  else if (accelerator_codes != NULL)
 		    {
-		      *keycode = tmp_keycode;
 		      /* 0x00 is an invalid keycode too. */
-		      if (*keycode == 0)
+		      if (tmp_keycode == 0) {
 			bad_keyval = TRUE;
+		      } else {
+			*accelerator_codes = g_new0 (guint, 2);
+			(*accelerator_codes)[0] = tmp_keycode;
+		      }
 		    }
 		}
 	    }
-	  else if (keycode != NULL)
+	  else if (accelerator_codes != NULL)
 	    {
-	      *keycode = XKeysymToKeycode (GDK_DISPLAY(), keyval);
-	      if (*keycode == 0)
-	 	bad_keyval = TRUE;
+	      GdkKeymapKey *keys;
+	      gint n_keys, i, j;
+
+	      if (!gdk_keymap_get_entries_for_keyval (NULL, keyval, &keys, &n_keys)) {
+ 	 	bad_keyval = TRUE;
+	      } else {
+		*accelerator_codes = g_new0 (guint, n_keys + 1);
+
+		for (i = 0, j = 0; i < n_keys; ++i) {
+		  if (keys[i].level == 0)
+		    (*accelerator_codes)[j++] = keys[i].keycode;
+		}
+
+		if (j == 0) {
+		  g_free (*accelerator_codes);
+		  *accelerator_codes = NULL;
+		  bad_keyval = TRUE;
+	        }
+	        g_free (keys);
+	      }
 	    }
 
           accelerator += len;

Modified: trunk/plugins/common/eggaccelerators.h
==============================================================================
--- trunk/plugins/common/eggaccelerators.h	(original)
+++ trunk/plugins/common/eggaccelerators.h	Mon Nov 24 20:48:15 2008
@@ -72,7 +72,7 @@
 
 gboolean egg_accelerator_parse_virtual        (const gchar            *accelerator,
                                                guint                  *accelerator_key,
-					       guint                  *keycode,
+					       guint                 **accelerator_codes,
                                                EggVirtualModifierType *accelerator_mods);
 void     egg_keymap_resolve_virtual_modifiers (GdkKeymap              *keymap,
                                                EggVirtualModifierType  virtual_mods,

Modified: trunk/plugins/common/gsd-keygrab.c
==============================================================================
--- trunk/plugins/common/gsd-keygrab.c	(original)
+++ trunk/plugins/common/gsd-keygrab.c	Mon Nov 24 20:48:15 2008
@@ -152,10 +152,14 @@
 
                 for (l = screens; l; l = l->next) {
                         GdkScreen *screen = l->data;
-                        grab_key_real (key->keycode,
-                                       gdk_screen_get_root_window (screen),
-                                       grab,
-                                       result | key->state);
+                        guint *code;
+
+                        for (code = key->keycodes; *code; ++code) {
+                                grab_key_real (*code,
+                                               gdk_screen_get_root_window (screen),
+                                               grab,
+                                               result | key->state);
+                        }
                 }
         }
 }
@@ -185,6 +189,20 @@
 }
 
 gboolean
+key_uses_keycode (const Key *key, guint keycode)
+{
+	if (key->keycodes != NULL) {
+		guint *c;
+
+		for (c = key->keycodes; *c; ++c) {
+			if (*c == keycode)
+				return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+gboolean
 match_key (Key *key, XEvent *event)
 {
 	guint keyval;
@@ -223,6 +241,6 @@
 
 	/* The key we passed doesn't have a keysym, so try with just the keycode */
         return (key != NULL
-                && key->keycode == event->xkey.keycode
-                && key->state == (event->xkey.state & gsd_used_mods));
+                && key->state == (event->xkey.state & gsd_used_mods)
+                && key_uses_keycode (key, event->xkey.keycode));
 }

Modified: trunk/plugins/common/gsd-keygrab.h
==============================================================================
--- trunk/plugins/common/gsd-keygrab.h	(original)
+++ trunk/plugins/common/gsd-keygrab.h	Mon Nov 24 20:48:15 2008
@@ -28,7 +28,7 @@
 typedef struct {
         guint keysym;
         guint state;
-        guint keycode;
+        guint *keycodes;
 } Key;
 
 
@@ -39,6 +39,9 @@
 gboolean        match_key       (Key     *key,
                                  XEvent  *event);
 
+gboolean        key_uses_keycode (const Key *key,
+                                  guint keycode);
+
 G_END_DECLS
 
 #endif /* __GSD_COMMON_KEYGRAB_H */

Modified: trunk/plugins/keybindings/gsd-keybindings-manager.c
==============================================================================
--- trunk/plugins/keybindings/gsd-keybindings-manager.c	(original)
+++ trunk/plugins/keybindings/gsd-keybindings-manager.c	Mon Nov 24 20:48:15 2008
@@ -119,6 +119,8 @@
 
         binding->key.keysym = 0;
         binding->key.state = 0;
+        g_free (binding->key.keycodes);
+        binding->key.keycodes = NULL;
 
         if (binding->binding_str == NULL ||
             binding->binding_str[0] == '\0' ||
@@ -126,14 +128,10 @@
                 return FALSE;
         }
 
-        if (egg_accelerator_parse_virtual (binding->binding_str,
-                                           &binding->key.keysym,
-                                           &binding->key.keycode,
-                                           &binding->key.state) == FALSE) {
-                return FALSE;
-        }
-
-        return TRUE;
+        return egg_accelerator_parse_virtual (binding->binding_str,
+                                              &binding->key.keysym,
+                                              &binding->key.keycodes,
+                                              &binding->key.state);
 }
 
 static gint
@@ -207,16 +205,17 @@
                 g_free (new_binding->binding_str);
                 g_free (new_binding->action);
                 g_free (new_binding->gconf_key);
+
+                new_binding->previous_key.keysym = new_binding->key.keysym;
+                new_binding->previous_key.state = new_binding->key.state;
+                new_binding->previous_key.keycodes = new_binding->key.keycodes;
+                new_binding->key.keycodes = NULL;
         }
 
         new_binding->binding_str = key;
         new_binding->action = action;
         new_binding->gconf_key = gconf_key;
 
-        new_binding->previous_key.keysym = new_binding->key.keysym;
-        new_binding->previous_key.state = new_binding->key.state;
-        new_binding->previous_key.keycode = new_binding->key.keycode;
-
         if (parse_binding (new_binding)) {
                 if (!tmp_elem)
                         manager->priv->binding_list = g_slist_prepend (manager->priv->binding_list, new_binding);
@@ -225,6 +224,7 @@
                 g_free (new_binding->binding_str);
                 g_free (new_binding->action);
                 g_free (new_binding->gconf_key);
+                g_free (new_binding->previous_key.keycodes);
                 g_free (new_binding);
 
                 if (tmp_elem)
@@ -236,6 +236,40 @@
 }
 
 static gboolean
+same_keycode (const Key *key, const Key *other)
+{
+        if (key->keycodes != NULL && other->keycodes != NULL) {
+                guint *c;
+
+                for (c = key->keycodes; *c; ++c) {
+                        if (key_uses_keycode (other, *c))
+                                return TRUE;
+                }
+        }
+        return FALSE;
+}
+
+static gboolean
+same_key (const Key *key, const Key *other)
+{
+        if (key->state == other->state) {
+                if (key->keycodes != NULL && other->keycodes != NULL) {
+                        guint *c1, *c2;
+
+                        for (c1 = key->keycodes, c2 = other->keycodes;
+                             *c1 || *c2; ++c1, ++c2) {
+                                     if (*c1 != *c2)
+                                        return FALSE;
+                        }
+                }
+
+                return TRUE;
+        }
+
+        return FALSE;
+}
+
+static gboolean
 key_already_used (GsdKeybindingsManager *manager,
                   Binding               *binding)
 {
@@ -244,7 +278,8 @@
         for (li = manager->priv->binding_list; li != NULL; li = li->next) {
                 Binding *tmp_binding =  (Binding*) li->data;
 
-                if (tmp_binding != binding &&  tmp_binding->key.keycode == binding->key.keycode &&
+                if (tmp_binding != binding &&
+                    same_keycode (&tmp_binding->key, &binding->key) &&
                     tmp_binding->key.state == binding->key.state) {
                         return TRUE;
                 }
@@ -262,29 +297,34 @@
         gdk_error_trap_push ();
 
         /* Now check for changes and grab new key if not already used */
-        for (li = manager->priv->binding_list ; li != NULL; li = li->next) {
+        for (li = manager->priv->binding_list; li != NULL; li = li->next) {
                 Binding *binding = (Binding *) li->data;
 
 		if (manager->priv->allowed_keys != NULL &&
-                    !g_slist_find_custom (manager->priv->allowed_keys, 
-                                          binding->gconf_key, 
-                                          g_strcmp0)) {
+                    !g_slist_find_custom (manager->priv->allowed_keys,
+                                          binding->gconf_key,
+                                          (GCompareFunc) g_strcmp0)) {
                         continue;
 		}
 
-                if (binding->previous_key.keycode != binding->key.keycode ||
-                    binding->previous_key.state != binding->key.state) {
+                if (!same_key (&binding->previous_key, &binding->key)) {
                         /* Ungrab key if it changed and not clashing with previously set binding */
-                        if (! key_already_used (manager, binding)) {
+                        if (!key_already_used (manager, binding)) {
+                                gint i;
+
                                 need_flush = TRUE;
-                                if (binding->previous_key.keycode) {
+                                if (binding->previous_key.keycodes) {
                                         grab_key_unsafe (&binding->previous_key, FALSE, manager->priv->screens);
                                 }
                                 grab_key_unsafe (&binding->key, TRUE, manager->priv->screens);
 
                                 binding->previous_key.keysym = binding->key.keysym;
                                 binding->previous_key.state = binding->key.state;
-                                binding->previous_key.keycode = binding->key.keycode;
+                                g_free (binding->previous_key.keycodes);
+                                for (i = 0; binding->key.keycodes[i]; ++i);
+                                binding->previous_key.keycodes = g_new0 (guint, i);
+                                for (i = 0; binding->key.keycodes[i]; ++i)
+                                        binding->previous_key.keycodes[i] = binding->key.keycodes[i];
                         } else
                                 g_warning ("Key binding (%s) is already in use", binding->binding_str);
                 }
@@ -448,7 +488,7 @@
         if (strcmp (gconf_entry_get_key (entry), ALLOWED_KEYS_KEY) == 0) {
                 g_slist_foreach (manager->priv->allowed_keys, (GFunc)g_free, NULL);
                 g_slist_free (manager->priv->allowed_keys);
-                manager->priv->allowed_keys = gconf_client_get_list (client, 
+                manager->priv->allowed_keys = gconf_client_get_list (client,
                                                                      ALLOWED_KEYS_KEY,
                                                                      GCONF_VALUE_STRING,
                                                                      NULL);
@@ -497,7 +537,7 @@
 
         client = gconf_client_get_default ();
 
-        manager->priv->allowed_keys = gconf_client_get_list (client, 
+        manager->priv->allowed_keys = gconf_client_get_list (client,
                                                              ALLOWED_KEYS_KEY,
                                                              GCONF_VALUE_STRING,
                                                              NULL);
@@ -564,6 +604,8 @@
                 g_free (b->binding_str);
                 g_free (b->action);
                 g_free (b->gconf_key);
+                g_free (b->previous_key.keycodes);
+                g_free (b->key.keycodes);
                 g_free (b);
         }
         g_slist_free (p->binding_list);

Modified: trunk/plugins/media-keys/gsd-media-keys-manager.c
==============================================================================
--- trunk/plugins/media-keys/gsd-media-keys-manager.c	(original)
+++ trunk/plugins/media-keys/gsd-media-keys-manager.c	Mon Nov 24 20:48:15 2008
@@ -305,8 +305,7 @@
                         }
 
                         key = g_new0 (Key, 1);
-                        if (egg_accelerator_parse_virtual (tmp, &key->keysym, &key->keycode, &key->state) == FALSE
-                            || key->keycode == 0) {
+                        if (!egg_accelerator_parse_virtual (tmp, &key->keysym, &key->keycodes, &key->state)) {
                                 g_free (tmp);
                                 g_free (key);
                                 break;
@@ -361,17 +360,8 @@
                 }
 
                 key = g_new0 (Key, 1);
-                if (!egg_accelerator_parse_virtual (tmp, &key->keysym, &key->keycode, &key->state)
-                    || key->keycode == 0) {
+                if (!egg_accelerator_parse_virtual (tmp, &key->keysym, &key->keycodes, &key->state)) {
                         g_debug ("Unable to parse: '%s'", tmp);
-
-                        g_free (tmp);
-                        g_free (key);
-                        continue;
-                }
-                /* avoid grabbing all the keyboard when KeyCode cannot be retrieved */
-                if (key->keycode == AnyKey)  {
-                        g_warning ("The shortcut key \"%s\" cannot be found on the current system, ignoring the binding", tmp);
                         g_free (tmp);
                         g_free (key);
                         continue;
@@ -1027,8 +1017,11 @@
         }
 
         for (i = 0; i < HANDLED_KEYS; ++i) {
-                g_free (keys[i].key);
-                keys[i].key = NULL;
+                if (keys[i].key) {
+                        g_free (keys[i].key->keycodes);
+                        g_free (keys[i].key);
+                        keys[i].key = NULL;
+                }
         }
 
         if (priv->volume) {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]