wlroots-hyprland/types/wlr_relative_pointer_v1.c

204 lines
7.1 KiB
C
Raw Normal View History

#include <assert.h>
#include <inttypes.h>
#include <stdlib.h>
#include <wayland-server-core.h>
#include <wayland-util.h>
#include <wlr/types/wlr_relative_pointer_v1.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/util/log.h>
#include "relative-pointer-unstable-v1-protocol.h"
#define RELATIVE_POINTER_MANAGER_VERSION 1
static const struct zwp_relative_pointer_manager_v1_interface relative_pointer_manager_v1_impl;
static const struct zwp_relative_pointer_v1_interface relative_pointer_v1_impl;
2018-12-17 21:04:49 +01:00
struct wlr_relative_pointer_v1 *wlr_relative_pointer_v1_from_resource(struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &zwp_relative_pointer_v1_interface,
&relative_pointer_v1_impl));
return wl_resource_get_user_data(resource);
}
static struct wlr_relative_pointer_manager_v1 *relative_pointer_manager_from_resource(struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &zwp_relative_pointer_manager_v1_interface,
&relative_pointer_manager_v1_impl));
return wl_resource_get_user_data(resource);
}
2018-12-17 21:04:49 +01:00
static void relative_pointer_destroy(struct wlr_relative_pointer_v1 *relative_pointer) {
2022-08-18 13:16:16 +02:00
wl_signal_emit_mutable(&relative_pointer->events.destroy, relative_pointer);
2018-12-17 21:04:49 +01:00
wl_list_remove(&relative_pointer->link);
wl_list_remove(&relative_pointer->seat_destroy.link);
wl_list_remove(&relative_pointer->pointer_destroy.link);
2018-12-17 23:58:31 +01:00
wl_resource_set_user_data(relative_pointer->resource, NULL);
free(relative_pointer);
}
2018-12-17 21:04:49 +01:00
static void relative_pointer_v1_handle_resource_destroy(struct wl_resource *resource) {
struct wlr_relative_pointer_v1 *relative_pointer =
wlr_relative_pointer_v1_from_resource(resource);
if (relative_pointer == NULL) {
return;
}
relative_pointer_destroy(relative_pointer);
}
static void relative_pointer_v1_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
2018-12-17 21:04:49 +01:00
static void relative_pointer_handle_seat_destroy(struct wl_listener *listener,
void *data) {
struct wlr_relative_pointer_v1 *relative_pointer =
wl_container_of(listener, relative_pointer, seat_destroy);
relative_pointer_destroy(relative_pointer);
}
static void relative_pointer_handle_pointer_destroy(struct wl_listener *listener,
void *data) {
struct wlr_relative_pointer_v1 *relative_pointer =
wl_container_of(listener, relative_pointer, pointer_destroy);
relative_pointer_destroy(relative_pointer);
}
static void relative_pointer_manager_v1_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static void relative_pointer_manager_v1_handle_get_relative_pointer(struct wl_client *client,
struct wl_resource *resource, uint32_t id, struct wl_resource *pointer) {
struct wlr_relative_pointer_manager_v1 *manager =
relative_pointer_manager_from_resource(resource);
struct wlr_seat_client *seat_client =
wlr_seat_client_from_pointer_resource(pointer);
struct wl_resource *relative_pointer_resource = wl_resource_create(client,
&zwp_relative_pointer_v1_interface, wl_resource_get_version(resource), id);
if (relative_pointer_resource == NULL) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(relative_pointer_resource, &relative_pointer_v1_impl,
NULL, relative_pointer_v1_handle_resource_destroy);
if (seat_client == NULL) {
// Leave the resource inert
return;
}
struct wlr_relative_pointer_v1 *relative_pointer = calloc(1, sizeof(*relative_pointer));
if (relative_pointer == NULL) {
wl_client_post_no_memory(client);
return;
}
relative_pointer->resource = relative_pointer_resource;
relative_pointer->pointer_resource = pointer;
relative_pointer->seat = seat_client->seat;
wl_signal_add(&relative_pointer->seat->events.destroy,
&relative_pointer->seat_destroy);
relative_pointer->seat_destroy.notify = relative_pointer_handle_seat_destroy;
relative_pointer: handle inert pointer objects Since 5e0ef70cc085 ("seat: Create inert objects for missing capabilities") wlroots can create inert seat objects when the capability is currently missing for the client but it had the capablity before. The client hoever will happily handover the wl_pointer resource to the relative_pointer implementation, creating a NULL pointer dereference when trying to access the seat_client which is set to NULL for inert objects. Since the protocol does not contain an error for such requests, we hand out an relative_pointer handle with the seat set to NULL. We also need to check whether there is an associated seat in send_relative_motion and need to tweak the destroy notifier in case no seat is available. This way we can hand out a valid relative_pointer resource and don't crash the compositor when trying to access an inert seat pointer resource in relative_pointer. Relevant WAYLAND_DEBUG=1 when testing a client and switching VT every second: [2619872.442] wl_seat@30.capabilities(3) [2619872.460] -> wl_seat@30.get_pointer(new id wl_pointer@36) [2619872.484] wl_data_device@25.selection(nil) [2619872.504] zwp_primary_selection_device_v1@26.selection(nil) [2619874.995] wl_seat@12.capabilities(3) [2619875.035] -> wl_compositor@5.create_surface(new id wl_surface@37) [2619875.088] -> wl_seat@12.get_pointer(new id wl_pointer@29) [2619875.105] -> zwp_relative_pointer_manager_v1@8.get_relative_pointer(new id zwp_relative_pointer_v1@27, wl_pointer@29) [2619875.127] -> wl_compositor@5.create_surface(new id wl_surface@35) [2619875.139] -> wl_seat@12.get_pointer(new id wl_pointer@43) [2619981.180] wl_seat@12.capabilities(2) [2619981.214] -> zwp_relative_pointer_v1@27.destroy() [2619981.226] -> wl_pointer@29.release() [2619981.236] -> wl_surface@37.destroy() [2619981.247] -> wl_pointer@43.release() [2619981.254] -> wl_surface@35.destroy() [2619981.262] wl_seat@12.capabilities(0) [2619981.285] -> wl_keyboard@33.release() [2619987.316] wl_seat@30.capabilities(2) [2619987.336] -> wl_pointer@36.release() [2619987.363] wl_seat@30.capabilities(0) [2619987.371] -> wl_keyboard@34.release() [2621932.880] wl_display@1.delete_id(41) [2621932.903] wl_display@1.delete_id(40) [2621932.910] wl_display@1.delete_id(27) [2621932.917] wl_display@1.delete_id(29) [2621932.924] wl_display@1.delete_id(37) [2621932.930] wl_display@1.delete_id(43) [2621932.944] wl_display@1.delete_id(35) [2621932.950] wl_display@1.delete_id(33) [2621932.959] wl_seat@12.capabilities(2) [2621932.976] -> wl_seat@12.get_keyboard(new id wl_keyboard@33) [2621936.875] wl_seat@12.capabilities(3) [2621936.893] -> wl_compositor@5.create_surface(new id wl_surface@35) [2621936.931] -> wl_seat@12.get_pointer(new id wl_pointer@43) [2621936.945] -> zwp_relative_pointer_manager_v1@8.get_relative_pointer(new id zwp_relative_pointer_v1@37, wl_pointer@43) [2621936.965] -> wl_compositor@5.create_surface(new id wl_surface@29) [2621936.987] -> wl_seat@12.get_pointer(new id wl_pointer@27) [2621942.796] wl_data_device@25.selection(nil) [2621942.817] zwp_primary_selection_device_v1@26.selection(nil) [2621942.823] wl_seat@30.capabilities(2)
2022-05-27 20:47:34 +02:00
wl_signal_init(&relative_pointer->events.destroy);
wl_resource_set_user_data(relative_pointer_resource, relative_pointer);
wl_list_insert(&manager->relative_pointers, &relative_pointer->link);
2018-12-17 21:04:49 +01:00
wl_resource_add_destroy_listener(relative_pointer->pointer_resource,
&relative_pointer->pointer_destroy);
relative_pointer->pointer_destroy.notify = relative_pointer_handle_pointer_destroy;
2022-08-18 13:16:16 +02:00
wl_signal_emit_mutable(&manager->events.new_relative_pointer,
relative_pointer);
}
static void relative_pointer_manager_v1_bind(struct wl_client *wl_client, void *data,
uint32_t version, uint32_t id) {
2018-12-23 13:50:39 +01:00
struct wlr_relative_pointer_manager_v1 *manager = data;
struct wl_resource *manager_resource = wl_resource_create(wl_client,
&zwp_relative_pointer_manager_v1_interface, version, id);
if (manager_resource == NULL) {
wl_client_post_no_memory(wl_client);
return;
}
wl_resource_set_implementation(manager_resource, &relative_pointer_manager_v1_impl,
manager, NULL);
}
static void handle_display_destroy(struct wl_listener *listener, void *data) {
2018-12-17 21:04:49 +01:00
struct wlr_relative_pointer_manager_v1 *manager =
wl_container_of(listener, manager, display_destroy_listener);
2022-08-18 13:16:16 +02:00
wl_signal_emit_mutable(&manager->events.destroy, manager);
wl_list_remove(&manager->display_destroy_listener.link);
wl_global_destroy(manager->global);
free(manager);
}
static const struct zwp_relative_pointer_manager_v1_interface relative_pointer_manager_v1_impl = {
.destroy = relative_pointer_manager_v1_handle_destroy,
.get_relative_pointer = relative_pointer_manager_v1_handle_get_relative_pointer,
};
static const struct zwp_relative_pointer_v1_interface relative_pointer_v1_impl = {
.destroy = relative_pointer_v1_handle_destroy,
};
struct wlr_relative_pointer_manager_v1 *wlr_relative_pointer_manager_v1_create(struct wl_display *display) {
struct wlr_relative_pointer_manager_v1 *manager = calloc(1, sizeof(*manager));
2018-12-23 13:50:39 +01:00
if (manager == NULL) {
return NULL;
}
2018-12-23 13:50:39 +01:00
wl_list_init(&manager->relative_pointers);
2018-12-23 13:50:39 +01:00
manager->global = wl_global_create(display,
&zwp_relative_pointer_manager_v1_interface, RELATIVE_POINTER_MANAGER_VERSION,
2018-12-23 13:50:39 +01:00
manager, relative_pointer_manager_v1_bind);
if (manager->global == NULL) {
free(manager);
return NULL;
}
2018-12-23 13:50:39 +01:00
wl_signal_init(&manager->events.destroy);
wl_signal_init(&manager->events.new_relative_pointer);
2018-12-23 13:50:39 +01:00
manager->display_destroy_listener.notify = handle_display_destroy;
wl_display_add_destroy_listener(display, &manager->display_destroy_listener);
2018-12-23 13:50:39 +01:00
return manager;
}
void wlr_relative_pointer_manager_v1_send_relative_motion(
struct wlr_relative_pointer_manager_v1 *manager, struct wlr_seat *seat,
uint64_t time_usec, double dx, double dy,
double dx_unaccel, double dy_unaccel) {
struct wlr_seat_client *focused = seat->pointer_state.focused_client;
if (focused == NULL) {
return;
}
struct wlr_relative_pointer_v1 *pointer;
wl_list_for_each(pointer, &manager->relative_pointers, link) {
struct wlr_seat_client *seat_client =
wlr_seat_client_from_pointer_resource(pointer->pointer_resource);
relative_pointer: handle inert pointer objects Since 5e0ef70cc085 ("seat: Create inert objects for missing capabilities") wlroots can create inert seat objects when the capability is currently missing for the client but it had the capablity before. The client hoever will happily handover the wl_pointer resource to the relative_pointer implementation, creating a NULL pointer dereference when trying to access the seat_client which is set to NULL for inert objects. Since the protocol does not contain an error for such requests, we hand out an relative_pointer handle with the seat set to NULL. We also need to check whether there is an associated seat in send_relative_motion and need to tweak the destroy notifier in case no seat is available. This way we can hand out a valid relative_pointer resource and don't crash the compositor when trying to access an inert seat pointer resource in relative_pointer. Relevant WAYLAND_DEBUG=1 when testing a client and switching VT every second: [2619872.442] wl_seat@30.capabilities(3) [2619872.460] -> wl_seat@30.get_pointer(new id wl_pointer@36) [2619872.484] wl_data_device@25.selection(nil) [2619872.504] zwp_primary_selection_device_v1@26.selection(nil) [2619874.995] wl_seat@12.capabilities(3) [2619875.035] -> wl_compositor@5.create_surface(new id wl_surface@37) [2619875.088] -> wl_seat@12.get_pointer(new id wl_pointer@29) [2619875.105] -> zwp_relative_pointer_manager_v1@8.get_relative_pointer(new id zwp_relative_pointer_v1@27, wl_pointer@29) [2619875.127] -> wl_compositor@5.create_surface(new id wl_surface@35) [2619875.139] -> wl_seat@12.get_pointer(new id wl_pointer@43) [2619981.180] wl_seat@12.capabilities(2) [2619981.214] -> zwp_relative_pointer_v1@27.destroy() [2619981.226] -> wl_pointer@29.release() [2619981.236] -> wl_surface@37.destroy() [2619981.247] -> wl_pointer@43.release() [2619981.254] -> wl_surface@35.destroy() [2619981.262] wl_seat@12.capabilities(0) [2619981.285] -> wl_keyboard@33.release() [2619987.316] wl_seat@30.capabilities(2) [2619987.336] -> wl_pointer@36.release() [2619987.363] wl_seat@30.capabilities(0) [2619987.371] -> wl_keyboard@34.release() [2621932.880] wl_display@1.delete_id(41) [2621932.903] wl_display@1.delete_id(40) [2621932.910] wl_display@1.delete_id(27) [2621932.917] wl_display@1.delete_id(29) [2621932.924] wl_display@1.delete_id(37) [2621932.930] wl_display@1.delete_id(43) [2621932.944] wl_display@1.delete_id(35) [2621932.950] wl_display@1.delete_id(33) [2621932.959] wl_seat@12.capabilities(2) [2621932.976] -> wl_seat@12.get_keyboard(new id wl_keyboard@33) [2621936.875] wl_seat@12.capabilities(3) [2621936.893] -> wl_compositor@5.create_surface(new id wl_surface@35) [2621936.931] -> wl_seat@12.get_pointer(new id wl_pointer@43) [2621936.945] -> zwp_relative_pointer_manager_v1@8.get_relative_pointer(new id zwp_relative_pointer_v1@37, wl_pointer@43) [2621936.965] -> wl_compositor@5.create_surface(new id wl_surface@29) [2621936.987] -> wl_seat@12.get_pointer(new id wl_pointer@27) [2621942.796] wl_data_device@25.selection(nil) [2621942.817] zwp_primary_selection_device_v1@26.selection(nil) [2621942.823] wl_seat@30.capabilities(2)
2022-05-27 20:47:34 +02:00
if (!pointer->seat || seat != pointer->seat || focused != seat_client) {
continue;
}
zwp_relative_pointer_v1_send_relative_motion(pointer->resource,
(uint32_t)(time_usec >> 32), (uint32_t)time_usec,
wl_fixed_from_double(dx), wl_fixed_from_double(dy),
wl_fixed_from_double(dx_unaccel), wl_fixed_from_double(dy_unaccel));
}
}