diff --git a/src/backends/x11/cm/meta-backend-x11-cm.c b/src/backends/x11/cm/meta-backend-x11-cm.c index ac9fc25fb..814ca61c0 100644 --- a/src/backends/x11/cm/meta-backend-x11-cm.c +++ b/src/backends/x11/cm/meta-backend-x11-cm.c @@ -21,6 +21,11 @@ #include "backends/x11/cm/meta-backend-x11-cm.h" +#include +#include +#include +#include + #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; diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c index 92a13dcfa..0fd7e7767 100644 --- a/src/backends/x11/meta-backend-x11.c +++ b/src/backends/x11/meta-backend-x11.c @@ -34,7 +34,6 @@ #include #include -#include #include #include @@ -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; } diff --git a/src/backends/x11/meta-backend-x11.h b/src/backends/x11/meta-backend-x11.h index 9c163eb6b..cfd5bd7cb 100644 --- a/src/backends/x11/meta-backend-x11.h +++ b/src/backends/x11/meta-backend-x11.h @@ -27,6 +27,7 @@ #include "backends/meta-backend-private.h" +#include #include #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 */ diff --git a/src/backends/x11/nested/meta-backend-x11-nested.c b/src/backends/x11/nested/meta-backend-x11-nested.c index cf9cea747..022599449 100644 --- a/src/backends/x11/nested/meta-backend-x11-nested.c +++ b/src/backends/x11/nested/meta-backend-x11-nested.c @@ -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;