[mutter/wayland] wayland: sync the keymap from X to wayland
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wayland] wayland: sync the keymap from X to wayland
- Date: Wed, 13 Nov 2013 14:00:32 +0000 (UTC)
commit 93ae868987edc6f73dc07bc7e2d6721a653bd1e3
Author: Giovanni Campagna <gcampagn redhat com>
Date: Wed Sep 4 11:11:39 2013 +0200
wayland: sync the keymap from X to wayland
When X clients change the keyboard map, the also update a property
on the root window. We can notice that and rebuild our data structures
with the new values, as well as inform the wayland clients.
This is a terrible hack, and it's not how we want to implement things
in 3.12, but it's enough to have the same keyboard layout in the
shell, in X clients and in wayland clients in 3.10, until we decide
on the fate of the keyboard g-s-d plugin.
https://bugzilla.gnome.org/show_bug.cgi?id=707446
src/core/display.c | 38 +++++++++
src/core/xprops.c | 75 ++++++++++++++++++
src/core/xprops.h | 5 +
src/meta/atomnames.h | 1 +
src/wayland/meta-wayland-keyboard.c | 147 ++++++++++++++++++++++------------
src/wayland/meta-wayland-keyboard.h | 13 +++-
6 files changed, 226 insertions(+), 53 deletions(-)
---
diff --git a/src/core/display.c b/src/core/display.c
index 14ee96e..74193f4 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -2191,6 +2191,40 @@ handle_window_focus_event (MetaDisplay *display,
}
}
+static void
+reload_xkb_rules (MetaScreen *screen)
+{
+ MetaWaylandCompositor *compositor;
+ char **names;
+ int n_names;
+ gboolean ok;
+ const char *rules, *model, *layout, *variant, *options;
+
+ compositor = meta_wayland_compositor_get_default ();
+
+ ok = meta_prop_get_latin1_list (screen->display, screen->xroot,
+ screen->display->atom__XKB_RULES_NAMES,
+ &names, &n_names);
+ if (!ok)
+ return;
+
+ if (n_names != 5)
+ goto out;
+
+ rules = names[0];
+ model = names[1];
+ layout = names[2];
+ variant = names[3];
+ options = names[4];
+
+ meta_wayland_keyboard_set_keymap_names (&compositor->seat->keyboard,
+ rules, model, layout, variant, options,
+ META_WAYLAND_KEYBOARD_SKIP_XCLIENTS);
+
+ out:
+ g_strfreev (names);
+}
+
/**
* meta_display_handle_event:
* @display: The MetaDisplay that events are coming from
@@ -2964,6 +2998,10 @@ meta_display_handle_event (MetaDisplay *display,
else if (event->xproperty.atom ==
display->atom__NET_DESKTOP_NAMES)
meta_screen_update_workspace_names (screen);
+ else if (meta_is_wayland_compositor () &&
+ event->xproperty.atom ==
+ display->atom__XKB_RULES_NAMES)
+ reload_xkb_rules (screen);
#if 0
else if (event->xproperty.atom ==
display->atom__NET_RESTACK_WINDOW)
diff --git a/src/core/xprops.c b/src/core/xprops.c
index 844824f..040581c 100644
--- a/src/core/xprops.c
+++ b/src/core/xprops.c
@@ -536,6 +536,81 @@ meta_prop_get_utf8_list (MetaDisplay *display,
return utf8_list_from_results (&results, str_p, n_str_p);
}
+/* this one freakishly returns g_malloc memory */
+static gboolean
+latin1_list_from_results (GetPropertyResults *results,
+ char ***str_p,
+ int *n_str_p)
+{
+ int i;
+ int n_strings;
+ char **retval;
+ const char *p;
+
+ *str_p = NULL;
+ *n_str_p = 0;
+
+ if (!validate_or_free_results (results, 8, XA_STRING, FALSE))
+ return FALSE;
+
+ /* I'm not sure this is right, but I'm guessing the
+ * property is nul-separated
+ */
+ i = 0;
+ n_strings = 0;
+ while (i < (int) results->n_items)
+ {
+ if (results->prop[i] == '\0')
+ ++n_strings;
+ ++i;
+ }
+
+ if (results->prop[results->n_items - 1] != '\0')
+ ++n_strings;
+
+ /* we're guaranteed that results->prop has a nul on the end
+ * by XGetWindowProperty
+ */
+
+ retval = g_new0 (char*, n_strings + 1);
+
+ p = (char *)results->prop;
+ i = 0;
+ while (i < n_strings)
+ {
+ retval[i] = g_strdup (p);
+
+ p = p + strlen (p) + 1;
+ ++i;
+ }
+
+ *str_p = retval;
+ *n_str_p = i;
+
+ meta_XFree (results->prop);
+ results->prop = NULL;
+
+ return TRUE;
+}
+
+gboolean
+meta_prop_get_latin1_list (MetaDisplay *display,
+ Window xwindow,
+ Atom xatom,
+ char ***str_p,
+ int *n_str_p)
+{
+ GetPropertyResults results;
+
+ *str_p = NULL;
+
+ if (!get_property (display, xwindow, xatom,
+ XA_STRING, &results))
+ return FALSE;
+
+ return latin1_list_from_results (&results, str_p, n_str_p);
+}
+
void
meta_prop_set_utf8_string_hint (MetaDisplay *display,
Window xwindow,
diff --git a/src/core/xprops.h b/src/core/xprops.h
index 5a799f8..a5c4fb9 100644
--- a/src/core/xprops.h
+++ b/src/core/xprops.h
@@ -102,6 +102,11 @@ gboolean meta_prop_get_utf8_list (MetaDisplay *display,
Atom xatom,
char ***str_p,
int *n_str_p);
+gboolean meta_prop_get_latin1_list (MetaDisplay *display,
+ Window xwindow,
+ Atom xatom,
+ char ***str_p,
+ int *n_str_p);
void meta_prop_set_utf8_string_hint
(MetaDisplay *display,
Window xwindow,
diff --git a/src/meta/atomnames.h b/src/meta/atomnames.h
index d7a6e7e..43a18a9 100644
--- a/src/meta/atomnames.h
+++ b/src/meta/atomnames.h
@@ -81,6 +81,7 @@ item(TIMESTAMP)
item(VERSION)
item(ATOM_PAIR)
item(BACKLIGHT)
+item(_XKB_RULES_NAMES)
/* Oddities: These are used, and we need atoms for them,
* but when we need all _NET_WM hints (i.e. when we're making
diff --git a/src/wayland/meta-wayland-keyboard.c b/src/wayland/meta-wayland-keyboard.c
index 6e24e36..05db151 100644
--- a/src/wayland/meta-wayland-keyboard.c
+++ b/src/wayland/meta-wayland-keyboard.c
@@ -106,11 +106,49 @@ create_anonymous_file (off_t size,
return -1;
}
-static gboolean
-meta_wayland_xkb_info_new_keymap (MetaWaylandXkbInfo *xkb_info)
+static void
+inform_clients_of_new_keymap (MetaWaylandKeyboard *keyboard,
+ int flags)
{
+ MetaWaylandCompositor *compositor;
+ struct wl_client *xclient;
+ struct wl_resource *keyboard_resource;
+
+ compositor = meta_wayland_compositor_get_default ();
+ xclient = compositor->xwayland_client;
+
+ wl_resource_for_each (keyboard_resource, &keyboard->resource_list)
+ {
+ if ((flags & META_WAYLAND_KEYBOARD_SKIP_XCLIENTS) &&
+ wl_resource_get_client (keyboard_resource) == xclient)
+ continue;
+
+ wl_keyboard_send_keymap (keyboard_resource,
+ WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
+ keyboard->xkb_info.keymap_fd,
+ keyboard->xkb_info.keymap_size);
+ }
+}
+
+static void
+meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard,
+ struct xkb_keymap *keymap,
+ int flags)
+{
+ MetaWaylandXkbInfo *xkb_info = &keyboard->xkb_info;
GError *error = NULL;
char *keymap_str;
+ size_t previous_size;
+
+ if (keymap == NULL)
+ {
+ g_warning ("Attempting to set null keymap (compilation probably failed)");
+ return;
+ }
+
+ if (xkb_info->keymap)
+ xkb_keymap_unref (xkb_info->keymap);
+ xkb_info->keymap = keymap;
xkb_info->shift_mod =
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_SHIFT);
@@ -129,21 +167,28 @@ meta_wayland_xkb_info_new_keymap (MetaWaylandXkbInfo *xkb_info)
keymap_str = xkb_map_get_as_string (xkb_info->keymap);
if (keymap_str == NULL)
{
- g_warning ("failed to get string version of keymap\n");
- return FALSE;
+ g_warning ("failed to get string version of keymap");
+ return;
}
+ previous_size = xkb_info->keymap_size;
xkb_info->keymap_size = strlen (keymap_str) + 1;
+ if (xkb_info->keymap_fd >= 0)
+ close (xkb_info->keymap_fd);
+
xkb_info->keymap_fd = create_anonymous_file (xkb_info->keymap_size, &error);
if (xkb_info->keymap_fd < 0)
{
- g_warning ("creating a keymap file for %lu bytes failed: %s\n",
+ g_warning ("creating a keymap file for %lu bytes failed: %s",
(unsigned long) xkb_info->keymap_size,
error->message);
g_clear_error (&error);
goto err_keymap_str;
}
+ if (xkb_info->keymap_area)
+ munmap (xkb_info->keymap_area, previous_size);
+
xkb_info->keymap_area = mmap (NULL, xkb_info->keymap_size,
PROT_READ | PROT_WRITE,
MAP_SHARED, xkb_info->keymap_fd, 0);
@@ -156,41 +201,24 @@ meta_wayland_xkb_info_new_keymap (MetaWaylandXkbInfo *xkb_info)
strcpy (xkb_info->keymap_area, keymap_str);
free (keymap_str);
- return TRUE;
+ if (keyboard->is_evdev)
+ {
+ ClutterDeviceManager *manager;
+
+ manager = clutter_device_manager_get_default ();
+ clutter_evdev_set_keyboard_map (manager, xkb_info->keymap);
+ }
+
+ inform_clients_of_new_keymap (keyboard, flags);
+
+ return;
err_dev_zero:
close (xkb_info->keymap_fd);
xkb_info->keymap_fd = -1;
err_keymap_str:
free (keymap_str);
- return FALSE;
-}
-
-static gboolean
-meta_wayland_keyboard_build_global_keymap (struct xkb_context *xkb_context,
- struct xkb_rule_names *xkb_names,
- MetaWaylandXkbInfo *xkb_info)
-{
- xkb_info->keymap = xkb_map_new_from_names (xkb_context,
- xkb_names,
- 0 /* flags */);
- if (xkb_info->keymap == NULL)
- {
- g_warning ("failed to compile global XKB keymap\n"
- " tried rules %s, model %s, layout %s, variant %s, "
- "options %s\n",
- xkb_names->rules,
- xkb_names->model,
- xkb_names->layout,
- xkb_names->variant,
- xkb_names->options);
- return FALSE;
- }
-
- if (!meta_wayland_xkb_info_new_keymap (xkb_info))
- return FALSE;
-
- return TRUE;
+ return;
}
static void
@@ -306,9 +334,8 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
struct wl_display *display,
gboolean is_evdev)
{
- ClutterDeviceManager *manager;
-
memset (keyboard, 0, sizeof *keyboard);
+ keyboard->xkb_info.keymap_fd = -1;
wl_list_init (&keyboard->resource_list);
wl_array_init (&keyboard->keys);
@@ -320,18 +347,15 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
keyboard->display = display;
keyboard->xkb_context = xkb_context_new (0 /* flags */);
-
- meta_wayland_keyboard_build_global_keymap (keyboard->xkb_context,
- &keyboard->xkb_names,
- &keyboard->xkb_info);
-
keyboard->is_evdev = is_evdev;
- if (is_evdev)
- {
- manager = clutter_device_manager_get_default ();
- clutter_evdev_set_keyboard_map (manager, keyboard->xkb_info.keymap);
- }
+ /* Compute a default until gnome-settings-daemon starts and sets
+ the appropriate values
+ */
+ meta_wayland_keyboard_set_keymap_names (keyboard,
+ "evdev",
+ "pc105",
+ "us", "", "", 0);
return TRUE;
}
@@ -563,12 +587,6 @@ meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard)
void
meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
{
- g_free ((char *) keyboard->xkb_names.rules);
- g_free ((char *) keyboard->xkb_names.model);
- g_free ((char *) keyboard->xkb_names.layout);
- g_free ((char *) keyboard->xkb_names.variant);
- g_free ((char *) keyboard->xkb_names.options);
-
meta_wayland_xkb_info_destroy (&keyboard->xkb_info);
xkb_context_unref (keyboard->xkb_context);
@@ -656,3 +674,28 @@ meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard,
meta_verbose ("Released modal keyboard grab, timestamp %d\n", timestamp);
}
+
+void
+meta_wayland_keyboard_set_keymap_names (MetaWaylandKeyboard *keyboard,
+ const char *rules,
+ const char *model,
+ const char *layout,
+ const char *variant,
+ const char *options,
+ int flags)
+{
+ struct xkb_rule_names xkb_names;
+
+ xkb_names.rules = rules;
+ xkb_names.model = model;
+ xkb_names.layout = layout;
+ xkb_names.variant = variant;
+ xkb_names.options = options;
+
+ meta_wayland_keyboard_take_keymap (keyboard,
+ xkb_keymap_new_from_names (keyboard->xkb_context,
+ &xkb_names,
+ 0 /* flags */),
+ flags);
+}
+
diff --git a/src/wayland/meta-wayland-keyboard.h b/src/wayland/meta-wayland-keyboard.h
index adb3d44..4354faf 100644
--- a/src/wayland/meta-wayland-keyboard.h
+++ b/src/wayland/meta-wayland-keyboard.h
@@ -112,7 +112,6 @@ struct _MetaWaylandKeyboard
struct xkb_context *xkb_context;
gboolean is_evdev;
MetaWaylandXkbInfo xkb_info;
- struct xkb_rule_names xkb_names;
MetaWaylandKeyboardGrab input_method_grab;
struct wl_resource *input_method_resource;
@@ -123,6 +122,18 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
struct wl_display *display,
gboolean is_evdev);
+typedef enum {
+ META_WAYLAND_KEYBOARD_SKIP_XCLIENTS = 1,
+} MetaWaylandKeyboardSetKeymapFlags;
+
+void
+meta_wayland_keyboard_set_keymap_names (MetaWaylandKeyboard *keyboard,
+ const char *rules,
+ const char *model,
+ const char *layout,
+ const char *variant,
+ const char *options,
+ int flags);
gboolean
meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
const ClutterKeyEvent *event);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]