[gtk+/gdk-backend-wayland: 6/10] Implement GdkKeymap using libxkbcommon



commit 7d29070faf4dadb8949b6abbc5e1f9b1f806a146
Author: Kristian Høgsberg <krh bitplanet net>
Date:   Fri Jan 7 12:10:41 2011 -0500

    Implement GdkKeymap using libxkbcommon

 gdk/wayland/gdkdevice-wayland.h        |    3 +-
 gdk/wayland/gdkdevicemanager-wayland.c |   29 +++--
 gdk/wayland/gdkdisplay-wayland.c       |    5 +-
 gdk/wayland/gdkkeys-wayland.c          |  218 +++++++++++++++++++++++++++++---
 gdk/wayland/gdkprivate-wayland.h       |    4 +-
 5 files changed, 218 insertions(+), 41 deletions(-)
---
diff --git a/gdk/wayland/gdkdevice-wayland.h b/gdk/wayland/gdkdevice-wayland.h
index 88fac43..a8d4dd9 100644
--- a/gdk/wayland/gdkdevice-wayland.h
+++ b/gdk/wayland/gdkdevice-wayland.h
@@ -20,8 +20,8 @@
 #ifndef __GDK_DEVICE_CORE_H__
 #define __GDK_DEVICE_CORE_H__
 
+#include <stdint.h>
 #include <gdk/gdkdeviceprivate.h>
-#include <X11/extensions/XKBcommon.h>
 
 G_BEGIN_DECLS
 
@@ -45,7 +45,6 @@ struct _GdkWaylandDevice
   GdkWindow *pointer_focus;
   GdkWindow *keyboard_focus;
   struct wl_input_device *device;
-  struct xkb_desc *xkb;
   int32_t x, y, surface_x, surface_y;
 };
 
diff --git a/gdk/wayland/gdkdevicemanager-wayland.c b/gdk/wayland/gdkdevicemanager-wayland.c
index c432ec7..d1543f9 100644
--- a/gdk/wayland/gdkdevicemanager-wayland.c
+++ b/gdk/wayland/gdkdevicemanager-wayland.c
@@ -28,6 +28,7 @@
 #include "gdkprivate-wayland.h"
 #include "gdkeventsource.h"
 
+#include <X11/extensions/XKBcommon.h>
 
 static void    gdk_device_manager_core_finalize    (GObject *object);
 
@@ -116,6 +117,8 @@ input_handle_key(void *data, struct wl_input_device *input_device,
   GdkWaylandDevice *device = data;
   GdkEvent *event;
   uint32_t code, modifier, level;
+  struct xkb_desc *xkb;
+  GdkKeymap *keymap;
 
   event = gdk_event_new (state ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
   event->key.window = g_object_ref (device->keyboard_focus);
@@ -125,16 +128,19 @@ input_handle_key(void *data, struct wl_input_device *input_device,
   event->key.group = 0;
   event->key.hardware_keycode = key;
 
-  code = key + device->xkb->min_key_code;
+  keymap = gdk_keymap_get_for_display (device->display);
+  xkb = _gdk_wayland_keymap_get_xkb_desc (keymap);
+
+  code = key + xkb->min_key_code;
 
   level = 0;
   if (device->modifiers & ShiftMask &&
-      XkbKeyGroupWidth(device->xkb, code, 0) > 1)
+      XkbKeyGroupWidth(xkb, code, 0) > 1)
     level = 1;
 
-  event->key.keyval = XkbKeySymEntry(device->xkb, code, level, 0);
+  event->key.keyval = XkbKeySymEntry(xkb, code, level, 0);
 
-  modifier = device->xkb->map->modmap[code];
+  modifier = xkb->map->modmap[code];
   if (state)
     device->modifiers |= modifier;
   else
@@ -269,10 +275,15 @@ static void
 update_modifiers(GdkWaylandDevice *device, struct wl_array *keys)
 {
   uint32_t *k, *end;
+  GdkKeymap *keymap;
+  struct xkb_desc *xkb;
+
+  keymap = gdk_keymap_get_for_display (device->display);
+  xkb = _gdk_wayland_keymap_get_xkb_desc (keymap);
 
   end = keys->data + keys->size;
   for (k = keys->data; k < end; k++)
-    device->modifiers |= device->xkb->map->modmap[*k];
+    device->modifiers |= xkb->map->modmap[*k];
 
   fprintf (stderr, "modifiers: 0x%x\n", device->modifiers);
 }
@@ -335,7 +346,6 @@ gdk_device_manager_core_add_device (GdkDeviceManager *device_manager,
   GdkDisplay *display;
   GdkDeviceManagerCore *device_manager_core =
     GDK_DEVICE_MANAGER_CORE(device_manager);
-  struct xkb_rule_names names;
   GdkWaylandDevice *device;
 
   device = g_new0 (GdkWaylandDevice, 1);
@@ -366,13 +376,6 @@ gdk_device_manager_core_add_device (GdkDeviceManager *device_manager,
   GDK_DEVICE_CORE (device->keyboard)->device = device;
   device->device = wl_device;
 
-  names.rules = "evdev";
-  names.model = "pc105";
-  names.layout = "us";
-  names.variant = "";
-  names.options = "";
-  device->xkb = xkb_compile_keymap_from_rules(&names);
-
   wl_input_device_add_listener(device->device,
 			       &input_device_listener, device);
 
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index fefa1f5..34740d1 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -709,10 +709,7 @@ gdk_wayland_display_get_keymap (GdkDisplay *display)
   display_wayland = GDK_DISPLAY_WAYLAND (display);
 
   if (!display_wayland->keymap)
-    display_wayland->keymap =
-      g_object_new (_gdk_wayland_keymap_get_type(), NULL);
-
-  display_wayland->keymap->display = display;
+    display_wayland->keymap = _gdk_wayland_keymap_new (display);
 
   return display_wayland->keymap;
 }
diff --git a/gdk/wayland/gdkkeys-wayland.c b/gdk/wayland/gdkkeys-wayland.c
index 87b1398..f18bf0e 100644
--- a/gdk/wayland/gdkkeys-wayland.c
+++ b/gdk/wayland/gdkkeys-wayland.c
@@ -49,6 +49,7 @@ typedef struct _GdkWaylandKeymapClass     GdkWaylandKeymapClass;
 struct _GdkWaylandKeymap
 {
   GdkKeymap parent_instance;
+  struct xkb_desc *xkb;
 };
 
 struct _GdkWaylandKeymapClass
@@ -57,7 +58,7 @@ struct _GdkWaylandKeymapClass
 };
 
 #define GDK_TYPE_WAYLAND_KEYMAP          (_gdk_wayland_keymap_get_type ())
-#define GDK_WAYLAND_KEYMAP(object)       (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_KEYMAP, GdkWaylandKeyMap))
+#define GDK_WAYLAND_KEYMAP(object)       (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_KEYMAP, GdkWaylandKeymap))
 #define GDK_IS_WAYLAND_KEYMAP(object)    (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_KEYMAP))
 
 G_DEFINE_TYPE (GdkWaylandKeymap, _gdk_wayland_keymap, GDK_TYPE_KEYMAP)
@@ -94,39 +95,190 @@ gdk_wayland_keymap_get_num_lock_state (GdkKeymap *keymap)
 
 static gboolean
 gdk_wayland_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
-				       guint          keyval,
-				       GdkKeymapKey **keys,
-				       gint          *n_keys)
+					   guint          keyval,
+					   GdkKeymapKey **keys,
+					   gint          *n_keys)
 {
-  return FALSE;
+  GArray *retval;
+  uint32_t keycode;
+  struct xkb_desc *xkb;
+
+  xkb = GDK_WAYLAND_KEYMAP (keymap)->xkb;
+  keycode = xkb->min_key_code;
+
+  retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
+
+  for (keycode = xkb->min_key_code; keycode <= xkb->max_key_code; keycode++)
+    {
+      gint max_shift_levels = XkbKeyGroupsWidth (xkb, keycode);
+
+      gint group = 0;
+      gint level = 0;
+      gint total_syms = XkbKeyNumSyms (xkb, keycode);
+      gint i = 0;
+      uint32_t *entry;
+
+      /* entry is an array with all syms for group 0, all
+       * syms for group 1, etc. and for each group the
+       * shift level syms are in order
+       */
+      entry = XkbKeySymsPtr (xkb, keycode);
+
+      for (i = 0; i < total_syms; i++)
+	{
+	  /* check out our cool loop invariant */
+	  g_assert (i == (group * max_shift_levels + level));
+
+	  if (entry[i] == keyval)
+	    {
+	      /* Found a match */
+	      GdkKeymapKey key;
+
+	      key.keycode = keycode;
+	      key.group = group;
+	      key.level = level;
+
+	      g_array_append_val (retval, key);
+
+	      g_assert (XkbKeySymEntry (xkb, keycode, level, group) ==
+			keyval);
+	    }
+
+	  level++;
+
+	  if (level == max_shift_levels)
+	    {
+	      level = 0;
+	      group++;
+	    }
+	}
+    }
+
+  *n_keys = retval->len;
+  *keys = (GdkKeymapKey *) g_array_free (retval, FALSE);
+
+  return *n_keys > 0;
 }
 
 static gboolean
 gdk_wayland_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
-					guint          hardware_keycode,
-					GdkKeymapKey **keys,
-					guint        **keyvals,
-					gint          *n_entries)
+					    guint          hardware_keycode,
+					    GdkKeymapKey **keys,
+					    guint        **keyvals,
+					    gint          *n_entries)
 {
-  return FALSE;
+  GArray *key_array;
+  GArray *keyval_array;
+  struct xkb_desc *xkb;
+  gint max_shift_levels;
+  gint group = 0;
+  gint level = 0;
+  gint total_syms;
+  gint i;
+  uint32_t *entry;
+
+  g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
+  g_return_val_if_fail (n_entries != NULL, FALSE);
+
+  xkb = GDK_WAYLAND_KEYMAP (keymap)->xkb;
+
+  if (hardware_keycode < xkb->min_key_code ||
+      hardware_keycode > xkb->max_key_code)
+    {
+      if (keys)
+	*keys = NULL;
+      if (keyvals)
+	*keyvals = NULL;
+
+      *n_entries = 0;
+      return FALSE;
+    }
+
+  if (keys)
+    key_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
+  else
+    key_array = NULL;
+
+  if (keyvals)
+    keyval_array = g_array_new (FALSE, FALSE, sizeof (guint));
+  else
+    keyval_array = NULL;
+
+  /* See sec 15.3.4 in XKB docs */
+  max_shift_levels = XkbKeyGroupsWidth (xkb, hardware_keycode);
+  total_syms = XkbKeyNumSyms (xkb, hardware_keycode);
+
+  /* entry is an array with all syms for group 0, all
+   * syms for group 1, etc. and for each group the
+   * shift level syms are in order
+   */
+  entry = XkbKeySymsPtr (xkb, hardware_keycode);
+
+  for (i = 0; i < total_syms; i++)
+    {
+      /* check out our cool loop invariant */
+      g_assert (i == (group * max_shift_levels + level));
+
+      if (key_array)
+	{
+	  GdkKeymapKey key;
+
+	  key.keycode = hardware_keycode;
+	  key.group = group;
+	  key.level = level;
+
+	  g_array_append_val (key_array, key);
+	}
+
+      if (keyval_array)
+	g_array_append_val (keyval_array, entry[i]);
+
+      ++level;
+
+      if (level == max_shift_levels)
+	{
+	  level = 0;
+	  ++group;
+	}
+    }
+
+  *n_entries = 0;
+
+  if (keys)
+    {
+      *n_entries = key_array->len;
+      *keys = (GdkKeymapKey*) g_array_free (key_array, FALSE);
+    }
+
+  if (keyvals)
+    {
+      *n_entries = keyval_array->len;
+      *keyvals = (guint*) g_array_free (keyval_array, FALSE);
+    }
+
+  return *n_entries > 0;
 }
 
 static guint
 gdk_wayland_keymap_lookup_key (GdkKeymap          *keymap,
-			   const GdkKeymapKey *key)
+			       const GdkKeymapKey *key)
 {
-  return 0;
+  struct xkb_desc *xkb;
+
+  xkb = GDK_WAYLAND_KEYMAP (keymap)->xkb;
+
+  return XkbKeySymEntry (xkb, key->keycode, key->level, key->group);
 }
 
 static gboolean
 gdk_wayland_keymap_translate_keyboard_state (GdkKeymap       *keymap,
-					 guint            hardware_keycode,
-					 GdkModifierType  state,
-					 gint             group,
-					 guint           *keyval,
-					 gint            *effective_group,
-					 gint            *level,
-					 GdkModifierType *consumed_modifiers)
+					     guint            hardware_keycode,
+					     GdkModifierType  state,
+					     gint             group,
+					     guint           *keyval,
+					     gint            *effective_group,
+					     gint            *level,
+					     GdkModifierType *consumed_modifiers)
 {
   return FALSE;
 }
@@ -134,13 +286,13 @@ gdk_wayland_keymap_translate_keyboard_state (GdkKeymap       *keymap,
 
 static void
 gdk_wayland_keymap_add_virtual_modifiers (GdkKeymap       *keymap,
-				      GdkModifierType *state)
+					  GdkModifierType *state)
 {
 }
 
 static gboolean
 gdk_wayland_keymap_map_virtual_modifiers (GdkKeymap       *keymap,
-				      GdkModifierType *state)
+					  GdkModifierType *state)
 {
   return FALSE;
 }
@@ -169,3 +321,27 @@ static void
 _gdk_wayland_keymap_init (GdkWaylandKeymap *keymap)
 {
 }
+
+GdkKeymap *
+_gdk_wayland_keymap_new (GdkDisplay *display)
+{
+  GdkWaylandKeymap *keymap;
+  struct xkb_rule_names names;
+
+  keymap = g_object_new (_gdk_wayland_keymap_get_type(), NULL);
+  GDK_KEYMAP (keymap)->display = display;
+
+  names.rules = "evdev";
+  names.model = "pc105";
+  names.layout = "us";
+  names.variant = "";
+  names.options = "";
+  keymap->xkb = xkb_compile_keymap_from_rules(&names);
+
+  return GDK_KEYMAP (keymap);
+}
+
+struct xkb_desc *_gdk_wayland_keymap_get_xkb_desc (GdkKeymap *keymap)
+{
+  return GDK_WAYLAND_KEYMAP (keymap)->xkb;
+}
diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h
index ef13fea..dcd9fa9 100644
--- a/gdk/wayland/gdkprivate-wayland.h
+++ b/gdk/wayland/gdkprivate-wayland.h
@@ -46,7 +46,9 @@
 #define GDK_WINDOW_IS_WAYLAND(win)    (GDK_IS_WINDOW_IMPL_WAYLAND (((GdkWindow *)win)->impl))
 
 GType      _gdk_wayland_window_get_type            (void);
-GType      _gdk_wayland_keymap_get_type            (void);
+
+GdkKeymap *_gdk_wayland_keymap_new (GdkDisplay *display);
+struct xkb_desc *_gdk_wayland_keymap_get_xkb_desc (GdkKeymap *keymap);
 
 GdkCursor *_gdk_wayland_display_get_cursor_for_type (GdkDisplay    *display,
 						     GdkCursorType  cursor_type);



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