diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index d61e1370..7319c170 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -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 }