From fd6513858928b05ddac41cc660b6006ffaac6f01 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 14 Jun 2010 17:29:21 +0100 Subject: [PATCH 1/7] build: Check for the XKB extension When compiling the X11 backends. --- README | 1 + configure.ac | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/README b/README index 9d132fd77..a1666dff4 100644 --- a/README +++ b/README @@ -28,6 +28,7 @@ On X11, Clutter depends on the following extensions • XExt • XFixes • XInput 1.x (if --enable-xinput is passed to configure) + • XKB When running the OpenGL flavor, Clutter requires at least version 1.3 or 1.2 with the multitexturing extension. However to build Clutter diff --git a/configure.ac b/configure.ac index 1fb7e2be6..1bcf2924c 100644 --- a/configure.ac +++ b/configure.ac @@ -684,7 +684,7 @@ AS_IF([test "x$SUPPORT_XLIB" = "x1"], [yes], [ - AC_DEFINE(HAVE_XINPUT, 1, Use the XINPUT X extension) + AC_DEFINE(HAVE_XINPUT, 1, [Use the XINPUT X extension]) X11_LIBS="$X11_LIBS -lXi" X11_PC_FILES="$X11_PC_FILES xi" @@ -694,6 +694,23 @@ AS_IF([test "x$SUPPORT_XLIB" = "x1"], [], ) + # XKB + clutter_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $X11_CFLAGS" + + clutter_save_LIBS="$LIBS" + LIBS="$LIBS $X11_LIBS" + + have_xkb=no + AC_CHECK_FUNC([XkbQueryExtension], + [ + AC_DEFINE(HAVE_XKB, 1, [Define to use XKB extension]) + have_xkb=yes + ]) + + CPPFLAGS="$clutter_save_CPPFLAGS" + LIBS="$clutter_save_LIBS" + x11_tests=yes BACKEND_PC_FILES="$BACKEND_PC_FILES $X11_PC_FILES" FLAVOUR_LIBS="$FLAVOUR_LIBS $X11_LIBS" @@ -1136,6 +1153,7 @@ fi if test "x$SUPPORT_XLIB" = "x1"; then echo " Enable XInput 1.0: ${xinput}" +echo " Enable XKB: ${have_xkb}" echo " Enable X11 tests: ${x11_tests}" fi From f44ccba42e29b0bc1d32afaaeb83de51a4a35603 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 14 Jun 2010 18:01:17 +0100 Subject: [PATCH 2/7] events: Add platform-data to allocated Events Events allocated by Clutter should have a pointer to platform-specific data; this would allow backends to add separate structures for holding ancillary data, whilst retaining the ClutterEvent structure for use on the stack. In theory, for Clutter 2.x we might just want to drop Event and use an opaque structure, or a typed data structure inheriting from GTypeInstance instead. --- clutter/clutter-backend.c | 30 +++++++++++++++++ clutter/clutter-backend.h | 6 ++++ clutter/clutter-event.c | 68 +++++++++++++++++++++++++++++++++++++-- clutter/clutter-private.h | 11 ++++++- 4 files changed, 112 insertions(+), 3 deletions(-) diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c index 1a92267d0..7e32ac55f 100644 --- a/clutter/clutter-backend.c +++ b/clutter/clutter-backend.c @@ -518,6 +518,36 @@ _clutter_backend_get_units_per_em (ClutterBackend *backend, return priv->units_per_em; } +void +_clutter_backend_copy_event_data (ClutterBackend *backend, + ClutterEvent *src, + ClutterEvent *dest) +{ + ClutterBackendClass *klass; + + g_return_if_fail (CLUTTER_IS_BACKEND (backend)); + g_return_if_fail (src != NULL); + g_return_if_fail (dest != NULL); + + klass = CLUTTER_BACKEND_GET_CLASS (backend); + if (klass->copy_event_data != NULL) + klass->copy_event_data (backend, src, dest); +} + +void +_clutter_backend_free_event_data (ClutterBackend *backend, + ClutterEvent *event) +{ + ClutterBackendClass *klass; + + g_return_if_fail (CLUTTER_IS_BACKEND (backend)); + g_return_if_fail (event != NULL); + + klass = CLUTTER_BACKEND_GET_CLASS (backend); + if (klass->free_event_data != NULL) + klass->free_event_data (backend, event); +} + /** * clutter_get_default_backend: * diff --git a/clutter/clutter-backend.h b/clutter/clutter-backend.h index 1012664d1..21d2ac39f 100644 --- a/clutter/clutter-backend.h +++ b/clutter/clutter-backend.h @@ -85,6 +85,12 @@ struct _ClutterBackendClass ClutterStage *stage); ClutterDeviceManager *(* get_device_manager) (ClutterBackend *backend); + void (* copy_event_data) (ClutterBackend *backend, + ClutterEvent *src, + ClutterEvent *dest); + void (* free_event_data) (ClutterBackend *backend, + ClutterEvent *event); + /* signals */ void (* resolution_changed) (ClutterBackend *backend); void (* font_changed) (ClutterBackend *backend); diff --git a/clutter/clutter-event.c b/clutter/clutter-event.c index d6755cb22..f71b21312 100644 --- a/clutter/clutter-event.c +++ b/clutter/clutter-event.c @@ -43,6 +43,52 @@ * be synthesized by Clutter itself or by the application code. */ +typedef struct _ClutterEventPrivate { + ClutterEvent base; + + gpointer platform_data; +} ClutterEventPrivate; + +static GHashTable *all_events = NULL; + +static gboolean +is_event_allocated (const ClutterEvent *event) +{ + if (all_events == NULL) + return FALSE; + + return g_hash_table_lookup (all_events, event) != NULL; +} + +/* + * _clutter_event_get_platform_data: + * @event: a #ClutterEvent + * + * Retrieves the pointer to platform-specific data inside an event + * + * Return value: a pointer to platform-specific data + * + * Since: 1.4 + */ +gpointer +_clutter_event_get_platform_data (const ClutterEvent *event) +{ + if (!is_event_allocated (event)) + return NULL; + + return ((ClutterEventPrivate *) event)->platform_data; +} + +void +_clutter_event_set_platform_data (ClutterEvent *event, + gpointer data) +{ + if (!is_event_allocated (event)) + return; + + ((ClutterEventPrivate *) event)->platform_data = data; +} + /** * clutter_event_type: * @event: a #ClutterEvent @@ -606,10 +652,18 @@ ClutterEvent * clutter_event_new (ClutterEventType type) { ClutterEvent *new_event; + ClutterEventPrivate *priv; - new_event = g_slice_new0 (ClutterEvent); + priv = g_slice_new0 (ClutterEventPrivate); + + new_event = (ClutterEvent *) priv; new_event->type = new_event->any.type = type; + if (all_events == NULL) + all_events = g_hash_table_new (NULL, NULL); + + g_hash_table_replace (all_events, priv, GUINT_TO_POINTER (1)); + return new_event; } @@ -631,6 +685,11 @@ clutter_event_copy (ClutterEvent *event) new_event = clutter_event_new (CLUTTER_NOTHING); *new_event = *event; + if (is_event_allocated (event)) + _clutter_backend_copy_event_data (clutter_get_default_backend (), + event, + new_event); + return new_event; } @@ -644,7 +703,12 @@ void clutter_event_free (ClutterEvent *event) { if (G_LIKELY (event != NULL)) - g_slice_free (ClutterEvent, event); + { + _clutter_backend_free_event_data (clutter_get_default_backend (), event); + + g_hash_table_remove (all_events, event); + g_slice_free (ClutterEventPrivate, (ClutterEventPrivate *) event); + } } /** diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index 40d717c74..666428b4d 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -245,7 +245,6 @@ int _clutter_stage_get_pending_swaps (ClutterStage *stage); gboolean _clutter_stage_has_full_redraw_queued (ClutterStage *stage); - /* vfuncs implemented by backend */ GType _clutter_backend_impl_get_type (void); @@ -270,6 +269,12 @@ gboolean _clutter_backend_post_parse (ClutterBackend *backend, GError **error); void _clutter_backend_init_events (ClutterBackend *backend); +void _clutter_backend_copy_event_data (ClutterBackend *backend, + ClutterEvent *src, + ClutterEvent *dest); +void _clutter_backend_free_event_data (ClutterBackend *backend, + ClutterEvent *event); + ClutterFeatureFlags _clutter_backend_get_features (ClutterBackend *backend); gfloat _clutter_backend_get_units_per_em (ClutterBackend *backend, @@ -341,6 +346,10 @@ void _clutter_effect_post_paint (ClutterEffect *effect); GType _clutter_layout_manager_get_child_meta_type (ClutterLayoutManager *manager); +void _clutter_event_set_platform_data (ClutterEvent *event, + gpointer data); +gpointer _clutter_event_get_platform_data (const ClutterEvent *event); + G_END_DECLS #endif /* _HAVE_CLUTTER_PRIVATE_H */ From d345a61e6c017af594a4d9624a861035be4dd592 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 8 Jul 2010 15:47:18 +0100 Subject: [PATCH 3/7] x11: Store the group inside the event platform data Now that we have private, per-event platform data, we can start putting it to good use. The first, most simple use is to store the key group given the event's modifiers. Since we assume a modern X11, we use XKB to retrieve it, or we simply fall back to 0 by default. The data is exposed as a ClutterX11-specific function, within the sanctioned clutter_x11_* namespace. --- clutter/x11/clutter-backend-x11.c | 25 +++++++++ clutter/x11/clutter-backend-x11.h | 12 +++++ clutter/x11/clutter-event-x11.c | 90 ++++++++++++++++++++++++++++--- clutter/x11/clutter-x11.h | 2 + 4 files changed, 122 insertions(+), 7 deletions(-) diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c index 81ce4d817..8bc13ec49 100644 --- a/clutter/x11/clutter-backend-x11.c +++ b/clutter/x11/clutter-backend-x11.c @@ -475,6 +475,29 @@ clutter_backend_x11_get_features (ClutterBackend *backend) return CLUTTER_FEATURE_STAGE_USER_RESIZE | CLUTTER_FEATURE_STAGE_CURSOR; } +static void +clutter_backend_x11_copy_event_data (ClutterBackend *backend, + ClutterEvent *src, + ClutterEvent *dest) +{ + gpointer event_x11; + + event_x11 = _clutter_event_get_platform_data (src); + if (event_x11 != NULL) + _clutter_event_set_platform_data (dest, _clutter_event_x11_copy (event_x11)); +} + +static void +clutter_backend_x11_free_event_data (ClutterBackend *backend, + ClutterEvent *event) +{ + gpointer event_x11; + + event_x11 = _clutter_event_get_platform_data (event); + if (event_x11 != NULL) + _clutter_event_x11_free (event_x11); +} + gboolean clutter_backend_x11_handle_event (ClutterBackendX11 *backend_x11, XEvent *xevent) @@ -516,6 +539,8 @@ clutter_backend_x11_class_init (ClutterBackendX11Class *klass) backend_class->add_options = clutter_backend_x11_add_options; backend_class->get_features = clutter_backend_x11_get_features; backend_class->get_device_manager = clutter_backend_x11_get_device_manager; + backend_class->copy_event_data = clutter_backend_x11_copy_event_data; + backend_class->free_event_data = clutter_backend_x11_free_event_data; backendx11_class->handle_event = clutter_backend_x11_handle_event; } diff --git a/clutter/x11/clutter-backend-x11.h b/clutter/x11/clutter-backend-x11.h index eebdc4db9..482634314 100644 --- a/clutter/x11/clutter-backend-x11.h +++ b/clutter/x11/clutter-backend-x11.h @@ -109,6 +109,9 @@ struct _ClutterBackendX11Class XEvent *xevent); }; +/* platform-specific event data */ +typedef struct _ClutterEventX11 ClutterEventX11; + void _clutter_backend_x11_events_init (ClutterBackend *backend); void _clutter_backend_x11_events_uninit (ClutterBackend *backend); @@ -146,6 +149,15 @@ _clutter_x11_get_device_for_xid (XID id); void _clutter_x11_select_events (Window xwin); +ClutterEventX11 * +_clutter_event_x11_new (void); + +ClutterEventX11 * +_clutter_event_x11_copy (ClutterEventX11 *event_x11); + +void +_clutter_event_x11_free (ClutterEventX11 *event_x11); + G_END_DECLS #endif /* __CLUTTER_BACKEND_X11_H__ */ diff --git a/clutter/x11/clutter-event-x11.c b/clutter/x11/clutter-event-x11.c index 28bb4b3ab..9643f189a 100644 --- a/clutter/x11/clutter-event-x11.c +++ b/clutter/x11/clutter-event-x11.c @@ -54,6 +54,10 @@ #include #endif +#ifdef HAVE_XKB +#include +#endif + /* XEMBED protocol support for toolkit embedding */ #define XEMBED_MAPPED (1 << 0) #define MAX_SUPPORTED_XEMBED_VERSION 1 @@ -85,6 +89,34 @@ struct _ClutterEventSource GPollFD event_poll_fd; }; +struct _ClutterEventX11 +{ + /* additional fields for Key events */ + gint key_group; +}; + +ClutterEventX11 * +_clutter_event_x11_new (void) +{ + return g_slice_new0 (ClutterEventX11); +} + +ClutterEventX11 * +_clutter_event_x11_copy (ClutterEventX11 *event_x11) +{ + if (event_x11 != NULL) + return g_slice_dup (ClutterEventX11, event_x11); + + return NULL; +} + +void +_clutter_event_x11_free (ClutterEventX11 *event_x11) +{ + if (event_x11 != NULL) + g_slice_free (ClutterEventX11, event_x11); +} + static gboolean clutter_event_prepare (GSource *source, gint *timeout); static gboolean clutter_event_check (GSource *source); @@ -300,12 +332,30 @@ translate_key_event (ClutterBackend *backend, ClutterEvent *event, XEvent *xevent) { - char buffer[256+1]; + ClutterEventX11 *event_x11; + char buffer[256 + 1]; int n; CLUTTER_NOTE (EVENT, "Translating key %s event", xevent->xany.type == KeyPress ? "press" : "release"); + /* KeyEvents have platform specific data associated to them */ + event_x11 = _clutter_event_x11_new (); + _clutter_event_set_platform_data (event, event_x11); + +#ifdef HAVE_XKB + event_x11->key_group = XkbGroupForCoreState (xevent->xkey.state); + + CLUTTER_NOTE (EVENT, "Key group: %d (xkb enabled: yes)", + event_x11->key_group); +#else + /* we force the key group to 0 */ + event_x11->key_group = 0; + + CLUTTER_NOTE (EVENT, "Key group: %d (xkb enabled: no)", + event_x11->key_group); +#endif /* HAVE_XKB */ + event->key.time = xevent->xkey.time; event->key.modifier_state = (ClutterModifierType) xevent->xkey.state; event->key.hardware_keycode = xevent->xkey.keycode; @@ -326,8 +376,8 @@ translate_key_event (ClutterBackend *backend, (event->key.unicode_value != -2)) return; } - - event->key.unicode_value = (gunichar)'\0'; + else + event->key.unicode_value = (gunichar)'\0'; } static gboolean @@ -509,7 +559,9 @@ event_translate (ClutterBackend *backend, if ((stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN) || (stage_x11->xwin_width != xevent->xconfigure.width) || (stage_x11->xwin_height != xevent->xconfigure.height)) - clutter_actor_queue_relayout (CLUTTER_ACTOR (stage)); + { + clutter_actor_queue_relayout (CLUTTER_ACTOR (stage)); + } /* If we're fullscreened, we want these variables to * represent the size of the window before it was set @@ -1031,9 +1083,7 @@ events_queue (ClutterBackend *backend) g_queue_push_head (clutter_context->events_queue, event); } else - { - clutter_event_free (event); - } + clutter_event_free (event); } } @@ -1209,3 +1259,29 @@ clutter_x11_get_current_event_time (void) return CLUTTER_BACKEND_X11 (backend)->last_event_time; } + +/** + * clutter_x11_event_get_key_group: + * @event: a #ClutterEvent of type %CLUTTER_KEY_PRESS or %CLUTTER_KEY_RELEASE + * + * Retrieves the group for the modifiers set in @event + * + * Return value: the group id + * + * Since: 1.4 + */ +gint +clutter_x11_event_get_key_group (const ClutterEvent *event) +{ + ClutterEventX11 *event_x11; + + g_return_val_if_fail (event != NULL, 0); + g_return_val_if_fail (event->type == CLUTTER_KEY_PRESS || + event->type == CLUTTER_KEY_RELEASE, 0); + + event_x11 = _clutter_event_get_platform_data (event); + if (event_x11 == NULL) + return 0; + + return event_x11->key_group; +} diff --git a/clutter/x11/clutter-x11.h b/clutter/x11/clutter-x11.h index 630e63af4..70e3324bb 100644 --- a/clutter/x11/clutter-x11.h +++ b/clutter/x11/clutter-x11.h @@ -141,6 +141,8 @@ gboolean clutter_x11_get_use_argb_visual (void); Time clutter_x11_get_current_event_time (void); +gint clutter_x11_event_get_key_group (const ClutterEvent *event); + G_END_DECLS #endif /* __CLUTTER_X11_H__ */ From bea657d3d5e7306c10b245d5cf348e80e0084719 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 12 Jul 2010 17:11:30 +0100 Subject: [PATCH 4/7] x11: Add a Keymap ancillary object We should try to abstract everything that is related with the key mapping to its own object, to avoid complicating ClutterBackendX11 any further. --- clutter/x11/Makefile.am | 2 + clutter/x11/clutter-backend-x11.c | 6 ++ clutter/x11/clutter-backend-x11.h | 3 + clutter/x11/clutter-event-x11.c | 17 +---- clutter/x11/clutter-keymap-x11.c | 123 ++++++++++++++++++++++++++++++ clutter/x11/clutter-keymap-x11.h | 44 +++++++++++ 6 files changed, 182 insertions(+), 13 deletions(-) create mode 100644 clutter/x11/clutter-keymap-x11.c create mode 100644 clutter/x11/clutter-keymap-x11.h diff --git a/clutter/x11/Makefile.am b/clutter/x11/Makefile.am index 6e227bb71..b8c7c03da 100644 --- a/clutter/x11/Makefile.am +++ b/clutter/x11/Makefile.am @@ -46,6 +46,8 @@ libclutter_x11_la_SOURCES = \ $(srcdir)/clutter-event-x11.c \ $(srcdir)/clutter-input-device-x11.h \ $(srcdir)/clutter-input-device-x11.c \ + $(srcdir)/clutter-keymap-x11.h \ + $(srcdir)/clutter-keymap-x11.c \ $(srcdir)/clutter-settings-x11.h \ $(srcdir)/clutter-stage-x11.h \ $(srcdir)/clutter-stage-x11.c \ diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c index 8bc13ec49..8a78c1937 100644 --- a/clutter/x11/clutter-backend-x11.c +++ b/clutter/x11/clutter-backend-x11.c @@ -319,6 +319,12 @@ clutter_backend_x11_post_parse (ClutterBackend *backend, "backend", backend_x11, NULL); + /* register keymap */ + backend_x11->keymap = + g_object_new (CLUTTER_TYPE_KEYMAP_X11, + "backend", backend_x11, + NULL); + /* create XSETTINGS client */ backend_x11->xsettings = _clutter_xsettings_client_new (backend_x11->xdpy, diff --git a/clutter/x11/clutter-backend-x11.h b/clutter/x11/clutter-backend-x11.h index 482634314..78a15cf0b 100644 --- a/clutter/x11/clutter-backend-x11.h +++ b/clutter/x11/clutter-backend-x11.h @@ -30,6 +30,7 @@ #include "clutter-x11.h" +#include "clutter-keymap-x11.h" #include "xsettings/xsettings-client.h" G_BEGIN_DECLS @@ -88,6 +89,8 @@ struct _ClutterBackendX11 XSettingsClient *xsettings; Window xsettings_xwin; + + ClutterKeymapX11 *keymap; }; struct _ClutterBackendX11Class diff --git a/clutter/x11/clutter-event-x11.c b/clutter/x11/clutter-event-x11.c index 9643f189a..9e65d9fa1 100644 --- a/clutter/x11/clutter-event-x11.c +++ b/clutter/x11/clutter-event-x11.c @@ -30,6 +30,7 @@ #include "clutter-stage-x11.h" #include "clutter-backend-x11.h" +#include "clutter-keymap-x11.h" #include "clutter-x11.h" #include "../clutter-backend.h" @@ -343,19 +344,6 @@ translate_key_event (ClutterBackend *backend, event_x11 = _clutter_event_x11_new (); _clutter_event_set_platform_data (event, event_x11); -#ifdef HAVE_XKB - event_x11->key_group = XkbGroupForCoreState (xevent->xkey.state); - - CLUTTER_NOTE (EVENT, "Key group: %d (xkb enabled: yes)", - event_x11->key_group); -#else - /* we force the key group to 0 */ - event_x11->key_group = 0; - - CLUTTER_NOTE (EVENT, "Key group: %d (xkb enabled: no)", - event_x11->key_group); -#endif /* HAVE_XKB */ - event->key.time = xevent->xkey.time; event->key.modifier_state = (ClutterModifierType) xevent->xkey.state; event->key.hardware_keycode = xevent->xkey.keycode; @@ -366,6 +354,9 @@ translate_key_event (ClutterBackend *backend, xevent->xkey.keycode, 0); + event_x11->key_group = + _clutter_keymap_x11_get_key_group (event->key.modifier_state); + /* unicode_value is the printable representation */ n = XLookupString (&xevent->xkey, buffer, sizeof (buffer) - 1, NULL, NULL); diff --git a/clutter/x11/clutter-keymap-x11.c b/clutter/x11/clutter-keymap-x11.c new file mode 100644 index 000000000..4e5561bd8 --- /dev/null +++ b/clutter/x11/clutter-keymap-x11.c @@ -0,0 +1,123 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corp. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: Emmanuele Bassi + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clutter-keymap-x11.h" + +#include "clutter-debug.h" +#include "clutter-private.h" + +#include + +#ifdef HAVE_XINPUT +#include +#endif + +#ifdef HAVE_XKB +#include +#endif + +typedef struct _ClutterKeymapX11Class ClutterKeymapX11Class; + +struct _ClutterKeymapX11 +{ + GObject parent_instance; + + ClutterBackend *backend; +}; + +struct _ClutterKeymapX11Class +{ + GObjectClass parent_class; +}; + +enum +{ + PROP_0, + + PROP_BACKEND +}; + +G_DEFINE_TYPE (ClutterKeymapX11, clutter_keymap_x11, G_TYPE_OBJECT); + +static void +clutter_keymap_x11_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ClutterKeymapX11 *keymap = CLUTTER_KEYMAP_X11 (gobject); + + switch (prop_id) + { + case PROP_BACKEND: + keymap->backend = g_value_get_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } +} + +static void +clutter_keymap_x11_finalize (GObject *gobject) +{ + G_OBJECT_CLASS (clutter_keymap_x11_parent_class)->finalize (gobject); +} + +static void +clutter_keymap_x11_class_init (ClutterKeymapX11Class *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; + + gobject_class->set_property = clutter_keymap_x11_set_property; + gobject_class->finalize = clutter_keymap_x11_finalize; + + pspec = g_param_spec_object ("backend", + "Backend", + "The Clutter backend", + CLUTTER_TYPE_BACKEND, + CLUTTER_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (gobject_class, PROP_BACKEND, pspec); +} + +static void +clutter_keymap_x11_init (ClutterKeymapX11 *keymap) +{ +} + +gint +_clutter_keymap_x11_get_key_group (ClutterModifierType state) +{ +#ifdef HAVE_XKB + return XkbGroupForCoreState (state); +#else + return 0; +#endif /* HAVE_XKB */ +} diff --git a/clutter/x11/clutter-keymap-x11.h b/clutter/x11/clutter-keymap-x11.h new file mode 100644 index 000000000..a64c8b2b7 --- /dev/null +++ b/clutter/x11/clutter-keymap-x11.h @@ -0,0 +1,44 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2009 Intel Corp. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: Emmanuele Bassi + */ + +#ifndef __CLUTTER_KEYMAP_X11_H__ +#define __CLUTTER_KEYMAP_X11_H__ + +#include +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_KEYMAP_X11 (clutter_keymap_x11_get_type ()) +#define CLUTTER_KEYMAP_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_KEYMAP_X11, ClutterKeymapX11)) +#define CLUTTER_IS_KEYMAP_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_KEYMAP_X11)) + +typedef struct _ClutterKeymapX11 ClutterKeymapX11; + +GType clutter_keymap_x11_get_type (void) G_GNUC_CONST; + +gint _clutter_keymap_x11_get_key_group (ClutterModifierType state); + +G_END_DECLS + +#endif /* __CLUTTER_KEYMAP_X11_H__ */ From bf2f8d670d449299aba85526ebc3289b20f3d300 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 12 Jul 2010 18:04:03 +0100 Subject: [PATCH 5/7] 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. --- clutter/x11/clutter-backend-x11.h | 3 + clutter/x11/clutter-event-x11.c | 20 ++-- clutter/x11/clutter-keymap-x11.c | 155 +++++++++++++++++++++++++++++- clutter/x11/clutter-keymap-x11.h | 3 +- 4 files changed, 171 insertions(+), 10 deletions(-) diff --git a/clutter/x11/clutter-backend-x11.h b/clutter/x11/clutter-backend-x11.h index 78a15cf0b..e51cc135f 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 9e65d9fa1..42f6034c9 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 4e5561bd8..fcf0f388f 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 a64c8b2b7..e0d0fb6aa 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 From 1ea4c50041b3193a83e0336e9a39a91b57bdb7ed Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 13 Jul 2010 09:15:21 +0100 Subject: [PATCH 6/7] x11: Use XKB to track the Locks state For Caps Lock and Num Lock. Store the state of both in the platform-specific per-event data structure. No accessors, yet. --- clutter/x11/clutter-event-x11.c | 17 +++++-- clutter/x11/clutter-keymap-x11.c | 83 ++++++++++++++++++++++++++++++-- clutter/x11/clutter-keymap-x11.h | 6 ++- 3 files changed, 96 insertions(+), 10 deletions(-) diff --git a/clutter/x11/clutter-event-x11.c b/clutter/x11/clutter-event-x11.c index 42f6034c9..267aa52b8 100644 --- a/clutter/x11/clutter-event-x11.c +++ b/clutter/x11/clutter-event-x11.c @@ -94,6 +94,9 @@ struct _ClutterEventX11 { /* additional fields for Key events */ gint key_group; + + guint num_lock_set : 1; + guint caps_lock_set : 1; }; ClutterEventX11 * @@ -328,7 +331,7 @@ convert_xdevicekey_to_xkey (XDeviceKeyEvent *xkev, } #endif /* HAVE_XINPUT */ -static void +static inline void translate_key_event (ClutterBackendX11 *backend_x11, ClutterEvent *event, XEvent *xevent) @@ -336,9 +339,6 @@ translate_key_event (ClutterBackendX11 *backend_x11, ClutterEventX11 *event_x11; char buffer[256 + 1]; int n; - - CLUTTER_NOTE (EVENT, "Translating key %s event", - xevent->xany.type == KeyPress ? "press" : "release"); /* KeyEvents have platform specific data associated to them */ event_x11 = _clutter_event_x11_new (); @@ -357,6 +357,10 @@ translate_key_event (ClutterBackendX11 *backend_x11, event_x11->key_group = _clutter_keymap_x11_get_key_group (backend_x11->keymap, event->key.modifier_state); + event_x11->num_lock_set = + _clutter_keymap_x11_get_num_lock_state (backend_x11->keymap); + event_x11->caps_lock_set = + _clutter_keymap_x11_get_caps_lock_state (backend_x11->keymap); /* unicode_value is the printable representation */ n = XLookupString (&xevent->xkey, buffer, sizeof (buffer) - 1, NULL, NULL); @@ -366,10 +370,13 @@ translate_key_event (ClutterBackendX11 *backend_x11, event->key.unicode_value = g_utf8_get_char_validated (buffer, n); if ((event->key.unicode_value != -1) && (event->key.unicode_value != -2)) - return; + goto out; } else event->key.unicode_value = (gunichar)'\0'; + +out: + return; } static gboolean diff --git a/clutter/x11/clutter-keymap-x11.c b/clutter/x11/clutter-keymap-x11.c index fcf0f388f..9957e8a7c 100644 --- a/clutter/x11/clutter-keymap-x11.c +++ b/clutter/x11/clutter-keymap-x11.c @@ -59,6 +59,9 @@ struct _ClutterKeymapX11 #ifdef HAVE_XKB XkbDescPtr xkb_desc; #endif + + guint caps_lock_state : 1; + guint num_lock_state : 1; }; struct _ClutterKeymapX11Class @@ -156,6 +159,65 @@ get_xkb (ClutterKeymapX11 *keymap_x11) } #endif /* HAVE_XKB */ +#ifdef HAVE_XKB +static void +update_locked_mods (ClutterKeymapX11 *keymap_x11, + gint locked_mods) +{ + gboolean old_caps_lock_state, old_num_lock_state; + + old_caps_lock_state = keymap_x11->caps_lock_state; + old_num_lock_state = keymap_x11->num_lock_state; + + keymap_x11->caps_lock_state = (locked_mods & CLUTTER_LOCK_MASK) != 0; + keymap_x11->num_lock_state = (locked_mods & keymap_x11->num_lock_mask) != 0; + + CLUTTER_NOTE (BACKEND, "Locks state changed - Num: %s, Caps: %s", + keymap_x11->num_lock_state ? "set" : "unset", + keymap_x11->caps_lock_state ? "set" : "unset"); +#if 0 + /* Add signal to ClutterBackend? */ + if ((keymap_x11->caps_lock_state != old_caps_lock_state) || + (keymap_x11->num_lock_state != old_num_lock_state)) + g_signal_emit_by_name (keymap_x11->backend, "key-lock-changed"); +#endif +} + +static ClutterX11FilterReturn +xkb_filter (XEvent *xevent, + ClutterEvent *event, + gpointer data) +{ + ClutterBackendX11 *backend_x11 = data; + ClutterKeymapX11 *keymap_x11 = backend_x11->keymap; + + g_assert (keymap_x11 != NULL); + + if (!backend_x11->use_xkb) + return CLUTTER_X11_FILTER_CONTINUE; + + if (xevent->type == backend_x11->xkb_event_base) + { + XkbEvent *xkb_event = (XkbEvent *) xevent; + + CLUTTER_NOTE (BACKEND, "Received XKB event [%d]", + xkb_event->any.xkb_type); + + switch (xkb_event->any.xkb_type) + { + case XkbStateNotify: + update_locked_mods (keymap_x11, xkb_event->state.locked_mods); + break; + + default: + break; + } + } + + return CLUTTER_X11_FILTER_CONTINUE; +} +#endif /* HAVE_XKB */ + static void clutter_keymap_x11_constructed (GObject *gobject) { @@ -183,8 +245,6 @@ clutter_keymap_x11_constructed (GObject *gobject) backend_x11->use_xkb = TRUE; -#if 0 - /* XXX - enable when we handle keymap-related events */ XkbSelectEvents (backend_x11->xdpy, XkbUseCoreKbd, XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask, @@ -194,7 +254,8 @@ clutter_keymap_x11_constructed (GObject *gobject) XkbUseCoreKbd, XkbStateNotify, XkbAllStateComponentsMask, XkbGroupLockMask|XkbModifierLockMask); -#endif + + clutter_x11_add_filter (xkb_filter, backend_x11); /* enable XKB autorepeat */ XkbSetDetectableAutoRepeat (backend_x11->xdpy, @@ -274,3 +335,19 @@ _clutter_keymap_x11_get_key_group (ClutterKeymapX11 *keymap, return 0; #endif /* HAVE_XKB */ } + +gboolean +_clutter_keymap_x11_get_num_lock_state (ClutterKeymapX11 *keymap) +{ + g_return_val_if_fail (CLUTTER_IS_KEYMAP_X11 (keymap), FALSE); + + return keymap->num_lock_state; +} + +gboolean +_clutter_keymap_x11_get_caps_lock_state (ClutterKeymapX11 *keymap) +{ + g_return_val_if_fail (CLUTTER_IS_KEYMAP_X11 (keymap), FALSE); + + return keymap->caps_lock_state; +} diff --git a/clutter/x11/clutter-keymap-x11.h b/clutter/x11/clutter-keymap-x11.h index e0d0fb6aa..f228c6f10 100644 --- a/clutter/x11/clutter-keymap-x11.h +++ b/clutter/x11/clutter-keymap-x11.h @@ -37,8 +37,10 @@ typedef struct _ClutterKeymapX11 ClutterKeymapX11; GType clutter_keymap_x11_get_type (void) G_GNUC_CONST; -gint _clutter_keymap_x11_get_key_group (ClutterKeymapX11 *keymap, - ClutterModifierType state); +gint _clutter_keymap_x11_get_key_group (ClutterKeymapX11 *keymap, + ClutterModifierType state); +gboolean _clutter_keymap_x11_get_num_lock_state (ClutterKeymapX11 *keymap); +gboolean _clutter_keymap_x11_get_caps_lock_state (ClutterKeymapX11 *keymap); G_END_DECLS From 6c913aa55e67d56c5095f48a61aaef85961736ec Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 13 Jul 2010 11:54:44 +0100 Subject: [PATCH 7/7] x11: Use XKB to translate keycodes into key symbols And fall back to XKeycodeToKeysym() if XKB is not available. --- clutter/x11/clutter-event-x11.c | 15 ++++--- clutter/x11/clutter-keymap-x11.c | 73 +++++++++++++++++++++++++++++++- clutter/x11/clutter-keymap-x11.h | 6 +++ 3 files changed, 87 insertions(+), 7 deletions(-) diff --git a/clutter/x11/clutter-event-x11.c b/clutter/x11/clutter-event-x11.c index 267aa52b8..acddb389f 100644 --- a/clutter/x11/clutter-event-x11.c +++ b/clutter/x11/clutter-event-x11.c @@ -95,8 +95,9 @@ struct _ClutterEventX11 /* additional fields for Key events */ gint key_group; - guint num_lock_set : 1; - guint caps_lock_set : 1; + guint key_is_modifier : 1; + guint num_lock_set : 1; + guint caps_lock_set : 1; }; ClutterEventX11 * @@ -350,13 +351,17 @@ translate_key_event (ClutterBackendX11 *backend_x11, /* keyval is the key ignoring all modifiers ('1' vs. '!') */ event->key.keyval = - XKeycodeToKeysym (xevent->xkey.display, - xevent->xkey.keycode, - 0); + _clutter_keymap_x11_translate_key_state (backend_x11->keymap, + event->key.hardware_keycode, + event->key.modifier_state, + NULL); event_x11->key_group = _clutter_keymap_x11_get_key_group (backend_x11->keymap, event->key.modifier_state); + event_x11->key_is_modifier = + _clutter_keymap_x11_get_is_modifier (backend_x11->keymap, + event->key.hardware_keycode); event_x11->num_lock_set = _clutter_keymap_x11_get_num_lock_state (backend_x11->keymap); event_x11->caps_lock_set = diff --git a/clutter/x11/clutter-keymap-x11.c b/clutter/x11/clutter-keymap-x11.c index 9957e8a7c..abd2cb53e 100644 --- a/clutter/x11/clutter-keymap-x11.c +++ b/clutter/x11/clutter-keymap-x11.c @@ -175,6 +175,7 @@ update_locked_mods (ClutterKeymapX11 *keymap_x11, CLUTTER_NOTE (BACKEND, "Locks state changed - Num: %s, Caps: %s", keymap_x11->num_lock_state ? "set" : "unset", keymap_x11->caps_lock_state ? "set" : "unset"); + #if 0 /* Add signal to ClutterBackend? */ if ((keymap_x11->caps_lock_state != old_caps_lock_state) || @@ -296,6 +297,15 @@ clutter_keymap_x11_set_property (GObject *gobject, static void clutter_keymap_x11_finalize (GObject *gobject) { + ClutterKeymapX11 *keymap; + + keymap = CLUTTER_KEYMAP_X11 (gobject); + +#ifdef HAVE_XKB + if (keymap->xkb_desc != NULL) + XkbFreeKeyboard (keymap->xkb_desc, XkbAllComponentsMask, True); +#endif + G_OBJECT_CLASS (clutter_keymap_x11_parent_class)->finalize (gobject); } @@ -328,8 +338,6 @@ _clutter_keymap_x11_get_key_group (ClutterKeymapX11 *keymap, ClutterModifierType state) { #ifdef HAVE_XKB - (void) get_xkb (keymap); - return XkbGroupForCoreState (state); #else return 0; @@ -351,3 +359,64 @@ _clutter_keymap_x11_get_caps_lock_state (ClutterKeymapX11 *keymap) return keymap->caps_lock_state; } + +gint +_clutter_keymap_x11_translate_key_state (ClutterKeymapX11 *keymap, + guint hardware_keycode, + ClutterModifierType modifier_state, + ClutterModifierType *mods_p) +{ + ClutterBackendX11 *backend_x11; + ClutterModifierType unconsumed_modifiers = 0; + gint retval; + + g_return_val_if_fail (CLUTTER_IS_KEYMAP_X11 (keymap), 0); + + backend_x11 = CLUTTER_BACKEND_X11 (keymap->backend); + +#ifdef HAVE_XKB + if (backend_x11->use_xkb) + { + XkbDescRec *xkb = get_xkb (keymap); + KeySym tmp_keysym; + + if (XkbTranslateKeyCode (xkb, hardware_keycode, modifier_state, + &unconsumed_modifiers, + &tmp_keysym)) + { + retval = tmp_keysym; + } + else + retval = 0; + } + else +#endif /* HAVE_XKB */ + retval = XKeycodeToKeysym (backend_x11->xdpy, hardware_keycode, 0); + + if (mods_p) + *mods_p = unconsumed_modifiers; + + return retval; +} + +gboolean +_clutter_keymap_x11_get_is_modifier (ClutterKeymapX11 *keymap, + guint keycode) +{ + g_return_val_if_fail (CLUTTER_IS_KEYMAP_X11 (keymap), FALSE); + + if (keycode < keymap->min_keycode || keycode > keymap->max_keycode) + return FALSE; + +#ifdef HAVE_XKB + if (CLUTTER_BACKEND_X11 (keymap->backend)->use_xkb) + { + XkbDescRec *xkb = get_xkb (keymap); + + if (xkb->map->modmap && xkb->map->modmap[keycode] != 0) + return TRUE; + } +#endif /* HAVE_XKB */ + + return FALSE; +} diff --git a/clutter/x11/clutter-keymap-x11.h b/clutter/x11/clutter-keymap-x11.h index f228c6f10..34abf3997 100644 --- a/clutter/x11/clutter-keymap-x11.h +++ b/clutter/x11/clutter-keymap-x11.h @@ -41,6 +41,12 @@ gint _clutter_keymap_x11_get_key_group (ClutterKeymapX11 *keymap, ClutterModifierType state); gboolean _clutter_keymap_x11_get_num_lock_state (ClutterKeymapX11 *keymap); gboolean _clutter_keymap_x11_get_caps_lock_state (ClutterKeymapX11 *keymap); +gint _clutter_keymap_x11_translate_key_state (ClutterKeymapX11 *keymap, + guint hardware_keycode, + ClutterModifierType modifier_state, + ClutterModifierType *mods_p); +gboolean _clutter_keymap_x11_get_is_modifier (ClutterKeymapX11 *keymap, + guint keycode); G_END_DECLS