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
This commit is contained in:
Isaac Freund 2020-03-13 20:22:59 +01:00 committed by Drew DeVault
parent e0bbafc253
commit 3f617631cb
3 changed files with 50 additions and 10 deletions

View file

@ -15,6 +15,8 @@ void seat_client_destroy_pointer(struct wl_resource *resource);
void seat_client_create_keyboard(struct wlr_seat_client *seat_client, void seat_client_create_keyboard(struct wlr_seat_client *seat_client,
uint32_t version, uint32_t id); uint32_t version, uint32_t id);
void seat_client_destroy_keyboard(struct wl_resource *resource); 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, void seat_client_create_touch(struct wlr_seat_client *seat_client,
uint32_t version, uint32_t id); uint32_t version, uint32_t id);

View file

@ -322,6 +322,19 @@ void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat,
} }
} }
if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) == 0) { 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; struct wl_resource *resource, *tmp;
wl_resource_for_each_safe(resource, tmp, &client->keyboards) { wl_resource_for_each_safe(resource, tmp, &client->keyboards) {
seat_client_destroy_keyboard(resource); seat_client_destroy_keyboard(resource);

View file

@ -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, void wlr_seat_keyboard_enter(struct wlr_seat *seat,
struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes, struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
struct wlr_keyboard_modifiers *modifiers) { struct wlr_keyboard_modifiers *modifiers) {
@ -240,14 +252,7 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat,
// leave the previously entered surface // leave the previously entered surface
if (focused_client != NULL && focused_surface != NULL) { if (focused_client != NULL && focused_surface != NULL) {
uint32_t serial = wlr_seat_client_next_serial(focused_client); seat_client_send_keyboard_leave_raw(focused_client, focused_surface);
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);
}
} }
// enter the current 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_keymap(seat_client, keyboard);
seat_client_send_repeat_info(seat_client, keyboard); seat_client_send_repeat_info(seat_client, keyboard);
// TODO possibly handle the case where this keyboard needs an enter struct wlr_seat_client *focused_client =
// right away 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) { void seat_client_destroy_keyboard(struct wl_resource *resource) {