summaryrefslogtreecommitdiff
path: root/gdk
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2004-11-29 14:25:22 +0000
committerMatthias Clasen <matthiasc@src.gnome.org>2004-11-29 14:25:22 +0000
commitc61b0e4a07d4a4147ba9d57fe0b04d95c8bea84c (patch)
tree8216368a7f44e9692d241bef175105bda1401e8e /gdk
parente08caa5bae054c3b1d528e61b390a6f1b129f791 (diff)
downloadgdk-pixbuf-c61b0e4a07d4a4147ba9d57fe0b04d95c8bea84c.tar.gz
Determine the direction of XKB groups from their content, not by looking
2004-11-29 Matthias Clasen <mclasen@redhat.com> Determine the direction of XKB groups from their content, not by looking for hardcoded keymap names. (#116626, patch by Behdad Esfahbod, based on an earlier patch by Ilya Konstantinov) * gdk/x11/gdkkeys-x11.c (struct _GdkKeymapX11): Cache directions for XKB groups. (get_direction): Determine direction of group by looking at directions of keysyms. (update_direction): Maintain the cache of group directions. (gdk_keymap_get_direction): Use update_direction().
Diffstat (limited to 'gdk')
-rw-r--r--gdk/x11/gdkkeys-x11.c187
1 files changed, 149 insertions, 38 deletions
diff --git a/gdk/x11/gdkkeys-x11.c b/gdk/x11/gdkkeys-x11.c
index 29571ec03..957d0bf2f 100644
--- a/gdk/x11/gdkkeys-x11.c
+++ b/gdk/x11/gdkkeys-x11.c
@@ -59,10 +59,19 @@ typedef struct _GdkKeymapX11 GdkKeymapX11;
#define GDK_KEYMAP_X11(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_KEYMAP_X11, GdkKeymapX11))
#define GDK_IS_KEYMAP_X11(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_KEYMAP_X11))
+typedef struct _DirectionCacheEntry DirectionCacheEntry;
+
+struct _DirectionCacheEntry
+{
+ guint serial;
+ Atom group_atom;
+ PangoDirection direction;
+};
+
struct _GdkKeymapX11
{
GdkKeymap parent_instance;
-
+
gint min_keycode;
gint max_keycode;
KeySym* keymap;
@@ -75,9 +84,18 @@ struct _GdkKeymapX11
PangoDirection current_direction;
gboolean have_direction;
guint current_serial;
-
+
#ifdef HAVE_XKB
XkbDescPtr xkb_desc;
+ /* We cache the directions */
+ Atom current_group_atom;
+ guint current_cache_serial;
+ /* A cache of size four should be more than enough, people usually
+ * have two groups around, and the xkb limit is four. It still
+ * works correct for more than four groups. It's just the
+ * cache.
+ */
+ DirectionCacheEntry group_direction_cache[4];
#endif
};
@@ -130,12 +148,14 @@ gdk_keymap_x11_init (GdkKeymapX11 *keymap)
keymap->group_switch_mask = 0;
keymap->lock_keysym = GDK_Caps_Lock;
keymap->have_direction = FALSE;
-
+ keymap->current_serial = 0;
+
#ifdef HAVE_XKB
keymap->xkb_desc = NULL;
+ keymap->current_group_atom = 0;
+ keymap->current_cache_serial = 0;
#endif
- keymap->current_serial = 0;
}
static inline void
@@ -211,14 +231,17 @@ gdk_keymap_get_for_display (GdkDisplay *display)
* otherwise we lose a whole group of keys
*/
#define KEYSYM_INDEX(keymap_impl, group, level) \
- (2 * ((group) % (int)((keymap_impl->keysyms_per_keycode + 1) / 2)) + (level))
+ (2 * ((group) % (gint)((keymap_impl->keysyms_per_keycode + 1) / 2)) + (level))
#define KEYSYM_IS_KEYPAD(s) (((s) >= 0xff80 && (s) <= 0xffbd) || \
((s) >= 0x11000000 && (s) <= 0x1100ffff))
-static int
-get_symbol (const KeySym *syms, GdkKeymapX11 *keymap_x11, int group, int level)
+static gint
+get_symbol (const KeySym *syms,
+ GdkKeymapX11 *keymap_x11,
+ gint group,
+ gint level)
{
- int index;
+ gint index;
index = KEYSYM_INDEX(keymap_x11, group, level);
if (index > keymap_x11->keysyms_per_keycode)
@@ -397,7 +420,7 @@ get_keymap (GdkKeymapX11 *keymap_x11)
static GdkKeymap *
get_effective_keymap (GdkKeymap *keymap,
- const char *function)
+ const char *function)
{
if (!keymap)
{
@@ -412,34 +435,132 @@ get_effective_keymap (GdkKeymap *keymap,
#if HAVE_XKB
static PangoDirection
-get_direction (GdkKeymapX11 *keymap_x11)
+get_direction (XkbDescRec *xkb,
+ gint group)
+{
+ gint code;
+
+ gint rtl_minus_ltr = 0; /* total number of RTL keysyms minus LTR ones */
+
+ for (code = xkb->min_key_code; code <= xkb->max_key_code; code++)
+ {
+ gint width = XkbKeyGroupWidth (xkb, code, group);
+ gint level;
+ for (level = 0; level < width; level++)
+ {
+ KeySym sym = XkbKeySymEntry (xkb, code, level, group);
+ PangoDirection dir = pango_unichar_direction (gdk_keyval_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;
+ else
+ return PANGO_DIRECTION_LTR;
+}
+
+static void
+update_direction (GdkKeymapX11 *keymap_x11)
{
XkbDescRec *xkb = get_xkb (keymap_x11);
- const char *name;
XkbStateRec state_rec;
- PangoDirection result;
-
GdkDisplay *display = GDK_KEYMAP (keymap_x11)->display;
+ gint group;
+ Atom group_atom;
XkbGetState (GDK_DISPLAY_XDISPLAY (display), XkbUseCoreKbd, &state_rec);
-
- if (xkb->names->groups[state_rec.locked_group] == None)
- result = PANGO_DIRECTION_LTR;
- else
+ group = XkbGroupLock (&state_rec);
+ group_atom = xkb->names->groups[group];
+
+ /* a group change? */
+ if (!keymap_x11->have_direction || keymap_x11->current_group_atom != group_atom)
{
- name = gdk_x11_get_xatom_name_for_display (display, xkb->names->groups[state_rec.locked_group]);
+ gboolean cache_hit = FALSE;
+ DirectionCacheEntry *cache = keymap_x11->group_direction_cache;
- if (g_ascii_strcasecmp (name, "arabic") == 0 ||
- g_ascii_strcasecmp (name, "hebrew") == 0 ||
- g_ascii_strcasecmp (name, "israelian") == 0)
- result = PANGO_DIRECTION_RTL;
+ PangoDirection direction = PANGO_DIRECTION_NEUTRAL;
+ gint i;
+
+ if (keymap_x11->have_direction)
+ {
+ /* lookup in 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++; /* freshen */
+ direction = cache[i].direction;
+ group_atom = cache[i].group_atom;
+ break;
+ }
+ }
+ }
else
- result = PANGO_DIRECTION_LTR;
+ {
+ /* initialize cache */
+ for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++)
+ {
+ cache[i].group_atom = 0;
+ cache[i].serial = keymap_x11->current_cache_serial;
+ }
+ keymap_x11->current_cache_serial++;
+ }
+
+ /* insert in cache */
+ if (!cache_hit)
+ {
+ gint oldest = 0;
+
+ direction = get_direction (xkb, group);
+
+ /* remove 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++;
+ }
+
+ keymap_x11->current_group_atom = group_atom;
+
+ keymap_x11->have_direction = TRUE;
+ keymap_x11->current_direction = direction;
}
-
- return result;
}
+static void
+_gdk_keymap_direction_changed (GdkKeymapX11 *keymap_x11)
+{
+ gboolean had_direction;
+ PangoDirection direction;
+
+ had_direction = keymap_x11->have_direction;
+ direction = keymap_x11->current_direction;
+
+ update_direction (keymap_x11);
+
+ if (!had_direction || direction != keymap_x11->current_direction)
+ g_signal_emit_by_name (keymap_x11, "direction_changed");
+}
+
+
void
_gdk_keymap_state_changed (GdkDisplay *display)
{
@@ -449,14 +570,7 @@ _gdk_keymap_state_changed (GdkDisplay *display)
{
GdkKeymapX11 *keymap_x11 = GDK_KEYMAP_X11 (display_x11->keymap);
- PangoDirection new_direction = get_direction (keymap_x11);
-
- if (!keymap_x11->have_direction || new_direction != keymap_x11->current_direction)
- {
- keymap_x11->have_direction = TRUE;
- keymap_x11->current_direction = new_direction;
- g_signal_emit_by_name (keymap_x11, "direction_changed");
- }
+ _gdk_keymap_direction_changed (keymap_x11);
}
}
@@ -484,16 +598,13 @@ gdk_keymap_get_direction (GdkKeymap *keymap)
GdkKeymapX11 *keymap_x11 = GDK_KEYMAP_X11 (keymap);
if (!keymap_x11->have_direction)
- {
- keymap_x11->current_direction = get_direction (keymap_x11);
- keymap_x11->have_direction = TRUE;
- }
+ update_direction (keymap_x11);
return keymap_x11->current_direction;
}
else
#endif /* HAVE_XKB */
- return PANGO_DIRECTION_LTR;
+ return PANGO_DIRECTION_NEUTRAL;
}
/**