backend/wayland: Listen to pointers from all seats

This effectively gets  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
backend/wayland

View File

@ -22,14 +22,16 @@
#include "util/signal.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;
wl_list_for_each(wlr_dev, &output->backend->devices, link) {
if (wlr_dev->type != WLR_INPUT_DEVICE_POINTER) {
continue;
}
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;
}
}
@ -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);
assert(output);
struct wlr_wl_pointer *pointer = output_get_pointer(output);
assert(!backend->current_pointer || backend->current_pointer == pointer);
struct wlr_wl_pointer *pointer = output_get_pointer(output, wl_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;
backend->current_pointer = pointer;
@ -422,6 +431,8 @@ static void input_device_destroy(struct wlr_input_device *wlr_dev) {
wl_keyboard_release(seat->keyboard);
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);
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 wlr_wl_backend *backend = output->backend;
struct wlr_input_device *wlr_dev;
wl_list_for_each(wlr_dev, &output->backend->devices, link) {
if (wlr_dev->type != WLR_INPUT_DEVICE_POINTER) {
continue;
}
struct wlr_wl_pointer *pointer = pointer_get_wl(wlr_dev->pointer);
if (pointer->output == output) {
return;
}
if (output_get_pointer(output, wl_pointer)) {
wlr_log(WLR_DEBUG,
"Pointer for seat %s and output %s already exists (ignoring)",
seat->name, output->wlr_output.name);
return;
}
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;
}
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 =
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);
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->output_name = strdup(output->wlr_output.name);
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) {
wlr_log(WLR_DEBUG, "seat %p dropped pointer", (void *)wl_seat);
struct wl_pointer *wl_pointer = seat->pointer;
struct wlr_input_device *device, *tmp;
wl_list_for_each_safe(device, tmp, &backend->devices, link) {
if (device->type == WLR_INPUT_DEVICE_POINTER) {
wlr_input_device_destroy(device);
if (device->type != WLR_INPUT_DEVICE_POINTER) {
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);
@ -774,9 +791,16 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
struct wlr_input_device *device, *tmp;
wl_list_for_each_safe(device, tmp, &backend->devices, link) {
if (device->type == WLR_INPUT_DEVICE_KEYBOARD) {
wlr_input_device_destroy(device);
if (device->type != WLR_INPUT_DEVICE_KEYBOARD) {
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
}