[clutter/clutter-1.18] x11: Add keymap direction query



commit 3209129d6b9031fc4beb4d0c5c6b8a8c05286941
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Mon Mar 3 23:23:12 2014 +0000

    x11: Add keymap direction query
    
    We should use the Xkb API to query the direction of the key map,
    depending on the group. To get a valid result we need to go over
    the Unicode equivalents of the key symbols for each group, so we
    should cache the result.
    
    The code used to query and cache the key map direction is taken
    from GDK.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=705779

 clutter/x11/clutter-backend-x11.c |   13 +++
 clutter/x11/clutter-keymap-x11.c  |  164 ++++++++++++++++++++++++++++++++++++-
 clutter/x11/clutter-keymap-x11.h  |    3 +
 3 files changed, 179 insertions(+), 1 deletions(-)
---
diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c
index d6f0a01..54845cb 100644
--- a/clutter/x11/clutter-backend-x11.c
+++ b/clutter/x11/clutter-backend-x11.c
@@ -774,6 +774,17 @@ clutter_backend_x11_create_stage (ClutterBackend  *backend,
   return stage;
 }
 
+static PangoDirection
+clutter_backend_x11_get_keymap_direction (ClutterBackend *backend)
+{
+  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
+
+  if (G_UNLIKELY (backend_x11->keymap == NULL))
+    return PANGO_DIRECTION_NEUTRAL;
+
+  return _clutter_keymap_x11_get_direction (backend_x11->keymap);
+}
+
 static void
 clutter_backend_x11_class_init (ClutterBackendX11Class *klass)
 {
@@ -797,6 +808,8 @@ clutter_backend_x11_class_init (ClutterBackendX11Class *klass)
   backend_class->get_renderer = clutter_backend_x11_get_renderer;
   backend_class->get_display = clutter_backend_x11_get_display;
   backend_class->create_stage = clutter_backend_x11_create_stage;
+
+  backend_class->get_keymap_direction = clutter_backend_x11_get_keymap_direction;
 }
 
 static void
diff --git a/clutter/x11/clutter-keymap-x11.c b/clutter/x11/clutter-keymap-x11.c
index e5de3ee..2e9bae4 100644
--- a/clutter/x11/clutter-keymap-x11.c
+++ b/clutter/x11/clutter-keymap-x11.c
@@ -37,6 +37,14 @@
 #endif
 
 typedef struct _ClutterKeymapX11Class   ClutterKeymapX11Class;
+typedef struct _DirectionCacheEntry     DirectionCacheEntry;
+
+struct _DirectionCacheEntry
+{
+  guint serial;
+  Atom group_atom;
+  PangoDirection direction;
+};
 
 struct _ClutterKeymapX11
 {
@@ -52,14 +60,20 @@ struct _ClutterKeymapX11
   ClutterModifierType num_lock_mask;
   ClutterModifierType scroll_lock_mask;
 
+  PangoDirection current_direction;
+
 #ifdef HAVE_XKB
   XkbDescPtr xkb_desc;
   int xkb_event_base;
   guint xkb_map_serial;
+  Atom current_group_atom;
+  guint current_cache_serial;
+  DirectionCacheEntry group_direction_cache[4];
 #endif
 
   guint caps_lock_state : 1;
   guint num_lock_state  : 1;
+  guint has_direction   : 1;
 };
 
 struct _ClutterKeymapX11Class
@@ -217,6 +231,128 @@ update_locked_mods (ClutterKeymapX11 *keymap_x11,
 }
 #endif /* HAVE_XKB */
 
+#ifdef HAVE_XKB
+/* the code to retrieve the keymap direction and cache it
+ * is taken from GDK:
+ *      gdk/x11/gdkkeys-x11.c
+ */
+static PangoDirection
+get_direction (XkbDescPtr xkb,
+               int        group)
+{
+  int rtl_minus_ltr = 0; /* total number of RTL keysyms minus LTR ones */
+  int code;
+
+  for (code = xkb->min_key_code;
+       code <= xkb->max_key_code;
+       code += 1)
+    {
+      int level = 0;
+      KeySym sym = XkbKeySymEntry (xkb, code, level, group);
+      PangoDirection dir = pango_unichar_direction (clutter_keysym_to_unicode (sym));
+
+      switch (dir)
+        {
+        case PANGO_DIRECTION_RTL:
+          rtl_minus_ltr++;
+          break;
+
+        case PANGO_DIRECTION_LTR:
+          rtl_minus_ltr--;
+          break;
+
+        default:
+          break;
+        }
+    }
+
+  if (rtl_minus_ltr > 0)
+    return PANGO_DIRECTION_RTL;
+
+  return PANGO_DIRECTION_LTR;
+}
+
+static PangoDirection
+get_direction_from_cache (ClutterKeymapX11 *keymap_x11,
+                          XkbDescPtr        xkb,
+                          int               group)
+{
+  Atom group_atom = xkb->names->groups[group];
+  gboolean cache_hit = FALSE;
+  DirectionCacheEntry *cache = keymap_x11->group_direction_cache;
+  PangoDirection direction = PANGO_DIRECTION_NEUTRAL;
+  int i;
+
+  if (keymap_x11->has_direction)
+    {
+      /* look up in the cache */
+      for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++)
+        {
+          if (cache[i].group_atom == group_atom)
+            {
+              cache_hit = TRUE;
+              cache[i].serial = keymap_x11->current_cache_serial++;
+              direction = cache[i].direction;
+              group_atom = cache[i].group_atom;
+              break;
+            }
+        }
+    }
+  else
+    {
+      /* initialize the cache */
+      for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++)
+        {
+          cache[i].group_atom = 0;
+          cache[i].direction = PANGO_DIRECTION_NEUTRAL;
+          cache[i].serial = keymap_x11->current_cache_serial;
+        }
+
+      keymap_x11->current_cache_serial += 1;
+    }
+
+  /* insert the new entry in the cache */
+  if (!cache_hit)
+    {
+      int oldest = 0;
+
+      direction = get_direction (xkb, group);
+
+      /* replace the oldest entry */
+      for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++)
+        {
+          if (cache[i].serial < cache[oldest].serial)
+            oldest = i;
+        }
+
+      cache[oldest].group_atom = group_atom;
+      cache[oldest].direction = direction;
+      cache[oldest].serial = keymap_x11->current_cache_serial++;
+    }
+
+  return direction;
+}
+#endif /* HAVE_XKB */
+
+static void
+update_direction (ClutterKeymapX11 *keymap_x11,
+                  int               group)
+{
+#ifdef HAVE_XKB
+  XkbDescPtr xkb = get_xkb (keymap_x11);
+  Atom group_atom;
+
+  group_atom = xkb->names->groups[group];
+
+  if (!keymap_x11->has_direction || keymap_x11->current_group_atom != group_atom)
+    {
+      keymap_x11->current_direction = get_direction_from_cache (keymap_x11, xkb, group);
+      keymap_x11->current_group_atom = group_atom;
+      keymap_x11->has_direction = TRUE;
+    }
+#endif /* HAVE_XKB */
+}
+
 static void
 clutter_keymap_x11_constructed (GObject *gobject)
 {
@@ -332,6 +468,7 @@ clutter_keymap_x11_class_init (ClutterKeymapX11Class *klass)
 static void
 clutter_keymap_x11_init (ClutterKeymapX11 *keymap)
 {
+  keymap->current_direction = PANGO_DIRECTION_NEUTRAL;
 }
 
 static ClutterTranslateReturn
@@ -360,7 +497,8 @@ clutter_keymap_x11_translate_event (ClutterEventTranslator *translator,
       switch (xkb_event->any.xkb_type)
         {
         case XkbStateNotify:
-          CLUTTER_NOTE (EVENT, "Updating locked modifiers");
+          CLUTTER_NOTE (EVENT, "Updating keyboard state");
+          update_direction (keymap_x11, XkbStateGroup (&xkb_event->state));
           update_locked_mods (keymap_x11, xkb_event->state.locked_mods);
           retval = CLUTTER_TRANSLATE_REMOVE;
           break;
@@ -503,3 +641,27 @@ _clutter_keymap_x11_get_is_modifier (ClutterKeymapX11 *keymap,
 
   return FALSE;
 }
+
+PangoDirection
+_clutter_keymap_x11_get_direction (ClutterKeymapX11 *keymap)
+{
+  g_return_val_if_fail (CLUTTER_IS_KEYMAP_X11 (keymap), PANGO_DIRECTION_NEUTRAL);
+
+#ifdef HAVE_XKB
+  if (CLUTTER_BACKEND_X11 (keymap->backend)->use_xkb)
+    {
+      if (!keymap->has_direction)
+        {
+          Display *xdisplay = CLUTTER_BACKEND_X11 (keymap->backend)->xdpy;
+          XkbStateRec state_rec;
+
+          XkbGetState (xdisplay, XkbUseCoreKbd, &state_rec);
+          update_direction (keymap, XkbStateGroup (&state_rec));
+        }
+
+      return keymap->current_direction;
+    }
+  else
+#endif
+    return PANGO_DIRECTION_NEUTRAL;
+}
diff --git a/clutter/x11/clutter-keymap-x11.h b/clutter/x11/clutter-keymap-x11.h
index 3032785..ad673a2 100644
--- a/clutter/x11/clutter-keymap-x11.h
+++ b/clutter/x11/clutter-keymap-x11.h
@@ -25,6 +25,7 @@
 #define __CLUTTER_KEYMAP_X11_H__
 
 #include <glib-object.h>
+#include <pango/pango.h>
 #include <clutter/clutter-event.h>
 
 G_BEGIN_DECLS
@@ -48,6 +49,8 @@ gint     _clutter_keymap_x11_translate_key_state (ClutterKeymapX11    *keymap,
 gboolean _clutter_keymap_x11_get_is_modifier     (ClutterKeymapX11    *keymap,
                                                   gint                 keycode);
 
+PangoDirection _clutter_keymap_x11_get_direction (ClutterKeymapX11    *keymap);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_KEYMAP_X11_H__ */


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