backend/wayland: Listen to pointers from all seats

This effectively gets swaywm/wlroots#1499 to the point where
functionality somewhat preserved and no crash happens.
We still can have only one cursor, but we can control it from multiple
seats in time-sharing manner by entering/leaving output.
This commit is contained in:
Mykola Orliuk 2020-10-04 22:28:25 +02:00 committed by Simon Ser
parent 44c4773d58
commit 07e2e0f60c
1 changed files with 43 additions and 19 deletions

View File

@ -22,14 +22,16 @@
#include "util/signal.h" #include "util/signal.h"
#include "util/time.h" #include "util/time.h"
static struct wlr_wl_pointer *output_get_pointer(struct wlr_wl_output *output) { static struct wlr_wl_pointer *output_get_pointer(
struct wlr_wl_output *output,
const struct wl_pointer *wl_pointer) {
struct wlr_input_device *wlr_dev; struct wlr_input_device *wlr_dev;
wl_list_for_each(wlr_dev, &output->backend->devices, link) { wl_list_for_each(wlr_dev, &output->backend->devices, link) {
if (wlr_dev->type != WLR_INPUT_DEVICE_POINTER) { if (wlr_dev->type != WLR_INPUT_DEVICE_POINTER) {
continue; continue;
} }
struct wlr_wl_pointer *pointer = pointer_get_wl(wlr_dev->pointer); struct wlr_wl_pointer *pointer = pointer_get_wl(wlr_dev->pointer);
if (pointer->output == output) { if (pointer->output == output && pointer->wl_pointer == wl_pointer) {
return pointer; return pointer;
} }
} }
@ -47,8 +49,15 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
struct wlr_wl_output *output = wl_surface_get_user_data(surface); struct wlr_wl_output *output = wl_surface_get_user_data(surface);
assert(output); assert(output);
struct wlr_wl_pointer *pointer = output_get_pointer(output); struct wlr_wl_pointer *pointer = output_get_pointer(output, wl_pointer);
assert(!backend->current_pointer || backend->current_pointer == pointer);
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",
pointer->input_device->seat->name,
current_pointer->input_device->seat->name);
return;
}
output->enter_serial = serial; output->enter_serial = serial;
backend->current_pointer = pointer; backend->current_pointer = pointer;
@ -422,6 +431,8 @@ static void input_device_destroy(struct wlr_input_device *wlr_dev) {
wl_keyboard_release(seat->keyboard); wl_keyboard_release(seat->keyboard);
seat->keyboard = NULL; seat->keyboard = NULL;
} }
// We can't destroy pointer here because we might have multiple devices
// exposing it to compositor.
wl_list_remove(&dev->wlr_input_device.link); wl_list_remove(&dev->wlr_input_device.link);
free(dev); free(dev);
} }
@ -625,15 +636,11 @@ void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) {
struct wl_pointer *wl_pointer = seat->pointer; struct wl_pointer *wl_pointer = seat->pointer;
struct wlr_wl_backend *backend = output->backend; struct wlr_wl_backend *backend = output->backend;
struct wlr_input_device *wlr_dev; if (output_get_pointer(output, wl_pointer)) {
wl_list_for_each(wlr_dev, &output->backend->devices, link) { wlr_log(WLR_DEBUG,
if (wlr_dev->type != WLR_INPUT_DEVICE_POINTER) { "Pointer for seat %s and output %s already exists (ignoring)",
continue; seat->name, output->wlr_output.name);
} return;
struct wlr_wl_pointer *pointer = pointer_get_wl(wlr_dev->pointer);
if (pointer->output == output) {
return;
}
} }
struct wlr_wl_pointer *pointer = calloc(1, sizeof(struct wlr_wl_pointer)); struct wlr_wl_pointer *pointer = calloc(1, sizeof(struct wlr_wl_pointer));
@ -642,7 +649,7 @@ void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) {
return; return;
} }
pointer->wl_pointer = wl_pointer; pointer->wl_pointer = wl_pointer;
pointer->output = output; pointer->output = output; // we need output to map absolute coordinates onto
struct wlr_wl_input_device *dev = struct wlr_wl_input_device *dev =
create_wl_input_device(seat, WLR_INPUT_DEVICE_POINTER); create_wl_input_device(seat, WLR_INPUT_DEVICE_POINTER);
@ -656,7 +663,7 @@ void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) {
wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy); wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy);
pointer->output_destroy.notify = pointer_handle_output_destroy; pointer->output_destroy.notify = pointer_handle_output_destroy;
wlr_dev = &dev->wlr_input_device; struct wlr_input_device *wlr_dev = &dev->wlr_input_device;
wlr_dev->pointer = &pointer->wlr_pointer; wlr_dev->pointer = &pointer->wlr_pointer;
wlr_dev->output_name = strdup(output->wlr_output.name); wlr_dev->output_name = strdup(output->wlr_output.name);
wlr_pointer_init(wlr_dev->pointer, &pointer_impl); wlr_pointer_init(wlr_dev->pointer, &pointer_impl);
@ -748,11 +755,21 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
if (!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer != NULL) { if (!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer != NULL) {
wlr_log(WLR_DEBUG, "seat %p dropped pointer", (void *)wl_seat); wlr_log(WLR_DEBUG, "seat %p dropped pointer", (void *)wl_seat);
struct wl_pointer *wl_pointer = seat->pointer;
struct wlr_input_device *device, *tmp; struct wlr_input_device *device, *tmp;
wl_list_for_each_safe(device, tmp, &backend->devices, link) { wl_list_for_each_safe(device, tmp, &backend->devices, link) {
if (device->type == WLR_INPUT_DEVICE_POINTER) { if (device->type != WLR_INPUT_DEVICE_POINTER) {
wlr_input_device_destroy(device); continue;
} }
struct wlr_wl_pointer *pointer = pointer_get_wl(device->pointer);
if (pointer->wl_pointer != wl_pointer) {
continue;
}
wlr_log(WLR_DEBUG, "dropping pointer %s",
pointer->input_device->wlr_input_device.name);
wlr_input_device_destroy(device);
assert(backend->current_pointer != pointer);
} }
wl_pointer_release(seat->pointer); wl_pointer_release(seat->pointer);
@ -774,9 +791,16 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
struct wlr_input_device *device, *tmp; struct wlr_input_device *device, *tmp;
wl_list_for_each_safe(device, tmp, &backend->devices, link) { wl_list_for_each_safe(device, tmp, &backend->devices, link) {
if (device->type == WLR_INPUT_DEVICE_KEYBOARD) { if (device->type != WLR_INPUT_DEVICE_KEYBOARD) {
wlr_input_device_destroy(device); continue;
} }
struct wlr_wl_input_device *input_device =
get_wl_input_device_from_input_device(device);
if (input_device->seat != seat) {
continue;
}
wlr_input_device_destroy(device);
} }
assert(seat->keyboard == NULL); // free'ed by input_device_destroy assert(seat->keyboard == NULL); // free'ed by input_device_destroy
} }