From 10fc36614f1613f60d861815ce43a383d0f3826e Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Tue, 23 Jan 2018 16:49:52 -0500 Subject: [PATCH] efl-wl: add functionality for directly passing through xkb objects when used in enlightenment, it's necessary to be able to directly use the compositor's keyboard state to ensure consistency when keypress events are not propagated @feature --- src/lib/efl_wl/Efl_Wl.h | 27 ++++ src/lib/efl_wl/efl_wl.c | 347 ++++++++++++++++++++++++++++------------ 2 files changed, 273 insertions(+), 101 deletions(-) diff --git a/src/lib/efl_wl/Efl_Wl.h b/src/lib/efl_wl/Efl_Wl.h index eb9e57938e..d27dedde28 100644 --- a/src/lib/efl_wl/Efl_Wl.h +++ b/src/lib/efl_wl/Efl_Wl.h @@ -160,6 +160,33 @@ EAPI Evas_Object *efl_wl_extracted_surface_object_find(void *surface_resource); * @since 1.21 */ EAPI Evas_Object *efl_wl_extracted_surface_extracted_parent_get(Evas_Object *surface); + +/** + * Set external xkbcommon resources to be used read-only by the compositor object + * + * Use this function if you have available the necessary xkbcommon objects which are used + * to handle keyboard states in a compositor. The passed objects will not be modified or copied, + * so this function must be called again in the case that the compositor widget outlives the + * lifetime of any of the passed pointers. + * + * @param obj The compositor widget + * @param seat The seat to set the keymap for, NULL to set the keymap for all seats + * @param keymap The xkb_keymap object to use + * @param state The xkb_state object to use + * @param fd The fd created from a mmapped xkb_keymap + * @param size The size of the xkb_keymap memory + * @param wl_key_array A pointer to the wl_array in which keys are stored + * @since 1.21 + */ +EAPI void efl_wl_seat_keymap_set(Evas_Object *obj, Eo *seat, void *state, int fd, size_t size, void *wl_key_array); + +/** + * Set the key repeat rate for a seat in the compositor + * + * @param obj The compositor widget + * @since 1.21 + */ +EAPI void efl_wl_seat_key_repeat_set(Evas_Object *obj, Eo *seat, int repeat_rate, int repeat_delay); #endif #endif diff --git a/src/lib/efl_wl/efl_wl.c b/src/lib/efl_wl/efl_wl.c index 12b2fa81f6..6967efc635 100644 --- a/src/lib/efl_wl/efl_wl.c +++ b/src/lib/efl_wl/efl_wl.c @@ -193,6 +193,7 @@ typedef struct Comp_Seat struct { struct wl_array keys; + struct wl_array *keys_external; struct { xkb_mod_mask_t depressed; @@ -211,6 +212,7 @@ typedef struct Comp_Seat int repeat_delay; Eina_Hash *resources; Comp_Surface *enter; + Eina_Bool external : 1; } kbd; struct @@ -3650,13 +3652,64 @@ seat_update_caps(Comp_Seat *s, struct wl_resource *res) wl_seat_send_capabilities(res, caps); } +static void +seat_keymap_send(Comp_Seat *s) +{ + Eina_List *l; + Eina_Iterator *it; + it = eina_hash_iterator_data_new(s->kbd.resources); + EINA_ITERATOR_FOREACH(it, l) + { + Eina_List *ll; + struct wl_resource *res; + EINA_LIST_FOREACH(l, ll, res) + wl_keyboard_send_keymap(res, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, s->kbd.keymap_fd, s->kbd.keymap_mem_size); + } + eina_iterator_free(it); +} + +static Eina_Bool +seat_kbd_mods_update(Comp_Seat *s) +{ + xkb_mod_mask_t mod; + xkb_layout_index_t grp; + + mod = xkb_state_serialize_mods(s->kbd.state, XKB_STATE_DEPRESSED); + s->kbd.mods.changed |= mod != s->kbd.mods.depressed; + s->kbd.mods.depressed = mod; + mod = xkb_state_serialize_mods(s->kbd.state, XKB_STATE_MODS_LATCHED); + s->kbd.mods.changed |= mod != s->kbd.mods.latched; + s->kbd.mods.latched = mod; + mod = xkb_state_serialize_mods(s->kbd.state, XKB_STATE_MODS_LOCKED); + s->kbd.mods.changed |= mod != s->kbd.mods.locked; + s->kbd.mods.locked = mod; + grp = xkb_state_serialize_layout(s->kbd.state, XKB_STATE_LAYOUT_EFFECTIVE); + s->kbd.mods.changed |= grp != s->kbd.mods.group; + s->kbd.mods.group = grp; + return s->kbd.mods.changed; +} + +static void +seat_kbd_external_init(Comp_Seat *s) +{ + Eina_List *l, *ll; + uint32_t serial; + struct wl_resource *res; + + seat_keymap_send(s); + if (!seat_kbd_mods_update(s)) return; + l = seat_kbd_active_resources_get(s); + if (!l) return; + serial = wl_display_next_serial(s->c->display); + EINA_LIST_FOREACH(l, ll, res) + comp_seat_send_modifiers(s, res, serial); +} + static void seat_keymap_update(Comp_Seat *s) { char *str; Eina_Tmpstr *file; - Eina_List *l; - Eina_Iterator *it; xkb_mod_mask_t latched = 0, locked = 0; if (s->kbd.keymap_mem) munmap(s->kbd.keymap_mem, s->kbd.keymap_mem_size); @@ -3710,15 +3763,7 @@ seat_keymap_update(Comp_Seat *s) s->kbd.keymap_mem[s->kbd.keymap_mem_size] = 0; free(str); - it = eina_hash_iterator_data_new(s->kbd.resources); - EINA_ITERATOR_FOREACH(it, l) - { - Eina_List *ll; - struct wl_resource *res; - EINA_LIST_FOREACH(l, ll, res) - wl_keyboard_send_keymap(res, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, s->kbd.keymap_fd, s->kbd.keymap_mem_size); - } - eina_iterator_free(it); + seat_keymap_send(s); } static inline void @@ -3756,27 +3801,6 @@ seat_keymap_create(Comp_Seat *s) s->kbd.keymap = xkb_map_new_from_names(s->kbd.context, &names, 0); } -static Eina_Bool -seat_mods_update(Comp_Seat *s) -{ - xkb_mod_mask_t mod; - xkb_layout_index_t grp; - - mod = xkb_state_serialize_mods(s->kbd.state, XKB_STATE_DEPRESSED); - s->kbd.mods.changed |= mod != s->kbd.mods.depressed; - s->kbd.mods.depressed = mod; - mod = xkb_state_serialize_mods(s->kbd.state, XKB_STATE_MODS_LATCHED); - s->kbd.mods.changed |= mod != s->kbd.mods.latched; - s->kbd.mods.latched = mod; - mod = xkb_state_serialize_mods(s->kbd.state, XKB_STATE_MODS_LOCKED); - s->kbd.mods.changed |= mod != s->kbd.mods.locked; - s->kbd.mods.locked = mod; - grp = xkb_state_serialize_layout(s->kbd.state, XKB_STATE_LAYOUT_EFFECTIVE); - s->kbd.mods.changed |= grp != s->kbd.mods.group; - s->kbd.mods.group = grp; - return s->kbd.mods.changed; -} - static const struct wl_keyboard_interface seat_kbd_interface = { resource_destroy @@ -4017,6 +4041,18 @@ seat_resource_hash_free(Eina_Hash *h) eina_hash_free(h); } +static void +seat_kbd_destroy(Comp_Seat *s) +{ + if (s->kbd.external) return; + if (s->kbd.state) xkb_state_unref(s->kbd.state); + if (s->kbd.keymap) xkb_keymap_unref(s->kbd.keymap); + if (s->kbd.context) xkb_context_unref(s->kbd.context); + 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); + wl_array_release(&s->kbd.keys); +} + static void seat_destroy(Comp_Seat *s) { @@ -4027,12 +4063,7 @@ seat_destroy(Comp_Seat *s) while (s->resources) wl_resource_destroy(eina_list_data_get(s->resources)); eina_stringshare_del(s->name); - if (s->kbd.state) xkb_state_unref(s->kbd.state); - if (s->kbd.keymap) xkb_keymap_unref(s->kbd.keymap); - if (s->kbd.context) xkb_context_unref(s->kbd.context); - 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); - wl_array_release(&s->kbd.keys); + seat_kbd_destroy(s); efl_unref(s->dev); s->c->seats = eina_inlist_remove(s->c->seats, EINA_INLIST_GET(s)); eina_hash_free(s->data_devices); @@ -4345,18 +4376,23 @@ comp_device_caps_update(Comp_Seat *s) } if (s->keyboard != kbd) { - if (s->keyboard) - { - seat_keymap_create(s); - seat_kbd_repeat_rate_update(s); - } + if (s->kbd.external) + seat_kbd_external_init(s); else { - xkb_keymap_unref(s->kbd.keymap); - s->kbd.keymap = NULL; + if (s->keyboard) + { + seat_keymap_create(s); + seat_kbd_repeat_rate_update(s); + } + else + { + xkb_keymap_unref(s->kbd.keymap); + s->kbd.keymap = NULL; + } + seat_keymap_update(s); + s->keyboard = !!s->kbd.state; } - seat_keymap_update(s); - s->keyboard = !!s->kbd.state; } seat_update_caps(s, NULL); } @@ -4403,22 +4439,28 @@ comp_seats_proxy(Comp *c) s->touch = !!(caps & ECORE_WL2_SEAT_CAPABILITIES_TOUCH); if (s->keyboard) { - if (s->seat) - { - s->kbd.keymap = ecore_wl2_input_keymap_get(s->seat); - if (s->kbd.keymap) xkb_keymap_ref(s->kbd.keymap); - } + if (s->kbd.external) + seat_kbd_external_init(s); else - seat_keymap_create(s); - seat_kbd_repeat_rate_update(s); - seat_keymap_update(s); - s->keyboard = !!s->kbd.state; + { + if (s->seat) + { + s->kbd.keymap = ecore_wl2_input_keymap_get(s->seat); + if (s->kbd.keymap) xkb_keymap_ref(s->kbd.keymap); + } + else + seat_keymap_create(s); + seat_kbd_repeat_rate_update(s); + seat_keymap_update(s); + s->keyboard = !!s->kbd.state; + } } } else if (!c->parent_disp) comp_device_caps_update(s); s->global = wl_global_create(c->display, &wl_seat_interface, 4, s, seat_bind); + evas_object_smart_callback_call(s->c->obj, "seat_added", dev); if (ecore_wl2_display_sync_is_done(c->client_disp)) seat_proxy_update(s); } @@ -4508,18 +4550,23 @@ comp_seat_caps_handler(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Wl2_Event_S s->pointer = ev->pointer_enabled; if (s->keyboard != ev->keyboard_enabled) { - if (ev->keyboard_enabled) - { - s->kbd.keymap = ecore_wl2_input_keymap_get(s->seat); - if (s->kbd.keymap) xkb_keymap_ref(s->kbd.keymap); - seat_kbd_repeat_rate_update(s); - } + if (s->kbd.external) + seat_kbd_external_init(s); else { - xkb_keymap_unref(s->kbd.keymap); - s->kbd.keymap = NULL; + if (ev->keyboard_enabled) + { + s->kbd.keymap = ecore_wl2_input_keymap_get(s->seat); + if (s->kbd.keymap) xkb_keymap_ref(s->kbd.keymap); + seat_kbd_repeat_rate_update(s); + } + else + { + xkb_keymap_unref(s->kbd.keymap); + s->kbd.keymap = NULL; + } + seat_keymap_update(s); } - seat_keymap_update(s); } s->keyboard = !!ev->keyboard_enabled && !!s->kbd.state; s->touch = ev->touch_enabled; @@ -4569,6 +4616,7 @@ comp_seat_keymap_changed(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Wl2_Event { struct xkb_keymap *keymap; + if (s->kbd.external) continue; if (ecore_wl2_input_seat_id_get(s->seat) != ev->id) continue; if (s->kbd.keymap) xkb_map_unref(s->kbd.keymap); @@ -4585,6 +4633,21 @@ comp_seat_keymap_changed(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Wl2_Event return ECORE_CALLBACK_RENEW; } +static void +seat_kbd_repeat_rate_send(Comp_Seat *s) +{ + Eina_List *ll, *lll; + struct wl_resource *res; + Eina_Iterator *it; + + it = eina_hash_iterator_data_new(s->kbd.resources); + EINA_ITERATOR_FOREACH(it, ll) + EINA_LIST_FOREACH(ll, lll, res) + if (wl_resource_get_version(res) >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) + wl_keyboard_send_repeat_info(res, s->kbd.repeat_rate, s->kbd.repeat_delay); + eina_iterator_free(it); +} + static Eina_Bool comp_seat_keyboard_repeat_changed(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Wl2_Event_Seat_Keyboard_Repeat_Changed *ev) { @@ -4596,36 +4659,23 @@ comp_seat_keyboard_repeat_changed(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_ if (c->parent_disp == ev->display) EINA_INLIST_FOREACH(c->seats, s) { - Eina_List *ll, *lll; - struct wl_resource *res; - Eina_Iterator *it; - if (ecore_wl2_input_seat_id_get(s->seat) != ev->id) continue; + if (s->kbd.external) continue; seat_kbd_repeat_rate_update(s); - it = eina_hash_iterator_data_new(s->kbd.resources); - EINA_ITERATOR_FOREACH(it, ll) - EINA_LIST_FOREACH(ll, lll, res) - if (wl_resource_get_version(res) >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) - wl_keyboard_send_repeat_info(res, s->kbd.repeat_rate, s->kbd.repeat_delay); - eina_iterator_free(it); + seat_kbd_repeat_rate_send(s); } return ECORE_CALLBACK_RENEW; } static void -comp_seat_key_update(Comp_Seat *s, xkb_keycode_t key, int dir, unsigned int timestamp) +comp_seat_key_send(Comp_Seat *s, xkb_keycode_t key, int dir, unsigned int timestamp, Eina_Bool mods) { Eina_List *l, *ll; struct wl_resource *res; uint32_t serial = wl_display_next_serial(s->c->display); - uint32_t xkb[] = { XKB_KEY_DOWN, XKB_KEY_UP }; uint32_t wl[] = { WL_KEYBOARD_KEY_STATE_PRESSED, WL_KEYBOARD_KEY_STATE_RELEASED }; - Eina_Bool mods = EINA_FALSE; - if (xkb_state_update_key(s->kbd.state, key + 8, xkb[dir])) - mods = seat_mods_update(s); - if (!s->focused) return; l = seat_kbd_active_resources_get(s); EINA_LIST_FOREACH(l, ll, res) @@ -4635,6 +4685,18 @@ comp_seat_key_update(Comp_Seat *s, xkb_keycode_t key, int dir, unsigned int time } } +static void +comp_seat_key_update(Comp_Seat *s, xkb_keycode_t key, int dir, unsigned int timestamp) +{ + uint32_t xkb[] = { XKB_KEY_DOWN, XKB_KEY_UP }; + Eina_Bool mods = EINA_FALSE; + + if (s->kbd.external || xkb_state_update_key(s->kbd.state, key + 8, xkb[dir])) + mods = seat_kbd_mods_update(s); + if (s->focused) + comp_seat_key_send(s, key, dir, timestamp, mods); +} + static Eina_Bool comp_key_down(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Key *ev) { @@ -4648,17 +4710,25 @@ comp_key_down(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Key *ev) EINA_LIST_FOREACH(comps, l, c) EINA_INLIST_FOREACH(c->seats, s) { - uint32_t *end, *k; - if (c->parent_disp && (dev != s->dev)) continue; - end = (uint32_t*)s->kbd.keys.data + (s->kbd.keys.size / sizeof(uint32_t)); - for (k = s->kbd.keys.data; k < end; k++) - if (*k == keycode) return ECORE_CALLBACK_RENEW; + if (s->kbd.external) + { + /* only doing passthrough in external mode */ + if (!s->focused) return ECORE_CALLBACK_RENEW; + } + else + { + uint32_t *end, *k; - s->kbd.keys.size = (char*)end - (char*)s->kbd.keys.data; - k = wl_array_add(&s->kbd.keys, sizeof(uint32_t)); - *k = keycode; + end = (uint32_t*)s->kbd.keys.data + (s->kbd.keys.size / sizeof(uint32_t)); + for (k = s->kbd.keys.data; k < end; k++) + if (*k == keycode) return ECORE_CALLBACK_RENEW; + + s->kbd.keys.size = (char*)end - (char*)s->kbd.keys.data; + k = wl_array_add(&s->kbd.keys, sizeof(uint32_t)); + *k = keycode; + } comp_seat_key_update(s, keycode, 0, ev->timestamp); } return ECORE_CALLBACK_RENEW; @@ -4677,19 +4747,27 @@ comp_key_up(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Key *ev) EINA_LIST_FOREACH(comps, l, c) EINA_INLIST_FOREACH(c->seats, s) { - uint32_t *end, *k; - if (c->parent_disp && (dev != s->dev)) continue; - end = (uint32_t*)s->kbd.keys.data + (s->kbd.keys.size / sizeof(uint32_t)); - for (k = s->kbd.keys.data; k < end; k++) - if (*k == keycode) - { - *k = end[-1]; - s->kbd.keys.size = (char*)end - (char*)s->kbd.keys.data - 1; - break; - } + if (s->kbd.external) + { + /* only doing passthrough in external mode */ + if (!s->focused) return ECORE_CALLBACK_RENEW; + } + else + { + uint32_t *end, *k; + end = (uint32_t*)s->kbd.keys.data + (s->kbd.keys.size / sizeof(uint32_t)); + + for (k = s->kbd.keys.data; k < end; k++) + if (*k == keycode) + { + *k = end[-1]; + s->kbd.keys.size = (char*)end - (char*)s->kbd.keys.data - 1; + break; + } + } comp_seat_key_update(s, keycode, 1, ev->timestamp); } return ECORE_CALLBACK_RENEW; @@ -4939,8 +5017,27 @@ comp_focus_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, voi s->focused = 1; if (s->selection_changed) comp_seat_selection_update(s); - if (!s->kbd.keymap) continue; - if (!seat_mods_update(s)) continue; + if ((!s->kbd.keymap) && (!s->kbd.state)) continue; + if (s->kbd.external) + { + Eina_Bool mods = seat_kbd_mods_update(s); + if (!s->focused) return; + l = seat_kbd_active_resources_get(s); + + EINA_LIST_FOREACH(l, ll, res) + { + uint32_t *end, *k; + serial = wl_display_next_serial(s->c->display); + + end = (uint32_t*)s->kbd.keys_external->data + (s->kbd.keys_external->size / sizeof(uint32_t)); + if (mods) comp_seat_send_modifiers(s, res, serial); + + for (k = s->kbd.keys_external->data; k < end; k++) + comp_seat_key_send(s, *k, 0, 0, mods); + } + return; + } + if (!seat_kbd_mods_update(s)) continue; l = seat_kbd_active_resources_get(s); if (!l) continue; serial = wl_display_next_serial(s->c->display); @@ -5738,3 +5835,51 @@ efl_wl_extracted_surface_extracted_parent_get(Evas_Object *surface) } return NULL; } + +void +efl_wl_seat_keymap_set(Evas_Object *obj, Eo *seat, void *state, int fd, size_t size, void *key_array) +{ + Comp *c; + Comp_Seat *s; + + if (!eina_streq(evas_object_type_get(obj), "comp")) abort(); + c = evas_object_smart_data_get(obj); + EINA_INLIST_FOREACH(c->seats, s) + { + if (!seat) efl_wl_seat_keymap_set(obj, s->dev, state, fd, size, key_array); + else if (s->dev == seat) break; + } + if (!seat) return; + EINA_SAFETY_ON_NULL_RETURN(s); + seat_kbd_destroy(s); + s->kbd.external = 1; + s->kbd.keys_external = key_array; + s->kbd.state = state; + s->kbd.keymap_fd = fd; + s->kbd.keymap_mem_size = size; + s->kbd.context = NULL; + s->kbd.keymap = NULL; + s->kbd.keymap_mem = NULL; + if (s->keyboard) + seat_kbd_external_init(s); +} + +void +efl_wl_seat_key_repeat_set(Evas_Object *obj, Eo *seat, int repeat_rate, int repeat_delay) +{ + Comp *c; + Comp_Seat *s; + + if (!eina_streq(evas_object_type_get(obj), "comp")) abort(); + c = evas_object_smart_data_get(obj); + EINA_INLIST_FOREACH(c->seats, s) + { + if (!seat) efl_wl_seat_key_repeat_set(obj, s->dev, repeat_rate, repeat_delay); + else if (s->dev == seat) break; + } + if (!seat) return; + EINA_SAFETY_ON_NULL_RETURN(s); + s->kbd.repeat_rate = repeat_rate; + s->kbd.repeat_delay = repeat_delay; + seat_kbd_repeat_rate_send(s); +}