From 44531e16e0edd3dbf6f7abe4afa930bceebcbf92 Mon Sep 17 00:00:00 2001
From: Mykola Orliuk <virkony@gmail.com>
Date: Thu, 8 Oct 2020 02:44:38 +0200
Subject: backend/wayland: Add active pointer per host seat

Every host seat with pointer capability propagates events to one of
sub-pointer depending which output window we entered.
active_pointer tracks reference to sub-pointer on enter/leave events to
avoid lookup for it on every move events.

Fixes swaywm/wlroots#1499
---
 backend/wayland/seat.c    | 30 ++++++++++++++++++++++--------
 include/backend/wayland.h |  1 +
 2 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c
index 19a1686a..cf841264 100644
--- a/backend/wayland/seat.c
+++ b/backend/wayland/seat.c
@@ -51,7 +51,9 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
 	struct wlr_wl_output *output = wl_surface_get_user_data(surface);
 	assert(output);
 	struct wlr_wl_pointer *pointer = output_get_pointer(output, wl_pointer);
+	seat->active_pointer = pointer;
 
+	// Manage cursor icon/rendering on output
 	struct wlr_wl_pointer *current_pointer = backend->current_pointer;
 	if (current_pointer && current_pointer != pointer) {
 		wlr_log(WLR_INFO, "Ignoring seat %s pointer cursor in favor of seat %s",
@@ -74,6 +76,12 @@ static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
 
 	struct wlr_wl_output *output = wl_surface_get_user_data(surface);
 	assert(output);
+
+	if (seat->active_pointer != NULL &&
+			seat->active_pointer->output == output) {
+		seat->active_pointer = NULL;
+	}
+
 	output->enter_serial = 0;
 
 	if (backend->current_pointer == NULL ||
@@ -87,7 +95,7 @@ static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
 static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
 		uint32_t time, wl_fixed_t sx, wl_fixed_t sy) {
 	struct wlr_wl_seat *seat = data;
-	struct wlr_wl_pointer *pointer = seat->backend->current_pointer;
+	struct wlr_wl_pointer *pointer = seat->active_pointer;
 	if (pointer == NULL) {
 		return;
 	}
@@ -105,7 +113,7 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
 static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
 		uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
 	struct wlr_wl_seat *seat = data;
-	struct wlr_wl_pointer *pointer = seat->backend->current_pointer;
+	struct wlr_wl_pointer *pointer = seat->active_pointer;
 	if (pointer == NULL) {
 		return;
 	}
@@ -122,7 +130,7 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
 static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
 		uint32_t time, uint32_t axis, wl_fixed_t value) {
 	struct wlr_wl_seat *seat = data;
-	struct wlr_wl_pointer *pointer = seat->backend->current_pointer;
+	struct wlr_wl_pointer *pointer = seat->active_pointer;
 	if (pointer == NULL) {
 		return;
 	}
@@ -142,7 +150,7 @@ static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
 
 static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) {
 	struct wlr_wl_seat *seat = data;
-	struct wlr_wl_pointer *pointer = seat->backend->current_pointer;
+	struct wlr_wl_pointer *pointer = seat->active_pointer;
 	if (pointer == NULL) {
 		return;
 	}
@@ -154,7 +162,7 @@ static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) {
 static void pointer_handle_axis_source(void *data,
 		struct wl_pointer *wl_pointer, uint32_t axis_source) {
 	struct wlr_wl_seat *seat = data;
-	struct wlr_wl_pointer *pointer = seat->backend->current_pointer;
+	struct wlr_wl_pointer *pointer = seat->active_pointer;
 	if (pointer == NULL) {
 		return;
 	}
@@ -165,7 +173,7 @@ static void pointer_handle_axis_source(void *data,
 static void pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer,
 		uint32_t time, uint32_t axis) {
 	struct wlr_wl_seat *seat = data;
-	struct wlr_wl_pointer *pointer = seat->backend->current_pointer;
+	struct wlr_wl_pointer *pointer = seat->active_pointer;
 	if (pointer == NULL) {
 		return;
 	}
@@ -184,7 +192,7 @@ static void pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer,
 static void pointer_handle_axis_discrete(void *data,
 		struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) {
 	struct wlr_wl_seat *seat = data;
-	struct wlr_wl_pointer *pointer = seat->backend->current_pointer;
+	struct wlr_wl_pointer *pointer = seat->active_pointer;
 	if (pointer == NULL) {
 		return;
 	}
@@ -485,6 +493,11 @@ static void pointer_destroy(struct wlr_pointer *wlr_pointer) {
 		pointer->output->backend->current_pointer = NULL;
 	}
 
+	struct wlr_wl_seat *seat = pointer->input_device->seat;
+	if (seat->active_pointer == pointer) {
+		seat->active_pointer = NULL;
+	}
+
 	wl_list_remove(&pointer->output_destroy.link);
 	free(pointer);
 }
@@ -600,7 +613,7 @@ static void relative_pointer_handle_relative_motion(void *data,
 		wl_fixed_t dy_unaccel) {
 	struct wlr_wl_input_device *input_device = data;
 	struct wlr_input_device *wlr_dev = &input_device->wlr_input_device;
-	if (pointer_get_wl(wlr_dev->pointer) != input_device->backend->current_pointer) {
+	if (pointer_get_wl(wlr_dev->pointer) != input_device->seat->active_pointer) {
 		return;
 	}
 
@@ -770,6 +783,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
 			wlr_log(WLR_DEBUG, "dropping pointer %s",
 				pointer->input_device->wlr_input_device.name);
 			wlr_input_device_destroy(device);
+			assert(seat->active_pointer != pointer);
 			assert(backend->current_pointer != pointer);
 		}
 
diff --git a/include/backend/wayland.h b/include/backend/wayland.h
index 20292625..9f64cdb7 100644
--- a/include/backend/wayland.h
+++ b/include/backend/wayland.h
@@ -116,6 +116,7 @@ struct wlr_wl_seat {
 	struct wl_keyboard *keyboard;
 
 	struct wlr_wl_backend *backend;
+	struct wlr_wl_pointer *active_pointer;
 };
 
 struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *backend);
-- 
cgit v1.2.3