Merge branch 'wip/xkb-support'

* wip/xkb-support:
  x11: Use XKB to translate keycodes into key symbols
  x11: Use XKB to track the Locks state
  x11: Use XKB detectable auto-repeat
  x11: Add a Keymap ancillary object
  x11: Store the group inside the event platform data
  events: Add platform-data to allocated Events
  build: Check for the XKB extension
This commit is contained in:
Emmanuele Bassi 2010-07-13 16:12:14 +01:00
commit ff56f4ac6f
13 changed files with 765 additions and 26 deletions

1
README
View File

@ -28,6 +28,7 @@ On X11, Clutter depends on the following extensions
• XExt • XExt
• XFixes • XFixes
• XInput 1.x (if --enable-xinput is passed to configure) • XInput 1.x (if --enable-xinput is passed to configure)
• XKB
When running the OpenGL flavor, Clutter requires at least version 1.3 When running the OpenGL flavor, Clutter requires at least version 1.3
or 1.2 with the multitexturing extension. However to build Clutter or 1.2 with the multitexturing extension. However to build Clutter

View File

@ -518,6 +518,36 @@ _clutter_backend_get_units_per_em (ClutterBackend *backend,
return priv->units_per_em; 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: * clutter_get_default_backend:
* *

View File

@ -85,6 +85,12 @@ struct _ClutterBackendClass
ClutterStage *stage); ClutterStage *stage);
ClutterDeviceManager *(* get_device_manager) (ClutterBackend *backend); 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 */ /* signals */
void (* resolution_changed) (ClutterBackend *backend); void (* resolution_changed) (ClutterBackend *backend);
void (* font_changed) (ClutterBackend *backend); void (* font_changed) (ClutterBackend *backend);

View File

@ -43,6 +43,52 @@
* be synthesized by Clutter itself or by the application code. * 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: * clutter_event_type:
* @event: a #ClutterEvent * @event: a #ClutterEvent
@ -606,10 +652,18 @@ ClutterEvent *
clutter_event_new (ClutterEventType type) clutter_event_new (ClutterEventType type)
{ {
ClutterEvent *new_event; 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; 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; return new_event;
} }
@ -631,6 +685,11 @@ clutter_event_copy (ClutterEvent *event)
new_event = clutter_event_new (CLUTTER_NOTHING); new_event = clutter_event_new (CLUTTER_NOTHING);
*new_event = *event; *new_event = *event;
if (is_event_allocated (event))
_clutter_backend_copy_event_data (clutter_get_default_backend (),
event,
new_event);
return new_event; return new_event;
} }
@ -644,7 +703,12 @@ void
clutter_event_free (ClutterEvent *event) clutter_event_free (ClutterEvent *event)
{ {
if (G_LIKELY (event != NULL)) 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);
}
} }
/** /**

View File

@ -245,7 +245,6 @@ int _clutter_stage_get_pending_swaps (ClutterStage *stage);
gboolean _clutter_stage_has_full_redraw_queued (ClutterStage *stage); gboolean _clutter_stage_has_full_redraw_queued (ClutterStage *stage);
/* vfuncs implemented by backend */ /* vfuncs implemented by backend */
GType _clutter_backend_impl_get_type (void); GType _clutter_backend_impl_get_type (void);
@ -270,6 +269,12 @@ gboolean _clutter_backend_post_parse (ClutterBackend *backend,
GError **error); GError **error);
void _clutter_backend_init_events (ClutterBackend *backend); 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); ClutterFeatureFlags _clutter_backend_get_features (ClutterBackend *backend);
gfloat _clutter_backend_get_units_per_em (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); 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 G_END_DECLS
#endif /* _HAVE_CLUTTER_PRIVATE_H */ #endif /* _HAVE_CLUTTER_PRIVATE_H */

View File

@ -46,6 +46,8 @@ libclutter_x11_la_SOURCES = \
$(srcdir)/clutter-event-x11.c \ $(srcdir)/clutter-event-x11.c \
$(srcdir)/clutter-input-device-x11.h \ $(srcdir)/clutter-input-device-x11.h \
$(srcdir)/clutter-input-device-x11.c \ $(srcdir)/clutter-input-device-x11.c \
$(srcdir)/clutter-keymap-x11.h \
$(srcdir)/clutter-keymap-x11.c \
$(srcdir)/clutter-settings-x11.h \ $(srcdir)/clutter-settings-x11.h \
$(srcdir)/clutter-stage-x11.h \ $(srcdir)/clutter-stage-x11.h \
$(srcdir)/clutter-stage-x11.c \ $(srcdir)/clutter-stage-x11.c \

View File

@ -319,6 +319,12 @@ clutter_backend_x11_post_parse (ClutterBackend *backend,
"backend", backend_x11, "backend", backend_x11,
NULL); NULL);
/* register keymap */
backend_x11->keymap =
g_object_new (CLUTTER_TYPE_KEYMAP_X11,
"backend", backend_x11,
NULL);
/* create XSETTINGS client */ /* create XSETTINGS client */
backend_x11->xsettings = backend_x11->xsettings =
_clutter_xsettings_client_new (backend_x11->xdpy, _clutter_xsettings_client_new (backend_x11->xdpy,
@ -475,6 +481,29 @@ clutter_backend_x11_get_features (ClutterBackend *backend)
return CLUTTER_FEATURE_STAGE_USER_RESIZE | CLUTTER_FEATURE_STAGE_CURSOR; 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 gboolean
clutter_backend_x11_handle_event (ClutterBackendX11 *backend_x11, clutter_backend_x11_handle_event (ClutterBackendX11 *backend_x11,
XEvent *xevent) XEvent *xevent)
@ -516,6 +545,8 @@ clutter_backend_x11_class_init (ClutterBackendX11Class *klass)
backend_class->add_options = clutter_backend_x11_add_options; backend_class->add_options = clutter_backend_x11_add_options;
backend_class->get_features = clutter_backend_x11_get_features; backend_class->get_features = clutter_backend_x11_get_features;
backend_class->get_device_manager = clutter_backend_x11_get_device_manager; 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; backendx11_class->handle_event = clutter_backend_x11_handle_event;
} }

View File

@ -30,6 +30,7 @@
#include "clutter-x11.h" #include "clutter-x11.h"
#include "clutter-keymap-x11.h"
#include "xsettings/xsettings-client.h" #include "xsettings/xsettings-client.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -88,6 +89,11 @@ struct _ClutterBackendX11
XSettingsClient *xsettings; XSettingsClient *xsettings;
Window xsettings_xwin; Window xsettings_xwin;
ClutterKeymapX11 *keymap;
int xkb_event_base;
gboolean use_xkb;
gboolean have_xkb_autorepeat;
}; };
struct _ClutterBackendX11Class struct _ClutterBackendX11Class
@ -109,6 +115,9 @@ struct _ClutterBackendX11Class
XEvent *xevent); XEvent *xevent);
}; };
/* platform-specific event data */
typedef struct _ClutterEventX11 ClutterEventX11;
void _clutter_backend_x11_events_init (ClutterBackend *backend); void _clutter_backend_x11_events_init (ClutterBackend *backend);
void _clutter_backend_x11_events_uninit (ClutterBackend *backend); void _clutter_backend_x11_events_uninit (ClutterBackend *backend);
@ -146,6 +155,15 @@ _clutter_x11_get_device_for_xid (XID id);
void void
_clutter_x11_select_events (Window xwin); _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 G_END_DECLS
#endif /* __CLUTTER_BACKEND_X11_H__ */ #endif /* __CLUTTER_BACKEND_X11_H__ */

View File

@ -30,6 +30,7 @@
#include "clutter-stage-x11.h" #include "clutter-stage-x11.h"
#include "clutter-backend-x11.h" #include "clutter-backend-x11.h"
#include "clutter-keymap-x11.h"
#include "clutter-x11.h" #include "clutter-x11.h"
#include "../clutter-backend.h" #include "../clutter-backend.h"
@ -54,6 +55,10 @@
#include <X11/extensions/XInput.h> #include <X11/extensions/XInput.h>
#endif #endif
#ifdef HAVE_XKB
#include <X11/XKBlib.h>
#endif
/* XEMBED protocol support for toolkit embedding */ /* XEMBED protocol support for toolkit embedding */
#define XEMBED_MAPPED (1 << 0) #define XEMBED_MAPPED (1 << 0)
#define MAX_SUPPORTED_XEMBED_VERSION 1 #define MAX_SUPPORTED_XEMBED_VERSION 1
@ -85,6 +90,38 @@ struct _ClutterEventSource
GPollFD event_poll_fd; GPollFD event_poll_fd;
}; };
struct _ClutterEventX11
{
/* additional fields for Key events */
gint key_group;
guint key_is_modifier : 1;
guint num_lock_set : 1;
guint caps_lock_set : 1;
};
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, static gboolean clutter_event_prepare (GSource *source,
gint *timeout); gint *timeout);
static gboolean clutter_event_check (GSource *source); static gboolean clutter_event_check (GSource *source);
@ -295,16 +332,18 @@ convert_xdevicekey_to_xkey (XDeviceKeyEvent *xkev,
} }
#endif /* HAVE_XINPUT */ #endif /* HAVE_XINPUT */
static void static inline void
translate_key_event (ClutterBackend *backend, translate_key_event (ClutterBackendX11 *backend_x11,
ClutterEvent *event, ClutterEvent *event,
XEvent *xevent) XEvent *xevent)
{ {
char buffer[256+1]; ClutterEventX11 *event_x11;
char buffer[256 + 1];
int n; int n;
CLUTTER_NOTE (EVENT, "Translating key %s event", /* KeyEvents have platform specific data associated to them */
xevent->xany.type == KeyPress ? "press" : "release"); event_x11 = _clutter_event_x11_new ();
_clutter_event_set_platform_data (event, event_x11);
event->key.time = xevent->xkey.time; event->key.time = xevent->xkey.time;
event->key.modifier_state = (ClutterModifierType) xevent->xkey.state; event->key.modifier_state = (ClutterModifierType) xevent->xkey.state;
@ -312,9 +351,21 @@ translate_key_event (ClutterBackend *backend,
/* keyval is the key ignoring all modifiers ('1' vs. '!') */ /* keyval is the key ignoring all modifiers ('1' vs. '!') */
event->key.keyval = event->key.keyval =
XKeycodeToKeysym (xevent->xkey.display, _clutter_keymap_x11_translate_key_state (backend_x11->keymap,
xevent->xkey.keycode, event->key.hardware_keycode,
0); 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 =
_clutter_keymap_x11_get_caps_lock_state (backend_x11->keymap);
/* unicode_value is the printable representation */ /* unicode_value is the printable representation */
n = XLookupString (&xevent->xkey, buffer, sizeof (buffer) - 1, NULL, NULL); n = XLookupString (&xevent->xkey, buffer, sizeof (buffer) - 1, NULL, NULL);
@ -324,10 +375,13 @@ translate_key_event (ClutterBackend *backend,
event->key.unicode_value = g_utf8_get_char_validated (buffer, n); event->key.unicode_value = g_utf8_get_char_validated (buffer, n);
if ((event->key.unicode_value != -1) && if ((event->key.unicode_value != -1) &&
(event->key.unicode_value != -2)) (event->key.unicode_value != -2))
return; goto out;
} }
else
event->key.unicode_value = (gunichar)'\0'; event->key.unicode_value = (gunichar)'\0';
out:
return;
} }
static gboolean static gboolean
@ -509,7 +563,9 @@ event_translate (ClutterBackend *backend,
if ((stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN) || if ((stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN) ||
(stage_x11->xwin_width != xevent->xconfigure.width) || (stage_x11->xwin_width != xevent->xconfigure.width) ||
(stage_x11->xwin_height != xevent->xconfigure.height)) (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 /* If we're fullscreened, we want these variables to
* represent the size of the window before it was set * represent the size of the window before it was set
@ -669,7 +725,7 @@ event_translate (ClutterBackend *backend,
clutter_device_manager_get_core_device (manager, clutter_device_manager_get_core_device (manager,
CLUTTER_KEYBOARD_DEVICE); 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); set_user_time (backend_x11, &xwindow, xevent->xkey.time);
break; break;
@ -685,8 +741,11 @@ event_translate (ClutterBackend *backend,
* the next event and check if it's a KeyPress for the same key * the next event and check if it's a KeyPress for the same key
* and timestamp - and then ignore it if it matches the * and timestamp - and then ignore it if it matches the
* KeyRelease * 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; XEvent next_event;
@ -706,7 +765,7 @@ event_translate (ClutterBackend *backend,
clutter_device_manager_get_core_device (manager, clutter_device_manager_get_core_device (manager,
CLUTTER_KEYBOARD_DEVICE); CLUTTER_KEYBOARD_DEVICE);
translate_key_event (backend, event, xevent); translate_key_event (backend_x11, event, xevent);
break; break;
default: default:
@ -986,7 +1045,7 @@ event_translate (ClutterBackend *backend,
? CLUTTER_KEY_PRESS ? CLUTTER_KEY_PRESS
: CLUTTER_KEY_RELEASE; : CLUTTER_KEY_RELEASE;
translate_key_event (backend, event, &xevent_converted); translate_key_event (backend_x11, event, &xevent_converted);
if (xevent->type == key_press) if (xevent->type == key_press)
set_user_time (backend_x11, &xwindow, xkev->time); set_user_time (backend_x11, &xwindow, xkev->time);
@ -1031,10 +1090,8 @@ events_queue (ClutterBackend *backend)
g_queue_push_head (clutter_context->events_queue, event); g_queue_push_head (clutter_context->events_queue, event);
} }
else else
{
clutter_event_free (event); clutter_event_free (event);
} }
}
} }
/** /**
@ -1209,3 +1266,29 @@ clutter_x11_get_current_event_time (void)
return CLUTTER_BACKEND_X11 (backend)->last_event_time; 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;
}

View File

@ -0,0 +1,422 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "clutter-keymap-x11.h"
#include "clutter-backend-x11.h"
#include "clutter-debug.h"
#include "clutter-private.h"
#include <X11/Xatom.h>
#ifdef HAVE_XINPUT
#include <X11/extensions/XInput.h>
#endif
#ifdef HAVE_XKB
#include <X11/XKBlib.h>
#endif
typedef struct _ClutterKeymapX11Class ClutterKeymapX11Class;
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
guint caps_lock_state : 1;
guint num_lock_state : 1;
};
struct _ClutterKeymapX11Class
{
GObjectClass parent_class;
};
enum
{
PROP_0,
PROP_BACKEND
};
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 */
#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)
{
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;
XkbSelectEvents (backend_x11->xdpy,
XkbUseCoreKbd,
XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask,
XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask);
XkbSelectEventDetails (backend_x11->xdpy,
XkbUseCoreKbd, XkbStateNotify,
XkbAllStateComponentsMask,
XkbGroupLockMask|XkbModifierLockMask);
clutter_x11_add_filter (xkb_filter, backend_x11);
/* 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,
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)
{
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);
}
static void
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;
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 (ClutterKeymapX11 *keymap,
ClutterModifierType state)
{
#ifdef HAVE_XKB
return XkbGroupForCoreState (state);
#else
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;
}
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;
}

View File

@ -0,0 +1,53 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
*/
#ifndef __CLUTTER_KEYMAP_X11_H__
#define __CLUTTER_KEYMAP_X11_H__
#include <glib-object.h>
#include <clutter/clutter-event.h>
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 (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
#endif /* __CLUTTER_KEYMAP_X11_H__ */

View File

@ -141,6 +141,8 @@ gboolean clutter_x11_get_use_argb_visual (void);
Time clutter_x11_get_current_event_time (void); Time clutter_x11_get_current_event_time (void);
gint clutter_x11_event_get_key_group (const ClutterEvent *event);
G_END_DECLS G_END_DECLS
#endif /* __CLUTTER_X11_H__ */ #endif /* __CLUTTER_X11_H__ */

View File

@ -692,7 +692,7 @@ AS_IF([test "x$SUPPORT_XLIB" = "x1"],
[yes], [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_LIBS="$X11_LIBS -lXi"
X11_PC_FILES="$X11_PC_FILES xi" X11_PC_FILES="$X11_PC_FILES xi"
@ -702,6 +702,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 x11_tests=yes
BACKEND_PC_FILES="$BACKEND_PC_FILES $X11_PC_FILES" BACKEND_PC_FILES="$BACKEND_PC_FILES $X11_PC_FILES"
FLAVOUR_LIBS="$FLAVOUR_LIBS $X11_LIBS" FLAVOUR_LIBS="$FLAVOUR_LIBS $X11_LIBS"
@ -1144,6 +1161,7 @@ fi
if test "x$SUPPORT_XLIB" = "x1"; then if test "x$SUPPORT_XLIB" = "x1"; then
echo " Enable XInput 1.0: ${xinput}" echo " Enable XInput 1.0: ${xinput}"
echo " Enable XKB: ${have_xkb}"
echo " Enable X11 tests: ${x11_tests}" echo " Enable X11 tests: ${x11_tests}"
fi fi