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().
This commit is contained in:
Matthias Clasen 2004-11-29 14:25:22 +00:00 committed by Matthias Clasen
parent e08caa5bae
commit c61b0e4a07
5 changed files with 196 additions and 41 deletions

View File

@ -1,5 +1,16 @@
2004-11-29 Matthias Clasen <mclasen@redhat.com> 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().
* gdk/gdkkeynames.c: Add dead_hook and dead_horn. * gdk/gdkkeynames.c: Add dead_hook and dead_horn.
* gdk/gdkkeysyms.h (GDK_dead_hook, GDK_dead_horn): Define * gdk/gdkkeysyms.h (GDK_dead_hook, GDK_dead_horn): Define

View File

@ -1,5 +1,16 @@
2004-11-29 Matthias Clasen <mclasen@redhat.com> 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().
* gdk/gdkkeynames.c: Add dead_hook and dead_horn. * gdk/gdkkeynames.c: Add dead_hook and dead_horn.
* gdk/gdkkeysyms.h (GDK_dead_hook, GDK_dead_horn): Define * gdk/gdkkeysyms.h (GDK_dead_hook, GDK_dead_horn): Define

View File

@ -1,5 +1,16 @@
2004-11-29 Matthias Clasen <mclasen@redhat.com> 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().
* gdk/gdkkeynames.c: Add dead_hook and dead_horn. * gdk/gdkkeynames.c: Add dead_hook and dead_horn.
* gdk/gdkkeysyms.h (GDK_dead_hook, GDK_dead_horn): Define * gdk/gdkkeysyms.h (GDK_dead_hook, GDK_dead_horn): Define

View File

@ -1,5 +1,16 @@
2004-11-29 Matthias Clasen <mclasen@redhat.com> 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().
* gdk/gdkkeynames.c: Add dead_hook and dead_horn. * gdk/gdkkeynames.c: Add dead_hook and dead_horn.
* gdk/gdkkeysyms.h (GDK_dead_hook, GDK_dead_horn): Define * gdk/gdkkeysyms.h (GDK_dead_hook, GDK_dead_horn): Define

View File

@ -59,6 +59,15 @@ typedef struct _GdkKeymapX11 GdkKeymapX11;
#define GDK_KEYMAP_X11(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_KEYMAP_X11, 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)) #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 struct _GdkKeymapX11
{ {
GdkKeymap parent_instance; GdkKeymap parent_instance;
@ -78,6 +87,15 @@ struct _GdkKeymapX11
#ifdef HAVE_XKB #ifdef HAVE_XKB
XkbDescPtr xkb_desc; 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 #endif
}; };
@ -130,12 +148,14 @@ gdk_keymap_x11_init (GdkKeymapX11 *keymap)
keymap->group_switch_mask = 0; keymap->group_switch_mask = 0;
keymap->lock_keysym = GDK_Caps_Lock; keymap->lock_keysym = GDK_Caps_Lock;
keymap->have_direction = FALSE; keymap->have_direction = FALSE;
keymap->current_serial = 0;
#ifdef HAVE_XKB #ifdef HAVE_XKB
keymap->xkb_desc = NULL; keymap->xkb_desc = NULL;
keymap->current_group_atom = 0;
keymap->current_cache_serial = 0;
#endif #endif
keymap->current_serial = 0;
} }
static inline void static inline void
@ -211,14 +231,17 @@ gdk_keymap_get_for_display (GdkDisplay *display)
* otherwise we lose a whole group of keys * otherwise we lose a whole group of keys
*/ */
#define KEYSYM_INDEX(keymap_impl, group, level) \ #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) || \ #define KEYSYM_IS_KEYPAD(s) (((s) >= 0xff80 && (s) <= 0xffbd) || \
((s) >= 0x11000000 && (s) <= 0x1100ffff)) ((s) >= 0x11000000 && (s) <= 0x1100ffff))
static int static gint
get_symbol (const KeySym *syms, GdkKeymapX11 *keymap_x11, int group, int level) get_symbol (const KeySym *syms,
GdkKeymapX11 *keymap_x11,
gint group,
gint level)
{ {
int index; gint index;
index = KEYSYM_INDEX(keymap_x11, group, level); index = KEYSYM_INDEX(keymap_x11, group, level);
if (index > keymap_x11->keysyms_per_keycode) if (index > keymap_x11->keysyms_per_keycode)
@ -412,34 +435,132 @@ get_effective_keymap (GdkKeymap *keymap,
#if HAVE_XKB #if HAVE_XKB
static PangoDirection 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); XkbDescRec *xkb = get_xkb (keymap_x11);
const char *name;
XkbStateRec state_rec; XkbStateRec state_rec;
PangoDirection result;
GdkDisplay *display = GDK_KEYMAP (keymap_x11)->display; GdkDisplay *display = GDK_KEYMAP (keymap_x11)->display;
gint group;
Atom group_atom;
XkbGetState (GDK_DISPLAY_XDISPLAY (display), XkbUseCoreKbd, &state_rec); XkbGetState (GDK_DISPLAY_XDISPLAY (display), XkbUseCoreKbd, &state_rec);
group = XkbGroupLock (&state_rec);
group_atom = xkb->names->groups[group];
if (xkb->names->groups[state_rec.locked_group] == None) /* a group change? */
result = PANGO_DIRECTION_LTR; if (!keymap_x11->have_direction || keymap_x11->current_group_atom != group_atom)
{
gboolean cache_hit = FALSE;
DirectionCacheEntry *cache = keymap_x11->group_direction_cache;
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 else
{ {
name = gdk_x11_get_xatom_name_for_display (display, xkb->names->groups[state_rec.locked_group]); /* initialize cache */
for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++)
if (g_ascii_strcasecmp (name, "arabic") == 0 || {
g_ascii_strcasecmp (name, "hebrew") == 0 || cache[i].group_atom = 0;
g_ascii_strcasecmp (name, "israelian") == 0) cache[i].serial = keymap_x11->current_cache_serial;
result = PANGO_DIRECTION_RTL; }
else keymap_x11->current_cache_serial++;
result = PANGO_DIRECTION_LTR;
} }
return result; /* 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;
}
}
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 void
_gdk_keymap_state_changed (GdkDisplay *display) _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); GdkKeymapX11 *keymap_x11 = GDK_KEYMAP_X11 (display_x11->keymap);
PangoDirection new_direction = get_direction (keymap_x11); _gdk_keymap_direction_changed (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");
}
} }
} }
@ -484,16 +598,13 @@ gdk_keymap_get_direction (GdkKeymap *keymap)
GdkKeymapX11 *keymap_x11 = GDK_KEYMAP_X11 (keymap); GdkKeymapX11 *keymap_x11 = GDK_KEYMAP_X11 (keymap);
if (!keymap_x11->have_direction) if (!keymap_x11->have_direction)
{ update_direction (keymap_x11);
keymap_x11->current_direction = get_direction (keymap_x11);
keymap_x11->have_direction = TRUE;
}
return keymap_x11->current_direction; return keymap_x11->current_direction;
} }
else else
#endif /* HAVE_XKB */ #endif /* HAVE_XKB */
return PANGO_DIRECTION_LTR; return PANGO_DIRECTION_NEUTRAL;
} }
/** /**