x11: Use XKB detectable auto-repeat

If we have XKB support then we should be using it to turn on the
detectable auto-repeat; this allows avoiding the peeking trick
that emulates it inside the event handling code.
This commit is contained in:
Emmanuele Bassi 2010-07-12 18:04:03 +01:00
parent bea657d3d5
commit bf2f8d670d
4 changed files with 171 additions and 10 deletions

View File

@ -91,6 +91,9 @@ struct _ClutterBackendX11
Window xsettings_xwin;
ClutterKeymapX11 *keymap;
int xkb_event_base;
gboolean use_xkb;
gboolean have_xkb_autorepeat;
};
struct _ClutterBackendX11Class

View File

@ -329,9 +329,9 @@ convert_xdevicekey_to_xkey (XDeviceKeyEvent *xkev,
#endif /* HAVE_XINPUT */
static void
translate_key_event (ClutterBackend *backend,
ClutterEvent *event,
XEvent *xevent)
translate_key_event (ClutterBackendX11 *backend_x11,
ClutterEvent *event,
XEvent *xevent)
{
ClutterEventX11 *event_x11;
char buffer[256 + 1];
@ -355,7 +355,8 @@ translate_key_event (ClutterBackend *backend,
0);
event_x11->key_group =
_clutter_keymap_x11_get_key_group (event->key.modifier_state);
_clutter_keymap_x11_get_key_group (backend_x11->keymap,
event->key.modifier_state);
/* unicode_value is the printable representation */
n = XLookupString (&xevent->xkey, buffer, sizeof (buffer) - 1, NULL, NULL);
@ -712,7 +713,7 @@ event_translate (ClutterBackend *backend,
clutter_device_manager_get_core_device (manager,
CLUTTER_KEYBOARD_DEVICE);
translate_key_event (backend, event, xevent);
translate_key_event (backend_x11, event, xevent);
set_user_time (backend_x11, &xwindow, xevent->xkey.time);
break;
@ -728,8 +729,11 @@ event_translate (ClutterBackend *backend,
* the next event and check if it's a KeyPress for the same key
* and timestamp - and then ignore it if it matches the
* KeyRelease
*
* if we have XKB, and autorepeat is enabled, then this becomes
* a no-op
*/
if (XPending (xevent->xkey.display))
if (!backend_x11->have_xkb_autorepeat && XPending (xevent->xkey.display))
{
XEvent next_event;
@ -749,7 +753,7 @@ event_translate (ClutterBackend *backend,
clutter_device_manager_get_core_device (manager,
CLUTTER_KEYBOARD_DEVICE);
translate_key_event (backend, event, xevent);
translate_key_event (backend_x11, event, xevent);
break;
default:
@ -1029,7 +1033,7 @@ event_translate (ClutterBackend *backend,
? CLUTTER_KEY_PRESS
: CLUTTER_KEY_RELEASE;
translate_key_event (backend, event, &xevent_converted);
translate_key_event (backend_x11, event, &xevent_converted);
if (xevent->type == key_press)
set_user_time (backend_x11, &xwindow, xkev->time);

View File

@ -26,6 +26,7 @@
#endif
#include "clutter-keymap-x11.h"
#include "clutter-backend-x11.h"
#include "clutter-debug.h"
#include "clutter-private.h"
@ -47,6 +48,17 @@ struct _ClutterKeymapX11
GObject parent_instance;
ClutterBackend *backend;
gint min_keycode;
gint max_keycode;
ClutterModifierType modmap[8];
ClutterModifierType num_lock_mask;
#ifdef HAVE_XKB
XkbDescPtr xkb_desc;
#endif
};
struct _ClutterKeymapX11Class
@ -63,6 +75,143 @@ enum
G_DEFINE_TYPE (ClutterKeymapX11, clutter_keymap_x11, G_TYPE_OBJECT);
#ifdef HAVE_XKB
/* code adapted from gdk/x11/gdkkeys-x11.c - update_modmap */
static void
update_modmap (Display *display,
ClutterKeymapX11 *keymap_x11)
{
static struct {
const gchar *name;
Atom atom;
ClutterModifierType mask;
} vmods[] = {
{ "Meta", 0, CLUTTER_META_MASK },
{ "Super", 0, CLUTTER_SUPER_MASK },
{ "Hyper", 0, CLUTTER_HYPER_MASK },
{ NULL, 0, 0 }
};
int i, j, k;
if (vmods[0].atom == 0)
for (i = 0; vmods[i].name; i++)
vmods[i].atom = XInternAtom (display, vmods[i].name, FALSE);
for (i = 0; i < 8; i++)
keymap_x11->modmap[i] = 1 << i;
for (i = 0; i < XkbNumVirtualMods; i++)
{
for (j = 0; vmods[j].atom; j++)
{
if (keymap_x11->xkb_desc->names->vmods[i] == vmods[j].atom)
{
for (k = 0; k < 8; k++)
{
if (keymap_x11->xkb_desc->server->vmods[i] & (1 << k))
keymap_x11->modmap[k] |= vmods[j].mask;
}
}
}
}
}
static XkbDescPtr
get_xkb (ClutterKeymapX11 *keymap_x11)
{
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (keymap_x11->backend);
if (keymap_x11->max_keycode == 0)
XDisplayKeycodes (backend_x11->xdpy,
&keymap_x11->min_keycode,
&keymap_x11->max_keycode);
if (keymap_x11->xkb_desc == NULL)
{
int flags = XkbKeySymsMask
| XkbKeyTypesMask
| XkbModifierMapMask
| XkbVirtualModsMask;
keymap_x11->xkb_desc = XkbGetMap (backend_x11->xdpy, flags, XkbUseCoreKbd);
if (G_UNLIKELY (keymap_x11->xkb_desc == NULL))
{
g_error ("Failed to get the keymap from XKB");
return NULL;
}
flags = XkbGroupNamesMask | XkbVirtualModNamesMask;
XkbGetNames (backend_x11->xdpy, flags, keymap_x11->xkb_desc);
update_modmap (backend_x11->xdpy, keymap_x11);
}
if (keymap_x11->num_lock_mask == 0)
keymap_x11->num_lock_mask = XkbKeysymToModifiers (backend_x11->xdpy,
XK_Num_Lock);
return keymap_x11->xkb_desc;
}
#endif /* HAVE_XKB */
static void
clutter_keymap_x11_constructed (GObject *gobject)
{
ClutterKeymapX11 *keymap_x11 = CLUTTER_KEYMAP_X11 (gobject);
ClutterBackendX11 *backend_x11;
g_assert (keymap_x11->backend != NULL);
backend_x11 = CLUTTER_BACKEND_X11 (keymap_x11->backend);
#if HAVE_XKB
{
gint xkb_major = XkbMajorVersion;
gint xkb_minor = XkbMinorVersion;
if (XkbLibraryVersion (&xkb_major, &xkb_minor))
{
xkb_major = XkbMajorVersion;
xkb_minor = XkbMinorVersion;
if (XkbQueryExtension (backend_x11->xdpy,
NULL, &backend_x11->xkb_event_base, NULL,
&xkb_major, &xkb_minor))
{
Bool detectable_autorepeat_supported;
backend_x11->use_xkb = TRUE;
#if 0
/* XXX - enable when we handle keymap-related events */
XkbSelectEvents (backend_x11->xdpy,
XkbUseCoreKbd,
XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask,
XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask);
XkbSelectEventDetails (backend_x11->xdpy,
XkbUseCoreKbd, XkbStateNotify,
XkbAllStateComponentsMask,
XkbGroupLockMask|XkbModifierLockMask);
#endif
/* enable XKB autorepeat */
XkbSetDetectableAutoRepeat (backend_x11->xdpy,
True,
&detectable_autorepeat_supported);
backend_x11->have_xkb_autorepeat = detectable_autorepeat_supported;
CLUTTER_NOTE (BACKEND, "Detectable autorepeat: %s",
backend_x11->have_xkb_autorepeat ? "supported"
: "not supported");
}
}
}
#endif /* HAVE_XKB */
}
static void
clutter_keymap_x11_set_property (GObject *gobject,
guint prop_id,
@ -95,6 +244,7 @@ clutter_keymap_x11_class_init (ClutterKeymapX11Class *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
gobject_class->constructed = clutter_keymap_x11_constructed;
gobject_class->set_property = clutter_keymap_x11_set_property;
gobject_class->finalize = clutter_keymap_x11_finalize;
@ -113,9 +263,12 @@ clutter_keymap_x11_init (ClutterKeymapX11 *keymap)
}
gint
_clutter_keymap_x11_get_key_group (ClutterModifierType state)
_clutter_keymap_x11_get_key_group (ClutterKeymapX11 *keymap,
ClutterModifierType state)
{
#ifdef HAVE_XKB
(void) get_xkb (keymap);
return XkbGroupForCoreState (state);
#else
return 0;

View File

@ -37,7 +37,8 @@ typedef struct _ClutterKeymapX11 ClutterKeymapX11;
GType clutter_keymap_x11_get_type (void) G_GNUC_CONST;
gint _clutter_keymap_x11_get_key_group (ClutterModifierType state);
gint _clutter_keymap_x11_get_key_group (ClutterKeymapX11 *keymap,
ClutterModifierType state);
G_END_DECLS