mirror of
https://github.com/brl/mutter.git
synced 2024-11-28 19:10:43 -05:00
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
This commit is contained in:
parent
78fcfec5c1
commit
9db02a7379
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
@ -559,12 +583,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);
|
||||
|
||||
@ -652,3 +670,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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user