summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@gnome.org>2014-03-03 23:23:12 +0000
committerEmmanuele Bassi <ebassi@gnome.org>2014-03-03 23:42:33 +0000
commit3209129d6b9031fc4beb4d0c5c6b8a8c05286941 (patch)
tree93b8db4365c258e6e2e9c9d2bc27dcc4fa5fb6e5
parenta0003499783d28028dbc4c48e3c673d6b244a20e (diff)
downloadclutter-3209129d6b9031fc4beb4d0c5c6b8a8c05286941.tar.gz
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
-rw-r--r--clutter/x11/clutter-backend-x11.c13
-rw-r--r--clutter/x11/clutter-keymap-x11.c164
-rw-r--r--clutter/x11/clutter-keymap-x11.h3
3 files changed, 179 insertions, 1 deletions
diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c
index d6f0a0163..54845cb64 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 e5de3ee7e..2e9bae423 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 30327852d..ad673a2a7 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__ */