summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRui Matos <tiagomatos@gmail.com>2014-08-04 16:47:35 +0200
committerRui Matos <tiagomatos@gmail.com>2014-08-07 11:24:24 +0200
commit101b215d6b7f0fba0c6b6ab8dee8d4fa121a9311 (patch)
tree939729558b0e446eb634350a884083c83828d55c
parent6af48de0b8c1d12ee90b9b81a5065eb66f54cc08 (diff)
downloadmutter-101b215d6b7f0fba0c6b6ab8dee8d4fa121a9311.tar.gz
backends: Add methods to handle keymaps
These methods allow us to set and get xkbcommon keymaps as well as locking a specific layout in a layout group. With this, we introduce dependencies on xkeyboard-config, xkbfile, xkbcommon-x11 and a libX11 new enough to have xcb support. https://bugzilla.gnome.org/show_bug.cgi?id=734301
-rw-r--r--configure.ac6
-rw-r--r--src/backends/meta-backend-private.h13
-rw-r--r--src/backends/meta-backend.c23
-rw-r--r--src/backends/meta-backend.h12
-rw-r--r--src/backends/native/meta-backend-native.c46
-rw-r--r--src/backends/x11/meta-backend-x11.c182
6 files changed, 282 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index b5bbc2fd2..246314058 100644
--- a/configure.ac
+++ b/configure.ac
@@ -87,6 +87,9 @@ MUTTER_PC_MODULES="
wayland-server >= 1.5.90
upower-glib >= 0.99.0
gnome-desktop-3.0
+ xkbfile
+ xkeyboard-config
+ xkbcommon-x11
"
GLIB_GSETTINGS
@@ -235,6 +238,9 @@ if test x$have_xinerama = xno; then
AC_MSG_ERROR([Xinerama extension was not found])
fi
+AC_DEFINE_UNQUOTED([XKB_BASE], ["`$PKG_CONFIG --variable xkb_base xkeyboard-config`"],
+ [XKB base dir])
+
RANDR_LIBS=
found_randr=no
AC_CHECK_LIB(Xrandr, XRRUpdateConfiguration,
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
index 02b123d5f..5b15781cf 100644
--- a/src/backends/meta-backend-private.h
+++ b/src/backends/meta-backend-private.h
@@ -30,6 +30,9 @@
#include "meta-backend.h"
+#define DEFAULT_XKB_RULES_FILE "evdev"
+#define DEFAULT_XKB_MODEL "pc105+inet"
+
#define META_TYPE_BACKEND (meta_backend_get_type ())
#define META_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_BACKEND, MetaBackend))
#define META_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_BACKEND, MetaBackendClass))
@@ -66,6 +69,16 @@ struct _MetaBackendClass
void (* warp_pointer) (MetaBackend *backend,
int x,
int y);
+
+ void (* set_keymap) (MetaBackend *backend,
+ const char *layouts,
+ const char *variants,
+ const char *options);
+
+ struct xkb_keymap * (* get_keymap) (MetaBackend *backend);
+
+ void (* lock_layout_group) (MetaBackend *backend,
+ guint idx);
};
#endif /* META_BACKEND_PRIVATE_H */
diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
index 3cfb95110..976d19e44 100644
--- a/src/backends/meta-backend.c
+++ b/src/backends/meta-backend.c
@@ -200,6 +200,29 @@ meta_backend_warp_pointer (MetaBackend *backend,
META_BACKEND_GET_CLASS (backend)->warp_pointer (backend, x, y);
}
+void
+meta_backend_set_keymap (MetaBackend *backend,
+ const char *layouts,
+ const char *variants,
+ const char *options)
+{
+ META_BACKEND_GET_CLASS (backend)->set_keymap (backend, layouts, variants, options);
+}
+
+struct xkb_keymap *
+meta_backend_get_keymap (MetaBackend *backend)
+
+{
+ return META_BACKEND_GET_CLASS (backend)->get_keymap (backend);
+}
+
+void
+meta_backend_lock_layout_group (MetaBackend *backend,
+ guint idx)
+{
+ META_BACKEND_GET_CLASS (backend)->lock_layout_group (backend, idx);
+}
+
static GType
get_backend_type (void)
{
diff --git a/src/backends/meta-backend.h b/src/backends/meta-backend.h
index f93b6f6cb..f4eab5562 100644
--- a/src/backends/meta-backend.h
+++ b/src/backends/meta-backend.h
@@ -27,6 +27,8 @@
#include <glib-object.h>
+#include <xkbcommon/xkbcommon.h>
+
#include <meta/meta-idle-monitor.h>
#include "meta-monitor-manager.h"
#include "meta-cursor-renderer.h"
@@ -54,6 +56,16 @@ void meta_backend_warp_pointer (MetaBackend *backend,
int x,
int y);
+void meta_backend_set_keymap (MetaBackend *backend,
+ const char *layouts,
+ const char *variants,
+ const char *options);
+
+struct xkb_keymap * meta_backend_get_keymap (MetaBackend *backend);
+
+void meta_backend_lock_layout_group (MetaBackend *backend,
+ guint idx);
+
void meta_clutter_init (void);
#endif /* META_BACKEND_H */
diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c
index e21788020..60f039ef6 100644
--- a/src/backends/native/meta-backend-native.c
+++ b/src/backends/native/meta-backend-native.c
@@ -189,6 +189,49 @@ meta_backend_native_warp_pointer (MetaBackend *backend,
}
static void
+meta_backend_native_set_keymap (MetaBackend *backend,
+ const char *layouts,
+ const char *variants,
+ const char *options)
+{
+ ClutterDeviceManager *manager = clutter_device_manager_get_default ();
+ struct xkb_rule_names names;
+ struct xkb_keymap *keymap;
+ struct xkb_context *context;
+
+ names.rules = DEFAULT_XKB_RULES_FILE;
+ names.model = DEFAULT_XKB_MODEL;
+ names.layout = layouts;
+ names.variant = variants;
+ names.options = options;
+
+ context = xkb_context_new (XKB_CONTEXT_NO_FLAGS);
+ keymap = xkb_keymap_new_from_names (context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
+ xkb_context_unref (context);
+
+ clutter_evdev_set_keyboard_map (manager, keymap);
+
+ /* FIXME: emit keymap changed signal */
+
+ xkb_keymap_unref (keymap);
+}
+
+static struct xkb_keymap *
+meta_backend_native_get_keymap (MetaBackend *backend)
+{
+ ClutterDeviceManager *manager = clutter_device_manager_get_default ();
+ return clutter_evdev_get_keyboard_map (manager);
+}
+
+static void
+meta_backend_native_lock_layout_group (MetaBackend *backend,
+ guint idx)
+{
+ ClutterDeviceManager *manager = clutter_device_manager_get_default ();
+ clutter_evdev_set_keyboard_layout_index (manager, idx);
+}
+
+static void
meta_backend_native_class_init (MetaBackendNativeClass *klass)
{
MetaBackendClass *backend_class = META_BACKEND_CLASS (klass);
@@ -199,6 +242,9 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass)
backend_class->create_cursor_renderer = meta_backend_native_create_cursor_renderer;
backend_class->warp_pointer = meta_backend_native_warp_pointer;
+ backend_class->set_keymap = meta_backend_native_set_keymap;
+ backend_class->get_keymap = meta_backend_native_get_keymap;
+ backend_class->lock_layout_group = meta_backend_native_lock_layout_group;
}
static void
diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
index 913e00a00..5e8c25a05 100644
--- a/src/backends/x11/meta-backend-x11.c
+++ b/src/backends/x11/meta-backend-x11.c
@@ -24,11 +24,18 @@
#include "config.h"
+#include <string.h>
+#include <stdlib.h>
+
#include "meta-backend-x11.h"
#include <clutter/x11/clutter-x11.h>
#include <X11/extensions/sync.h>
+#include <X11/XKBlib.h>
+#include <X11/extensions/XKBrules.h>
+#include <X11/Xlib-xcb.h>
+#include <xkbcommon/xkbcommon-x11.h>
#include "meta-idle-monitor-xsync.h"
#include "meta-monitor-manager-xrandr.h"
@@ -43,6 +50,7 @@ struct _MetaBackendX11Private
{
/* The host X11 display */
Display *xdisplay;
+ xcb_connection_t *xcb;
GSource *source;
int xsync_event_base;
@@ -52,6 +60,9 @@ struct _MetaBackendX11Private
int xinput_event_base;
int xinput_error_base;
Time latest_evtime;
+
+ uint8_t xkb_event_base;
+ uint8_t xkb_error_base;
};
typedef struct _MetaBackendX11Private MetaBackendX11Private;
@@ -320,6 +331,17 @@ meta_backend_x11_post_init (MetaBackend *backend)
take_touch_grab (backend);
+ priv->xcb = XGetXCBConnection (priv->xdisplay);
+ if (!xkb_x11_setup_xkb_extension (priv->xcb,
+ XKB_X11_MIN_MAJOR_XKB_VERSION,
+ XKB_X11_MIN_MINOR_XKB_VERSION,
+ XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS,
+ NULL, NULL,
+ &priv->xkb_event_base,
+ &priv->xkb_error_base))
+ meta_fatal ("X server doesn't have the XKB extension, version %d.%d or newer\n",
+ XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION);
+
META_BACKEND_CLASS (meta_backend_x11_parent_class)->post_init (backend);
}
@@ -414,6 +436,163 @@ meta_backend_x11_warp_pointer (MetaBackend *backend,
}
static void
+get_xkbrf_var_defs (Display *xdisplay,
+ const char *layouts,
+ const char *variants,
+ const char *options,
+ char **rules_p,
+ XkbRF_VarDefsRec *var_defs)
+{
+ char *rules = NULL;
+
+ /* Get it from the X property or fallback on defaults */
+ if (!XkbRF_GetNamesProp (xdisplay, &rules, var_defs) || !rules)
+ {
+ rules = strdup (DEFAULT_XKB_RULES_FILE);
+ var_defs->model = strdup (DEFAULT_XKB_MODEL);
+ var_defs->layout = NULL;
+ var_defs->variant = NULL;
+ var_defs->options = NULL;
+ }
+
+ /* Swap in our new options... */
+ free (var_defs->layout);
+ var_defs->layout = strdup (layouts);
+ free (var_defs->variant);
+ var_defs->variant = strdup (variants);
+ free (var_defs->options);
+ var_defs->options = strdup (options);
+
+ /* Sometimes, the property is a file path, and sometimes it's
+ not. Normalize it so it's always a file path. */
+ if (rules[0] == '/')
+ *rules_p = g_strdup (rules);
+ else
+ *rules_p = g_build_filename (XKB_BASE, "rules", rules, NULL);
+
+ free (rules);
+}
+
+static void
+free_xkbrf_var_defs (XkbRF_VarDefsRec *var_defs)
+{
+ free (var_defs->model);
+ free (var_defs->layout);
+ free (var_defs->variant);
+ free (var_defs->options);
+}
+
+static void
+free_xkb_component_names (XkbComponentNamesRec *p)
+{
+ free (p->keymap);
+ free (p->keycodes);
+ free (p->types);
+ free (p->compat);
+ free (p->symbols);
+ free (p->geometry);
+}
+
+static void
+upload_xkb_description (Display *xdisplay,
+ const gchar *rules_file_path,
+ XkbRF_VarDefsRec *var_defs,
+ XkbComponentNamesRec *comp_names)
+{
+ XkbDescRec *xkb_desc;
+ gchar *rules_file;
+
+ /* Upload it to the X server using the same method as setxkbmap */
+ xkb_desc = XkbGetKeyboardByName (xdisplay,
+ XkbUseCoreKbd,
+ comp_names,
+ XkbGBN_AllComponentsMask,
+ XkbGBN_AllComponentsMask &
+ (~XkbGBN_GeometryMask), True);
+ if (!xkb_desc)
+ {
+ g_warning ("Couldn't upload new XKB keyboard description");
+ return;
+ }
+
+ XkbFreeKeyboard (xkb_desc, 0, True);
+
+ rules_file = g_path_get_basename (rules_file_path);
+
+ if (!XkbRF_SetNamesProp (xdisplay, rules_file, var_defs))
+ g_warning ("Couldn't update the XKB root window property");
+
+ g_free (rules_file);
+}
+
+static void
+meta_backend_x11_set_keymap (MetaBackend *backend,
+ const char *layouts,
+ const char *variants,
+ const char *options)
+{
+ MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
+ MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
+ XkbRF_RulesRec *xkb_rules;
+ XkbRF_VarDefsRec xkb_var_defs = { 0 };
+ gchar *rules_file_path;
+
+ get_xkbrf_var_defs (priv->xdisplay,
+ layouts,
+ variants,
+ options,
+ &rules_file_path,
+ &xkb_var_defs);
+
+ xkb_rules = XkbRF_Load (rules_file_path, NULL, True, True);
+ if (xkb_rules)
+ {
+ XkbComponentNamesRec xkb_comp_names = { 0 };
+
+ XkbRF_GetComponents (xkb_rules, &xkb_var_defs, &xkb_comp_names);
+ upload_xkb_description (priv->xdisplay, rules_file_path, &xkb_var_defs, &xkb_comp_names);
+
+ free_xkb_component_names (&xkb_comp_names);
+ XkbRF_Free (xkb_rules, True);
+ }
+ else
+ {
+ g_warning ("Couldn't load XKB rules");
+ }
+
+ free_xkbrf_var_defs (&xkb_var_defs);
+ g_free (rules_file_path);
+}
+
+static struct xkb_keymap *
+meta_backend_x11_get_keymap (MetaBackend *backend)
+{
+ MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
+ MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
+ struct xkb_keymap *keymap;
+ struct xkb_context *context;
+
+ context = xkb_context_new (XKB_CONTEXT_NO_FLAGS);
+ keymap = xkb_x11_keymap_new_from_device (context,
+ priv->xcb,
+ xkb_x11_get_core_keyboard_device_id (priv->xcb),
+ XKB_KEYMAP_COMPILE_NO_FLAGS);
+ xkb_context_unref (context);
+
+ return keymap;
+}
+
+static void
+meta_backend_x11_lock_layout_group (MetaBackend *backend,
+ guint idx)
+{
+ MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
+ MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
+
+ XkbLockGroup (priv->xdisplay, XkbUseCoreKbd, idx);
+}
+
+static void
meta_backend_x11_class_init (MetaBackendX11Class *klass)
{
MetaBackendClass *backend_class = META_BACKEND_CLASS (klass);
@@ -426,6 +605,9 @@ meta_backend_x11_class_init (MetaBackendX11Class *klass)
backend_class->grab_device = meta_backend_x11_grab_device;
backend_class->ungrab_device = meta_backend_x11_ungrab_device;
backend_class->warp_pointer = meta_backend_x11_warp_pointer;
+ backend_class->set_keymap = meta_backend_x11_set_keymap;
+ backend_class->get_keymap = meta_backend_x11_get_keymap;
+ backend_class->lock_layout_group = meta_backend_x11_lock_layout_group;
}
static void