From 1282c3b12fc2c0dacf0c5df9b261dfc45046e7c6 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Fri, 13 Mar 2020 23:38:33 +0100 Subject: [PATCH] Send pointer 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 pointer events. --- include/types/wlr_seat.h | 2 ++ types/seat/wlr_seat.c | 12 +++++++++ types/seat/wlr_seat_pointer.c | 50 ++++++++++++++++++++++++++++------- 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/include/types/wlr_seat.h b/include/types/wlr_seat.h index f96db148..c39889b6 100644 --- a/include/types/wlr_seat.h +++ b/include/types/wlr_seat.h @@ -11,6 +11,8 @@ extern const struct wlr_touch_grab_interface default_touch_grab_impl; void seat_client_create_pointer(struct wlr_seat_client *seat_client, uint32_t version, uint32_t id); void seat_client_destroy_pointer(struct wl_resource *resource); +void seat_client_send_pointer_leave_raw(struct wlr_seat_client *seat_client, + struct wlr_surface *surface); void seat_client_create_keyboard(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 a9507069..d606c6a2 100644 --- a/types/seat/wlr_seat.c +++ b/types/seat/wlr_seat.c @@ -316,6 +316,18 @@ void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat, wl_list_for_each(client, &wlr_seat->clients, link) { // Make resources inert if necessary if ((capabilities & WL_SEAT_CAPABILITY_POINTER) == 0) { + struct wlr_seat_client *focused_client = + wlr_seat->pointer_state.focused_client; + struct wlr_surface *focused_surface = + wlr_seat->pointer_state.focused_surface; + + if (focused_client != NULL && focused_surface != NULL) { + seat_client_send_pointer_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 pointer is recreated + struct wl_resource *resource, *tmp; wl_resource_for_each_safe(resource, tmp, &client->pointers) { seat_client_destroy_pointer(resource); diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c index 2a43e61b..7ac21d0d 100644 --- a/types/seat/wlr_seat_pointer.c +++ b/types/seat/wlr_seat_pointer.c @@ -129,6 +129,20 @@ static void seat_pointer_handle_surface_destroy(struct wl_listener *listener, wlr_seat_pointer_clear_focus(state->seat); } +void seat_client_send_pointer_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->pointers) { + if (wlr_seat_client_from_pointer_resource(resource) == NULL) { + continue; + } + + wl_pointer_send_leave(resource, serial, surface->resource); + pointer_send_frame(resource); + } +} + void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, struct wlr_surface *surface, double sx, double sy) { if (wlr_seat->pointer_state.focused_surface == surface) { @@ -149,16 +163,7 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_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->pointers) { - if (wlr_seat_client_from_pointer_resource(resource) == NULL) { - continue; - } - - wl_pointer_send_leave(resource, serial, focused_surface->resource); - pointer_send_frame(resource); - } + seat_client_send_pointer_leave_raw(focused_client, focused_surface); } // enter the current surface @@ -404,6 +409,31 @@ void seat_client_create_pointer(struct wlr_seat_client *seat_client, wl_resource_set_implementation(resource, &pointer_impl, seat_client, &pointer_handle_resource_destroy); wl_list_insert(&seat_client->pointers, wl_resource_get_link(resource)); + + struct wlr_seat_client *focused_client = + seat_client->seat->pointer_state.focused_client; + struct wlr_surface *focused_surface = + seat_client->seat->pointer_state.focused_surface; + + // Send an enter event if there is a focused client/surface stored + if (focused_client != NULL && focused_surface != NULL) { + double sx = seat_client->seat->pointer_state.sx; + double sy = seat_client->seat->pointer_state.sy; + + uint32_t serial = wlr_seat_client_next_serial(focused_client); + struct wl_resource *resource; + wl_resource_for_each(resource, &focused_client->pointers) { + if (wl_resource_get_id(resource) == id) { + if (wlr_seat_client_from_pointer_resource(resource) == NULL) { + continue; + } + + wl_pointer_send_enter(resource, serial, focused_surface->resource, + wl_fixed_from_double(sx), wl_fixed_from_double(sy)); + pointer_send_frame(resource); + } + } + } } void seat_client_destroy_pointer(struct wl_resource *resource) {