backends/x11: Only apply keymap when not running nested

https://bugzilla.gnome.org/show_bug.cgi?id=777800
This commit is contained in:
Jonas Ådahl 2017-01-31 22:09:02 +08:00
parent 6d64123849
commit bd2ca79a48
4 changed files with 244 additions and 190 deletions

View File

@ -21,6 +21,11 @@
#include "backends/x11/cm/meta-backend-x11-cm.h"
#include <stdlib.h>
#include <X11/XKBlib.h>
#include <X11/extensions/XKBrules.h>
#include <xkbcommon/xkbcommon-x11.h>
#include "backends/meta-backend-private.h"
#include "backends/x11/meta-cursor-renderer-x11.h"
#include "backends/x11/meta-monitor-manager-xrandr.h"
@ -28,10 +33,18 @@
struct _MetaBackendX11Cm
{
MetaBackendX11 parent;
char *keymap_layouts;
char *keymap_variants;
char *keymap_options;
int locked_group;
};
G_DEFINE_TYPE (MetaBackendX11Cm, meta_backend_x11_cm, META_TYPE_BACKEND_X11)
static void
apply_keymap (MetaBackendX11 *x11);
static void
take_touch_grab (MetaBackend *backend)
{
@ -50,6 +63,17 @@ take_touch_grab (MetaBackend *backend)
False, &mask, 1, &mods);
}
static void
on_device_added (ClutterDeviceManager *device_manager,
ClutterInputDevice *device,
gpointer user_data)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (user_data);
if (clutter_input_device_get_device_type (device) == CLUTTER_KEYBOARD_DEVICE)
apply_keymap (x11);
}
static void
meta_backend_x11_cm_post_init (MetaBackend *backend)
{
@ -58,6 +82,10 @@ meta_backend_x11_cm_post_init (MetaBackend *backend)
parent_backend_class->post_init (backend);
g_signal_connect_object (clutter_device_manager_get_default (),
"device-added",
G_CALLBACK (on_device_added), backend, 0);
take_touch_grab (backend);
}
@ -107,15 +135,202 @@ meta_backend_x11_cm_select_stage_events (MetaBackend *backend)
XISelectEvents (xdisplay, xwin, &mask, 1);
}
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
apply_keymap (MetaBackendX11 *x11)
{
MetaBackendX11Cm *x11_cm = META_BACKEND_X11_CM (x11);
Display *xdisplay = meta_backend_x11_get_xdisplay (x11);
XkbRF_RulesRec *xkb_rules;
XkbRF_VarDefsRec xkb_var_defs = { 0 };
char *rules_file_path;
if (!x11_cm->keymap_layouts ||
!x11_cm->keymap_variants ||
!x11_cm->keymap_options)
return;
get_xkbrf_var_defs (xdisplay,
x11_cm->keymap_layouts,
x11_cm->keymap_variants,
x11_cm->keymap_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 (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 void
meta_backend_x11_cm_set_keymap (MetaBackend *backend,
const char *layouts,
const char *variants,
const char *options)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Cm *x11_cm = META_BACKEND_X11_CM (x11);
g_free (x11_cm->keymap_layouts);
x11_cm->keymap_layouts = g_strdup (layouts);
g_free (x11_cm->keymap_variants);
x11_cm->keymap_variants = g_strdup (variants);
g_free (x11_cm->keymap_options);
x11_cm->keymap_options = g_strdup (options);
apply_keymap (x11);
}
static void
meta_backend_x11_cm_lock_layout_group (MetaBackend *backend,
guint idx)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Cm *x11_cm = META_BACKEND_X11_CM (x11);
Display *xdisplay = meta_backend_x11_get_xdisplay (x11);
x11_cm->locked_group = idx;
XkbLockGroup (xdisplay, XkbUseCoreKbd, idx);
}
static gboolean
meta_backend_x11_cm_handle_host_xevent (MetaBackendX11 *backend_x11,
XEvent *event)
{
MetaBackend *backend = META_BACKEND (backend_x11);
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Cm *x11_cm = META_BACKEND_X11_CM (x11);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaMonitorManagerXrandr *monitor_manager_xrandr =
META_MONITOR_MANAGER_XRANDR (monitor_manager);
Display *xdisplay = meta_backend_x11_get_xdisplay (x11);
if (event->type == meta_backend_x11_get_xkb_event_base (x11))
{
XkbEvent *xkb_ev = (XkbEvent *) event;
if (xkb_ev->any.device == META_VIRTUAL_CORE_KEYBOARD_ID)
{
switch (xkb_ev->any.xkb_type)
{
case XkbStateNotify:
if (xkb_ev->state.changed & XkbGroupLockMask)
{
if (x11_cm->locked_group != xkb_ev->state.locked_group)
XkbLockGroup (xdisplay, XkbUseCoreKbd,
x11_cm->locked_group);
}
break;
default:
break;
}
}
}
return meta_monitor_manager_xrandr_handle_xevent (monitor_manager_xrandr,
event);
@ -169,6 +384,8 @@ meta_backend_x11_cm_class_init (MetaBackendX11CmClass *klass)
backend_class->create_cursor_renderer = meta_backend_x11_cm_create_cursor_renderer;
backend_class->update_screen_size = meta_backend_x11_cm_update_screen_size;
backend_class->select_stage_events = meta_backend_x11_cm_select_stage_events;
backend_class->lock_layout_group = meta_backend_x11_cm_lock_layout_group;
backend_class->set_keymap = meta_backend_x11_cm_set_keymap;
backend_x11_class->handle_host_xevent = meta_backend_x11_cm_handle_host_xevent;
backend_x11_class->translate_device_event = meta_backend_x11_cm_translate_device_event;

View File

@ -34,7 +34,6 @@
#include <X11/extensions/sync.h>
#include <X11/XKBlib.h>
#include <X11/extensions/XKBrules.h>
#include <X11/Xlib-xcb.h>
#include <xkbcommon/xkbcommon-x11.h>
@ -67,17 +66,11 @@ struct _MetaBackendX11Private
uint8_t xkb_error_base;
struct xkb_keymap *keymap;
gchar *keymap_layouts;
gchar *keymap_variants;
gchar *keymap_options;
int locked_group;
MetaLogicalMonitor *cached_current_logical_monitor;
};
typedef struct _MetaBackendX11Private MetaBackendX11Private;
static void apply_keymap (MetaBackendX11 *x11);
G_DEFINE_TYPE_WITH_PRIVATE (MetaBackendX11, meta_backend_x11, META_TYPE_BACKEND);
static void
@ -283,13 +276,6 @@ handle_host_xevent (MetaBackend *backend,
case XkbMapNotify:
keymap_changed (backend);
break;
case XkbStateNotify:
if (xkb_ev->state.changed & XkbGroupLockMask)
{
if (priv->locked_group != xkb_ev->state.locked_group)
XkbLockGroup (priv->xdisplay, XkbUseCoreKbd, priv->locked_group);
}
break;
default:
break;
}
@ -383,17 +369,6 @@ x_event_source_new (MetaBackend *backend)
return source;
}
static void
on_device_added (ClutterDeviceManager *device_manager,
ClutterInputDevice *device,
gpointer user_data)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (user_data);
if (clutter_input_device_get_device_type (device) == CLUTTER_KEYBOARD_DEVICE)
apply_keymap (x11);
}
static void
on_monitors_changed (MetaMonitorManager *manager,
MetaBackend *backend)
@ -450,9 +425,6 @@ meta_backend_x11_post_init (MetaBackend *backend)
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);
g_signal_connect_object (clutter_device_manager_get_default (), "device-added",
G_CALLBACK (on_device_added), backend, 0);
META_BACKEND_CLASS (meta_backend_x11_parent_class)->post_init (backend);
monitor_manager = meta_backend_get_monitor_manager (backend);
@ -567,155 +539,6 @@ meta_backend_x11_get_current_logical_monitor (MetaBackend *backend)
return priv->cached_current_logical_monitor;
}
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
apply_keymap (MetaBackendX11 *x11)
{
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
XkbRF_RulesRec *xkb_rules;
XkbRF_VarDefsRec xkb_var_defs = { 0 };
gchar *rules_file_path;
if (!priv->keymap_layouts ||
!priv->keymap_variants ||
!priv->keymap_options)
return;
get_xkbrf_var_defs (priv->xdisplay,
priv->keymap_layouts,
priv->keymap_variants,
priv->keymap_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 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);
g_free (priv->keymap_layouts);
priv->keymap_layouts = g_strdup (layouts);
g_free (priv->keymap_variants);
priv->keymap_variants = g_strdup (variants);
g_free (priv->keymap_options);
priv->keymap_options = g_strdup (options);
apply_keymap (x11);
}
static struct xkb_keymap *
meta_backend_x11_get_keymap (MetaBackend *backend)
{
@ -738,17 +561,6 @@ meta_backend_x11_get_keymap (MetaBackend *backend)
return priv->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);
priv->locked_group = idx;
XkbLockGroup (priv->xdisplay, XkbUseCoreKbd, idx);
}
static void
meta_backend_x11_set_numlock (MetaBackend *backend,
gboolean numlock_state)
@ -765,6 +577,14 @@ meta_backend_x11_handle_event (MetaBackendX11 *x11,
priv->cached_current_logical_monitor = NULL;
}
uint8_t
meta_backend_x11_get_xkb_event_base (MetaBackendX11 *x11)
{
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
return priv->xkb_event_base;
}
static void
meta_backend_x11_class_init (MetaBackendX11Class *klass)
{
@ -778,9 +598,7 @@ meta_backend_x11_class_init (MetaBackendX11Class *klass)
backend_class->ungrab_device = meta_backend_x11_ungrab_device;
backend_class->warp_pointer = meta_backend_x11_warp_pointer;
backend_class->get_current_logical_monitor = meta_backend_x11_get_current_logical_monitor;
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;
backend_class->set_numlock = meta_backend_x11_set_numlock;
}

View File

@ -27,6 +27,7 @@
#include "backends/meta-backend-private.h"
#include <stdint.h>
#include <X11/Xlib.h>
#include "backends/x11/meta-clutter-backend-x11.h"
@ -54,4 +55,6 @@ Window meta_backend_x11_get_xwindow (MetaBackendX11 *backend);
void meta_backend_x11_handle_event (MetaBackendX11 *x11,
XEvent *xevent);
uint8_t meta_backend_x11_get_xkb_event_base (MetaBackendX11 *x11);
#endif /* META_BACKEND_X11_H */

View File

@ -105,6 +105,20 @@ meta_backend_x11_nested_select_stage_events (MetaBackend *backend)
xwa.your_event_mask | FocusChangeMask | KeymapStateMask);
}
static void
meta_backend_x11_nested_lock_layout_group (MetaBackend *backend,
guint idx)
{
}
static void
meta_backend_x11_nested_set_keymap (MetaBackend *backend,
const char *layouts,
const char *variants,
const char *options)
{
}
static gboolean
meta_backend_x11_nested_handle_host_xevent (MetaBackendX11 *x11,
XEvent *event)
@ -162,6 +176,8 @@ meta_backend_x11_nested_class_init (MetaBackendX11NestedClass *klass)
backend_class->create_cursor_renderer = meta_backend_x11_nested_create_cursor_renderer;
backend_class->update_screen_size = meta_backend_x11_nested_update_screen_size;
backend_class->select_stage_events = meta_backend_x11_nested_select_stage_events;
backend_class->lock_layout_group = meta_backend_x11_nested_lock_layout_group;
backend_class->set_keymap = meta_backend_x11_nested_set_keymap;
backend_x11_class->handle_host_xevent = meta_backend_x11_nested_handle_host_xevent;
backend_x11_class->translate_device_event = meta_backend_x11_nested_translate_device_event;