aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsaac Freund <ifreund@ifreund.xyz>2020-03-13 23:38:33 +0100
committerSimon Ser <contact@emersion.fr>2020-03-14 00:09:32 +0100
commit1282c3b12fc2c0dacf0c5df9b261dfc45046e7c6 (patch)
tree188224b356c791a4ae47f3dfc8c9282641cdd645
parent7c309ba4d30d5ff99fd52a1124e251203ac80883 (diff)
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.
-rw-r--r--include/types/wlr_seat.h2
-rw-r--r--types/seat/wlr_seat.c12
-rw-r--r--types/seat/wlr_seat_pointer.c50
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) {