From: Emmanuele Bassi Date: Mon, 12 Jul 2010 17:04:03 +0000 (+0100) Subject: x11: Use XKB detectable auto-repeat X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bf2f8d670d449299aba85526ebc3289b20f3d300;p=profile%2Fivi%2Fclutter.git 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. --- diff --git a/clutter/x11/clutter-backend-x11.h b/clutter/x11/clutter-backend-x11.h index 78a15cf..e51cc13 100644 --- a/clutter/x11/clutter-backend-x11.h +++ b/clutter/x11/clutter-backend-x11.h @@ -91,6 +91,9 @@ struct _ClutterBackendX11 Window xsettings_xwin; ClutterKeymapX11 *keymap; + int xkb_event_base; + gboolean use_xkb; + gboolean have_xkb_autorepeat; }; struct _ClutterBackendX11Class diff --git a/clutter/x11/clutter-event-x11.c b/clutter/x11/clutter-event-x11.c index 9e65d9f..42f6034 100644 --- a/clutter/x11/clutter-event-x11.c +++ b/clutter/x11/clutter-event-x11.c @@ -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); diff --git a/clutter/x11/clutter-keymap-x11.c b/clutter/x11/clutter-keymap-x11.c index 4e5561b..fcf0f38 100644 --- a/clutter/x11/clutter-keymap-x11.c +++ b/clutter/x11/clutter-keymap-x11.c @@ -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; diff --git a/clutter/x11/clutter-keymap-x11.h b/clutter/x11/clutter-keymap-x11.h index a64c8b2..e0d0fb6 100644 --- a/clutter/x11/clutter-keymap-x11.h +++ b/clutter/x11/clutter-keymap-x11.h @@ -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