From a32735e9a7bc537430d155a4af853d498dda2009 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Wed, 24 Jan 2018 16:16:17 -0500 Subject: [PATCH] efl-wl: create and maintain xserver-based keymap and keyboard states under x11 when run in a non-wayland environment, it's necessary to do some extra work in order to guarantee that the keymap remains the same in the compositor as in the xserver and to also guarantee that modifier states are accurately applied even when the compositor is not actively focused fix T6631 --- configure.ac | 1 + src/lib/efl_wl/copiedfromweston.x | 50 +++++++++++++ src/lib/efl_wl/efl_wl.c | 57 ++++++++++----- src/lib/efl_wl/x11.x | 118 ++++++++++++++++++++++++++++-- 4 files changed, 201 insertions(+), 25 deletions(-) diff --git a/configure.ac b/configure.ac index 8043adfecf..196ca21334 100644 --- a/configure.ac +++ b/configure.ac @@ -3807,6 +3807,7 @@ EFL_OPTIONAL_INTERNAL_DEPEND_PKG([EFL_WL], [${want_x11_any}], [ecore_x]) EFL_DEPEND_PKG([EFL_WL], [WAYLAND], [wayland-server >= 1.11.0 xkbcommon >= 0.6.0]) +EFL_OPTIONAL_DEPEND_PKG([EFL_WL], [${want_x11_any}], [XKBCOMMONX11], [xkbcommon-x11]) EFL_EVAL_PKGS([EFL_WL]) diff --git a/src/lib/efl_wl/copiedfromweston.x b/src/lib/efl_wl/copiedfromweston.x index 0b1388b064..17a31cbe55 100644 --- a/src/lib/efl_wl/copiedfromweston.x +++ b/src/lib/efl_wl/copiedfromweston.x @@ -356,3 +356,53 @@ drag_grab_button(Comp_Seat *s, #endif } } + +#ifdef HAVE_ECORE_X +static xkb_mod_index_t x11_kbd_shift_mod; +static xkb_mod_index_t x11_kbd_caps_mod; +static xkb_mod_index_t x11_kbd_ctrl_mod; +static xkb_mod_index_t x11_kbd_alt_mod; +static xkb_mod_index_t x11_kbd_mod2_mod; +static xkb_mod_index_t x11_kbd_mod3_mod; +static xkb_mod_index_t x11_kbd_super_mod; +static xkb_mod_index_t x11_kbd_mod5_mod; + +static void +keymap_mods_init(struct xkb_keymap *keymap) +{ + x11_kbd_shift_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); + x11_kbd_caps_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); + x11_kbd_ctrl_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL); + x11_kbd_alt_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT); + x11_kbd_mod2_mod = xkb_keymap_mod_get_index(keymap, "Mod2"); + x11_kbd_mod3_mod = xkb_keymap_mod_get_index(keymap, "Mod3"); + x11_kbd_super_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_LOGO); + x11_kbd_mod5_mod = xkb_keymap_mod_get_index(keymap, "Mod5"); +} + +static uint32_t +get_xkb_mod_mask(uint32_t in) +{ + uint32_t ret = 0; + + if ((in & ECORE_X_MODIFIER_SHIFT) && x11_kbd_shift_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_shift_mod); + if ((in & ECORE_X_LOCK_CAPS) && x11_kbd_caps_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_caps_mod); + if ((in & ECORE_X_MODIFIER_CTRL) && x11_kbd_ctrl_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_ctrl_mod); + if ((in & ECORE_X_MODIFIER_ALT) && x11_kbd_alt_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_alt_mod); + if ((in & ECORE_X_LOCK_NUM) && x11_kbd_mod2_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_mod2_mod); + if ((in & ECORE_X_LOCK_SCROLL) && x11_kbd_mod3_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_mod3_mod); + if ((in & ECORE_X_MODIFIER_WIN) && x11_kbd_super_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_super_mod); + if ((in & ECORE_X_MODIFIER_ALTGR) && x11_kbd_mod5_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_mod5_mod); + + return ret; +} + +#endif diff --git a/src/lib/efl_wl/efl_wl.c b/src/lib/efl_wl/efl_wl.c index d6622ef8dd..fd02aed44a 100644 --- a/src/lib/efl_wl/efl_wl.c +++ b/src/lib/efl_wl/efl_wl.c @@ -3710,26 +3710,32 @@ seat_keymap_update(Comp_Seat *s) Eina_Tmpstr *file; xkb_mod_mask_t latched = 0, locked = 0; - if (s->kbd.keymap_mem) munmap(s->kbd.keymap_mem, s->kbd.keymap_mem_size); - if (s->kbd.keymap_fd > -1) close(s->kbd.keymap_fd); - - if (s->kbd.state) +#ifdef HAVE_ECORE_X + if (!x11_kbd_keymap) { - latched = xkb_state_serialize_mods(s->kbd.state, XKB_STATE_MODS_LATCHED); - locked = xkb_state_serialize_mods(s->kbd.state, XKB_STATE_MODS_LOCKED); - xkb_state_unref(s->kbd.state); - } - if (!s->kbd.keymap) - { - s->kbd.state = NULL; - s->kbd.keymap_fd = -1; - s->kbd.keymap_mem = NULL; - return; - } +#endif + if (s->kbd.keymap_mem) munmap(s->kbd.keymap_mem, s->kbd.keymap_mem_size); + if (s->kbd.keymap_fd > -1) close(s->kbd.keymap_fd); - s->kbd.state = xkb_state_new(s->kbd.keymap); - xkb_state_update_mask(s->kbd.state, 0, latched, locked, 0, 0, 0); + if (s->kbd.state) + { + latched = xkb_state_serialize_mods(s->kbd.state, XKB_STATE_MODS_LATCHED); + locked = xkb_state_serialize_mods(s->kbd.state, XKB_STATE_MODS_LOCKED); + xkb_state_unref(s->kbd.state); + } + if (!s->kbd.keymap) + { + s->kbd.state = NULL; + s->kbd.keymap_fd = -1; + s->kbd.keymap_mem = NULL; + return; + } + s->kbd.state = xkb_state_new(s->kbd.keymap); + xkb_state_update_mask(s->kbd.state, 0, latched, locked, 0, 0, 0); +#ifdef HAVE_ECORE_X + } +#endif str = xkb_map_get_as_string(s->kbd.keymap); s->kbd.keymap_mem_size = strlen(str) + 1; s->kbd.keymap_fd = eina_file_mkstemp("comp-keymapXXXXXX", &file); @@ -4395,6 +4401,11 @@ comp_device_caps_update(Comp_Seat *s) { if (s->keyboard) { +#ifdef HAVE_ECORE_X + if ((!s->c->parent_disp) && ecore_x_display_get()) + x11_kbd_apply(s); + else +#endif seat_keymap_create(s); seat_kbd_repeat_rate_update(s); } @@ -4462,9 +4473,16 @@ comp_seats_proxy(Comp *c) if (s->kbd.keymap) xkb_keymap_ref(s->kbd.keymap); } else - seat_keymap_create(s); - seat_kbd_repeat_rate_update(s); + { +#ifdef HAVE_ECORE_X + if ((!s->c->parent_disp) && ecore_x_display_get()) + x11_kbd_apply(s); + else +#endif + seat_keymap_create(s); + } seat_keymap_update(s); + seat_kbd_repeat_rate_update(s); s->keyboard = !!s->kbd.state; } } @@ -5339,6 +5357,7 @@ comp_smart_add(Evas_Object *obj) #ifdef HAVE_ECORE_X if (ecore_x_display_get()) { + ecore_x_xkb_track_state(); // if proxiedallowed ecore_x_dnd_aware_set(ecore_evas_window_get(ecore_evas_ecore_evas_get(c->evas)), EINA_TRUE); if (!comps) x11_init(); diff --git a/src/lib/efl_wl/x11.x b/src/lib/efl_wl/x11.x index bebd017519..2d7a88352f 100644 --- a/src/lib/efl_wl/x11.x +++ b/src/lib/efl_wl/x11.x @@ -1,3 +1,5 @@ +#include "xkbcommon/xkbcommon-x11.h" + #define WL_TEXT_STR "text/plain;charset=utf-8" #define INCR_CHUNK_SIZE 1 << 17 @@ -562,6 +564,99 @@ x11_dnd_move(void *data, Ecore_X_Xdnd_Position *pos) evas_object_move(data, pos->position.x, pos->position.y); } +static int32_t x11_core_device = -1; +static struct xkb_context *x11_kbd_context; +static struct xkb_keymap *x11_kbd_keymap; +static struct xkb_state *x11_kbd_state; + +static Eina_Bool seat_kbd_mods_update(Comp_Seat *s); +static void comp_seat_send_modifiers(Comp_Seat *s, struct wl_resource *res, uint32_t serial); + +static Eina_Bool +x11_xkb_state(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_X_Event_Xkb *ev) +{ + Comp *c; + Eina_List *l; + Comp_Seat *s; + + if (!xkb_state_update_mask(x11_kbd_state, + get_xkb_mod_mask(ev->base_mods), + get_xkb_mod_mask(ev->latched_mods), + get_xkb_mod_mask(ev->locked_mods), + 0, + 0, + ev->group)) return ECORE_CALLBACK_RENEW; + EINA_LIST_FOREACH(comps, l, c) + EINA_INLIST_FOREACH(c->seats, s) + { + Eina_List *ll, *lll; + uint32_t serial; + struct wl_resource *res; + + seat_kbd_mods_update(s); + ll = seat_kbd_active_resources_get(s); + if (!ll) continue; + serial = wl_display_next_serial(s->c->display); + EINA_LIST_FOREACH(ll, lll, res) + comp_seat_send_modifiers(s, res, serial); + } + return ECORE_CALLBACK_RENEW; +} + +static void +x11_kbd_destroy(void) +{ + if (x11_kbd_state) xkb_state_unref(x11_kbd_state); + x11_kbd_state = NULL; + if (x11_kbd_keymap) xkb_keymap_unref(x11_kbd_keymap); + x11_kbd_keymap = NULL; + if (x11_kbd_context) xkb_context_unref(x11_kbd_context); + x11_kbd_context = NULL; +} + +static void +x11_kbd_create(void) +{ + Ecore_X_Connection *conn = ecore_x_connection_get(); + + x11_kbd_destroy(); + + x11_kbd_context = xkb_context_new(0); + x11_core_device = xkb_x11_get_core_keyboard_device_id(conn); + x11_kbd_keymap = xkb_x11_keymap_new_from_device(x11_kbd_context, conn, x11_core_device, 0); + x11_kbd_state = xkb_x11_state_new_from_device(x11_kbd_keymap, conn, x11_core_device); + keymap_mods_init(x11_kbd_keymap); +} + +static void +x11_kbd_apply(Comp_Seat *s) +{ + if (!x11_kbd_state) x11_kbd_create(); + s->kbd.context = x11_kbd_context; + s->kbd.keymap = x11_kbd_keymap; + s->kbd.state = x11_kbd_state; +} + +static void seat_keymap_update(Comp_Seat *s); + +static Eina_Bool +x11_xkb_refresh() +{ + Eina_List *l; + Comp *c; + Comp_Seat *s; + + x11_kbd_create(); + EINA_LIST_FOREACH(comps, l, c) + EINA_INLIST_FOREACH(c->seats, s) + { + if (!s->keyboard) continue; + x11_kbd_apply(s); + seat_keymap_update(s); + } + return ECORE_CALLBACK_RENEW; +} + static void x11_init(void) { @@ -589,18 +684,29 @@ x11_init(void) handlers = eina_list_append(handlers, h); h = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, (Ecore_Event_Handler_Cb)x11_dnd_mouse_up, NULL); handlers = eina_list_append(handlers, h); - xconvertselection = dlsym(NULL, "XConvertSelection"); - string_atom = ecore_x_atom_get("UTF8_STRING"); - timestamp_atom = ecore_x_atom_get("TIMESTAMP"); - int_atom = ecore_x_atom_get("INTEGER"); - incr_atom = ecore_x_atom_get("TIMESTAMP"); - comp_dnd_atom = ecore_x_atom_get("SIRCMPWIDG_ATOM"); + h = ecore_event_handler_add(ECORE_X_EVENT_XKB_STATE_NOTIFY, (Ecore_Event_Handler_Cb)x11_xkb_state, NULL); + handlers = eina_list_append(handlers, h); + h = ecore_event_handler_add(ECORE_X_EVENT_XKB_NEWKBD_NOTIFY, (Ecore_Event_Handler_Cb)x11_xkb_refresh, NULL); + handlers = eina_list_append(handlers, h); + if (!xconvertselection) + { + xconvertselection = dlsym(NULL, "XConvertSelection"); + string_atom = ecore_x_atom_get("UTF8_STRING"); + timestamp_atom = ecore_x_atom_get("TIMESTAMP"); + int_atom = ecore_x_atom_get("INTEGER"); + incr_atom = ecore_x_atom_get("TIMESTAMP"); + comp_dnd_atom = ecore_x_atom_get("SIRCMPWIDG_ATOM"); + ecore_x_xkb_track_state(); + } + pipes = eina_hash_int32_new((Eina_Free_Cb)_pipe_free); } static void x11_shutdown(void) { + x11_core_device = -1; + x11_kbd_destroy(); eina_hash_free(pipes); pipes = NULL; }