From 3f617631cb68c0e90a755b86f9c241caf0080f9a Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Fri, 13 Mar 2020 20:22:59 +0100 Subject: [PATCH] Send keyboard enter/leave on capability change This is more correct according to the protocol and fixes issues with clients that wait for an enter event before processing key events --- include/types/wlr_seat.h | 2 ++ types/seat/wlr_seat.c | 13 ++++++++++ types/seat/wlr_seat_keyboard.c | 45 ++++++++++++++++++++++++++-------- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/include/types/wlr_seat.h b/include/types/wlr_seat.h index 2a3cd69b..f96db148 100644 --- a/include/types/wlr_seat.h +++ b/include/types/wlr_seat.h @@ -15,6 +15,8 @@ void seat_client_destroy_pointer(struct wl_resource *resource); void seat_client_create_keyboard(struct wlr_seat_client *seat_client, uint32_t version, uint32_t id); void seat_client_destroy_keyboard(struct wl_resource *resource); +void seat_client_send_keyboard_leave_raw(struct wlr_seat_client *seat_client, + struct wlr_surface *surface); void seat_client_create_touch(struct wlr_seat_client *seat_client, uint32_t version, uint32_t id); diff --git a/types/seat/wlr_seat.c b/types/seat/wlr_seat.c index b6b58c91..a9507069 100644 --- a/types/seat/wlr_seat.c +++ b/types/seat/wlr_seat.c @@ -322,6 +322,19 @@ void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat, } } if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) == 0) { + struct wlr_seat_client *focused_client = + wlr_seat->keyboard_state.focused_client; + struct wlr_surface *focused_surface = + wlr_seat->keyboard_state.focused_surface; + + if (focused_client != NULL && focused_surface != NULL) { + seat_client_send_keyboard_leave_raw(focused_client, + focused_surface); + } + + // Note: we don't set focused client/surface to NULL since we need + // them to send the enter event if the keyboard is recreated + struct wl_resource *resource, *tmp; wl_resource_for_each_safe(resource, tmp, &client->keyboards) { seat_client_destroy_keyboard(resource); diff --git a/types/seat/wlr_seat_keyboard.c b/types/seat/wlr_seat_keyboard.c index 52a4222a..93e259c9 100644 --- a/types/seat/wlr_seat_keyboard.c +++ b/types/seat/wlr_seat_keyboard.c @@ -218,6 +218,18 @@ void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat, } } +void seat_client_send_keyboard_leave_raw(struct wlr_seat_client *seat_client, + struct wlr_surface *surface) { + uint32_t serial = wlr_seat_client_next_serial(seat_client); + struct wl_resource *resource; + wl_resource_for_each(resource, &seat_client->keyboards) { + if (seat_client_from_keyboard_resource(resource) == NULL) { + continue; + } + wl_keyboard_send_leave(resource, serial, surface->resource); + } +} + void wlr_seat_keyboard_enter(struct wlr_seat *seat, struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes, struct wlr_keyboard_modifiers *modifiers) { @@ -240,14 +252,7 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat, // leave the previously entered surface if (focused_client != NULL && focused_surface != NULL) { - uint32_t serial = wlr_seat_client_next_serial(focused_client); - struct wl_resource *resource; - wl_resource_for_each(resource, &focused_client->keyboards) { - if (seat_client_from_keyboard_resource(resource) == NULL) { - continue; - } - wl_keyboard_send_leave(resource, serial, focused_surface->resource); - } + seat_client_send_keyboard_leave_raw(focused_client, focused_surface); } // enter the current surface @@ -409,8 +414,28 @@ void seat_client_create_keyboard(struct wlr_seat_client *seat_client, seat_client_send_keymap(seat_client, keyboard); seat_client_send_repeat_info(seat_client, keyboard); - // TODO possibly handle the case where this keyboard needs an enter - // right away + struct wlr_seat_client *focused_client = + seat_client->seat->keyboard_state.focused_client; + struct wlr_surface *focused_surface = + seat_client->seat->keyboard_state.focused_surface; + + // Send an enter event if there is a focused client/surface stored + if (focused_client != NULL && focused_surface != NULL) { + struct wl_array keys; + wl_array_init(&keys); + uint32_t serial = wlr_seat_client_next_serial(focused_client); + struct wl_resource *resource; + wl_resource_for_each(resource, &focused_client->keyboards) { + if (wl_resource_get_id(resource) == id) { + if (seat_client_from_keyboard_resource(resource) == NULL) { + continue; + } + wl_keyboard_send_enter(resource, serial, + focused_surface->resource, &keys); + } + } + wl_array_release(&keys); + } } void seat_client_destroy_keyboard(struct wl_resource *resource) {