diff --git a/include/wlr/types/wlr_pointer_warp_v1.h b/include/wlr/types/wlr_pointer_warp_v1.h new file mode 100644 index 000000000..466ca3290 --- /dev/null +++ b/include/wlr/types/wlr_pointer_warp_v1.h @@ -0,0 +1,38 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_TYPES_WLR_POINTER_WARP_V1_H +#define WLR_TYPES_WLR_POINTER_WARP_V1_H + +#include + +struct wlr_pointer_warp_v1 { + struct wl_global *global; + + struct { + struct wl_signal destroy; + struct wl_signal warp; // struct wlr_pointer_warp_v1_event_warp + } events; + + void *data; + + struct { + struct wl_listener display_destroy; + } WLR_PRIVATE; +}; + +struct wlr_pointer_warp_v1_event_warp { + struct wlr_surface *surface; + struct wlr_seat_client *seat_client; + double x, y; + uint32_t serial; +}; + +struct wlr_pointer_warp_v1 *wlr_pointer_warp_v1_create(struct wl_display *display, + uint32_t version); +#endif diff --git a/protocol/meson.build b/protocol/meson.build index 4d667d94a..5830272b3 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -40,6 +40,7 @@ protocols = { 'ext-workspace-v1': wl_protocol_dir / 'staging/ext-workspace/ext-workspace-v1.xml', 'fractional-scale-v1': wl_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml', 'linux-drm-syncobj-v1': wl_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml', + 'pointer-warp-v1': wl_protocol_dir / 'staging/pointer-warp/pointer-warp-v1.xml', 'security-context-v1': wl_protocol_dir / 'staging/security-context/security-context-v1.xml', 'single-pixel-buffer-v1': wl_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml', 'xdg-activation-v1': wl_protocol_dir / 'staging/xdg-activation/xdg-activation-v1.xml', diff --git a/types/meson.build b/types/meson.build index bc3d32cd9..0513b8fc8 100644 --- a/types/meson.build +++ b/types/meson.build @@ -74,6 +74,7 @@ wlr_files += files( 'wlr_output_swapchain_manager.c', 'wlr_pointer_constraints_v1.c', 'wlr_pointer_gestures_v1.c', + 'wlr_pointer_warp_v1.c', 'wlr_pointer.c', 'wlr_presentation_time.c', 'wlr_primary_selection_v1.c', diff --git a/types/wlr_pointer_warp_v1.c b/types/wlr_pointer_warp_v1.c new file mode 100644 index 000000000..fc7393e7a --- /dev/null +++ b/types/wlr_pointer_warp_v1.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include "pointer-warp-v1-protocol.h" + +#define POINTER_WARP_VERSION 1 + +static const struct wp_pointer_warp_v1_interface pointer_warp_impl; + +static struct wlr_pointer_warp_v1 *pointer_warp_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wp_pointer_warp_v1_interface, + &pointer_warp_impl)); + return wl_resource_get_user_data(resource); +} + +static void resource_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static void pointer_warp_handle_warp_pointer(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *surface_resource, + struct wl_resource *pointer_resource, wl_fixed_t sx, wl_fixed_t sy, + uint32_t serial) { + struct wlr_pointer_warp_v1 *pointer_warp = + pointer_warp_from_resource(resource); + struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); + struct wlr_seat_client *seat_client = + wlr_seat_client_from_pointer_resource(pointer_resource); + if (seat_client == NULL) { + return; + } + + struct wlr_pointer_warp_v1_event_warp event = { + .surface = surface, + .seat_client = seat_client, + .x = wl_fixed_to_double(sx), + .y = wl_fixed_to_double(sy), + .serial = serial, + }; + + wl_signal_emit_mutable(&pointer_warp->events.warp, &event); +} + +static const struct wp_pointer_warp_v1_interface pointer_warp_impl = { + .destroy = resource_destroy, + .warp_pointer = pointer_warp_handle_warp_pointer, +}; + +static void pointer_warp_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id) { + struct wlr_pointer_warp_v1 *pointer_warp = data; + struct wl_resource *resource = wl_resource_create(client, + &wp_pointer_warp_v1_interface, version, id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, &pointer_warp_impl, pointer_warp, NULL); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_pointer_warp_v1 *pointer_warp = + wl_container_of(listener, pointer_warp, display_destroy); + + wl_signal_emit_mutable(&pointer_warp->events.destroy, NULL); + + assert(wl_list_empty(&pointer_warp->events.destroy.listener_list)); + assert(wl_list_empty(&pointer_warp->events.warp.listener_list)); + + wl_list_remove(&pointer_warp->display_destroy.link); + wl_global_destroy(pointer_warp->global); + free(pointer_warp); +} + +struct wlr_pointer_warp_v1 *wlr_pointer_warp_v1_create(struct wl_display *display, + uint32_t version) { + assert(version <= POINTER_WARP_VERSION); + + struct wlr_pointer_warp_v1 *pointer_warp = calloc(1, sizeof(*pointer_warp)); + if (pointer_warp == NULL) { + return NULL; + } + + pointer_warp->global = wl_global_create(display, &wp_pointer_warp_v1_interface, + version, pointer_warp, pointer_warp_bind); + if (pointer_warp->global == NULL) { + free(pointer_warp); + return NULL; + } + + wl_signal_init(&pointer_warp->events.destroy); + wl_signal_init(&pointer_warp->events.warp); + + pointer_warp->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &pointer_warp->display_destroy); + + return pointer_warp; +}