From 005b9692277e49aa15a2fd17a1d1d1fe7271b280 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 28 Jan 2025 22:07:17 +0100 Subject: [PATCH] wayland: Implement the cursor_shape_v1 protocol Part-of: --- src/meson.build | 3 + src/wayland/meta-wayland-cursor-shape.c | 330 +++++++++++++++++++++++ src/wayland/meta-wayland-cursor-shape.h | 23 ++ src/wayland/meta-wayland-pointer.c | 34 ++- src/wayland/meta-wayland-pointer.h | 3 + src/wayland/meta-wayland-tablet-tool.c | 54 +++- src/wayland/meta-wayland-tablet-tool.h | 3 + src/wayland/meta-wayland-versions.h | 1 + src/wayland/meta-wayland.c | 4 +- src/wayland/protocol/cursor-shape-v1.xml | 163 +++++++++++ 10 files changed, 606 insertions(+), 12 deletions(-) create mode 100644 src/wayland/meta-wayland-cursor-shape.c create mode 100644 src/wayland/meta-wayland-cursor-shape.h create mode 100644 src/wayland/protocol/cursor-shape-v1.xml diff --git a/src/meson.build b/src/meson.build index bbc86dcaf..ab7c94a08 100644 --- a/src/meson.build +++ b/src/meson.build @@ -604,6 +604,8 @@ if have_wayland 'wayland/meta-wayland-color-management.c', 'wayland/meta-wayland-color-management.h', 'wayland/meta-wayland-commit-timing.c', + 'wayland/meta-wayland-cursor-shape.c', + 'wayland/meta-wayland-cursor-shape.h', 'wayland/meta-wayland-fifo.c', 'wayland/meta-wayland-cursor-surface.c', 'wayland/meta-wayland-cursor-surface.h', @@ -1107,6 +1109,7 @@ if have_wayland # - protocol stability ('private', 'stable' or 'unstable') # - protocol version (if stability is 'unstable') wayland_protocols = [ + ['cursor-shape-v1', 'private', ], ['drm-lease', 'staging', 'v1', ], ['fractional-scale', 'staging', 'v1', ], ['gtk-shell', 'private', ], diff --git a/src/wayland/meta-wayland-cursor-shape.c b/src/wayland/meta-wayland-cursor-shape.c new file mode 100644 index 000000000..5fe7ce32c --- /dev/null +++ b/src/wayland/meta-wayland-cursor-shape.c @@ -0,0 +1,330 @@ +/* + * Copyright 2024 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +#include "config.h" + +#include "wayland/meta-wayland-cursor-shape.h" + +#include "core/meta-debug-control-private.h" +#include "core/window-private.h" +#include "wayland/meta-wayland-private.h" +#include "wayland/meta-wayland-xdg-shell.h" +#include "wayland/meta-wayland-versions.h" + +#include "cursor-shape-v1-server-protocol.h" + +typedef enum _MetaWaylandCursorShapeDeviceType +{ + META_WAYLAND_CURSOR_SHAPE_DEVICE_TYPE_POINTER, + META_WAYLAND_CURSOR_SHAPE_DEVICE_TYPE_TOOL, +} MetaWaylandCursorShapeDeviceType; + +typedef struct _MetaWaylandCursorShapeDevice +{ + MetaWaylandCursorShapeDeviceType type; + union { + MetaWaylandPointer *pointer; + MetaWaylandTabletTool *tool; + }; +} MetaWaylandCursorShapeDevice; + +static const struct +{ + enum wp_cursor_shape_device_v1_shape shape; + MetaCursor cursor; +} shape_map[] = { + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT, META_CURSOR_DEFAULT }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CONTEXT_MENU, META_CURSOR_CONTEXT_MENU }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_HELP, META_CURSOR_HELP }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER, META_CURSOR_POINTER }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_PROGRESS, META_CURSOR_PROGRESS }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_WAIT, META_CURSOR_WAIT }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CELL, META_CURSOR_CELL }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR, META_CURSOR_CROSSHAIR }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT, META_CURSOR_TEXT }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_VERTICAL_TEXT, META_CURSOR_VERTICAL_TEXT }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALIAS, META_CURSOR_ALIAS }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_COPY, META_CURSOR_COPY }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE, META_CURSOR_MOVE }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NO_DROP, META_CURSOR_NO_DROP }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NOT_ALLOWED, META_CURSOR_NOT_ALLOWED }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRAB, META_CURSOR_GRAB }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRABBING, META_CURSOR_GRABBING }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_E_RESIZE, META_CURSOR_E_RESIZE }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_N_RESIZE, META_CURSOR_N_RESIZE }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE, META_CURSOR_NE_RESIZE }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE, META_CURSOR_NW_RESIZE }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_S_RESIZE, META_CURSOR_S_RESIZE }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SE_RESIZE, META_CURSOR_SE_RESIZE }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE, META_CURSOR_SW_RESIZE }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_W_RESIZE, META_CURSOR_W_RESIZE }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE, META_CURSOR_EW_RESIZE }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE, META_CURSOR_NS_RESIZE }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE, META_CURSOR_NESW_RESIZE }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE, META_CURSOR_NWSE_RESIZE }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_COL_RESIZE, META_CURSOR_COL_RESIZE }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ROW_RESIZE, META_CURSOR_ROW_RESIZE }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_SCROLL, META_CURSOR_ALL_SCROLL }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_IN, META_CURSOR_ZOOM_IN }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_OUT, META_CURSOR_ZOOM_OUT }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DND_ASK, META_CURSOR_DND_ASK }, + { WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_RESIZE, META_CURSOR_ALL_RESIZE }, +}; + +static MetaCursor +cursor_from_shape (enum wp_cursor_shape_device_v1_shape shape, + int version) +{ + if (shape < WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT) + return META_CURSOR_INVALID; + + if (version <= 1 && shape > WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_OUT) + return META_CURSOR_INVALID; + + if (shape >= G_N_ELEMENTS (shape_map)) + return META_CURSOR_INVALID; + + return shape_map[shape].cursor; +} + +static MetaWaylandCursorShapeDevice * +meta_wayland_cursor_shape_device_new_pointer (MetaWaylandPointer *pointer) +{ + MetaWaylandCursorShapeDevice *cursor_shape_device = + g_new0 (MetaWaylandCursorShapeDevice, 1); + + cursor_shape_device->type = META_WAYLAND_CURSOR_SHAPE_DEVICE_TYPE_POINTER; + cursor_shape_device->pointer = pointer; + g_object_add_weak_pointer (G_OBJECT (pointer), + (gpointer *) &cursor_shape_device->pointer); + + return cursor_shape_device; +} + + +static MetaWaylandCursorShapeDevice * +meta_wayland_cursor_shape_device_new_tool (MetaWaylandTabletTool *tool) +{ + MetaWaylandCursorShapeDevice *cursor_shape_device = + g_new0 (MetaWaylandCursorShapeDevice, 1); + + cursor_shape_device->type = META_WAYLAND_CURSOR_SHAPE_DEVICE_TYPE_TOOL; + cursor_shape_device->tool = tool; + g_object_add_weak_pointer (G_OBJECT (tool), + (gpointer *) &cursor_shape_device->tool); + + return cursor_shape_device; +} + +static void +meta_wayland_cursor_shape_device_free (MetaWaylandCursorShapeDevice *cursor_shape_device) +{ + if (cursor_shape_device->type == META_WAYLAND_CURSOR_SHAPE_DEVICE_TYPE_POINTER) + g_clear_weak_pointer ((gpointer *) &cursor_shape_device->pointer); + if (cursor_shape_device->type == META_WAYLAND_CURSOR_SHAPE_DEVICE_TYPE_TOOL) + g_clear_weak_pointer ((gpointer *) &cursor_shape_device->tool); + + g_free (cursor_shape_device); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaWaylandCursorShapeDevice, + meta_wayland_cursor_shape_device_free) + +static void +cursor_shape_device_destructor (struct wl_resource *resource) +{ + MetaWaylandCursorShapeDevice *cursor_shape_device = + wl_resource_get_user_data (resource); + + meta_wayland_cursor_shape_device_free (cursor_shape_device); +} + +static void +cursor_shape_device_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +cursor_shape_device_set_shape (struct wl_client *client, + struct wl_resource *resource, + uint32_t serial, + enum wp_cursor_shape_device_v1_shape shape) +{ + MetaWaylandCursorShapeDevice *cursor_shape_device = + wl_resource_get_user_data (resource); + MetaCursor cursor = cursor_from_shape (shape, + wl_resource_get_version (resource)); + + if (cursor == META_CURSOR_INVALID) + { + wl_resource_post_error (resource, + WP_CURSOR_SHAPE_DEVICE_V1_ERROR_INVALID_SHAPE, + "wp_cursor_shape_device_v1@%d: " + "the specified shape value is invalid", + wl_resource_get_id (resource)); + return; + } + + if (cursor_shape_device->type == META_WAYLAND_CURSOR_SHAPE_DEVICE_TYPE_POINTER && + cursor_shape_device->pointer) + { + MetaWaylandPointer *pointer = cursor_shape_device->pointer; + + if (!meta_wayland_pointer_check_focus_serial (pointer, client, serial)) + return; + + meta_wayland_pointer_set_cursor_shape (pointer, cursor); + } + + if (cursor_shape_device->type == META_WAYLAND_CURSOR_SHAPE_DEVICE_TYPE_TOOL && + cursor_shape_device->tool) + { + MetaWaylandTabletTool *tool = cursor_shape_device->tool; + + if (!meta_wayland_tablet_tool_check_focus_serial (tool, client, serial)) + return; + + meta_wayland_tablet_tool_set_cursor_shape (tool, cursor); + } +} + +static const struct wp_cursor_shape_device_v1_interface cursor_shape_device_interface = { + cursor_shape_device_destroy, + cursor_shape_device_set_shape, +}; + +static void +cursor_manager_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +cursor_manager_get_pointer (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *pointer_resource) +{ + MetaWaylandPointer *pointer = wl_resource_get_user_data (pointer_resource); + g_autoptr (MetaWaylandCursorShapeDevice) cursor_shape_device = NULL; + struct wl_resource *shape_device_resource; + + cursor_shape_device = meta_wayland_cursor_shape_device_new_pointer (pointer); + + shape_device_resource = + wl_resource_create (client, + &wp_cursor_shape_device_v1_interface, + wl_resource_get_version (resource), + id); + wl_resource_set_implementation (shape_device_resource, + &cursor_shape_device_interface, + g_steal_pointer (&cursor_shape_device), + cursor_shape_device_destructor); +} + +static void +cursor_manager_get_tablet_tool_v2 (struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *pointer_resource) +{ + MetaWaylandTabletTool *tool = wl_resource_get_user_data (resource); + g_autoptr (MetaWaylandCursorShapeDevice) cursor_shape_device = NULL; + struct wl_resource *shape_device_resource; + + cursor_shape_device = meta_wayland_cursor_shape_device_new_tool (tool); + + shape_device_resource = + wl_resource_create (client, + &wp_cursor_shape_device_v1_interface, + wl_resource_get_version (resource), + id); + wl_resource_set_implementation (shape_device_resource, + &cursor_shape_device_interface, + g_steal_pointer (&cursor_shape_device), + cursor_shape_device_destructor); +} + +static const struct wp_cursor_shape_manager_v1_interface cursor_shape_manager_interface = { + cursor_manager_destroy, + cursor_manager_get_pointer, + cursor_manager_get_tablet_tool_v2, +}; + +static void +bind_cursor_shape (struct wl_client *client, + void *data, + uint32_t version, + uint32_t id) +{ + struct wl_resource *resource; + + resource = wl_resource_create (client, &wp_cursor_shape_manager_v1_interface, + version, id); + wl_resource_set_implementation (resource, &cursor_shape_manager_interface, + NULL, NULL); +} + +static void +update_enabled (MetaWaylandCompositor *compositor) +{ + MetaDebugControl *debug_control = + meta_context_get_debug_control (compositor->context); + gboolean is_enabled = + meta_debug_control_is_cursor_shape_protocol_enabled (debug_control); + struct wl_global *global; + + global = g_object_get_data (G_OBJECT (compositor), + "-meta-wayland-cursor-shape"); + + if (is_enabled && global == NULL) + { + + global = wl_global_create (compositor->wayland_display, + &wp_cursor_shape_manager_v1_interface, + META_WP_CURSOR_SHAPE_VERSION, + NULL, bind_cursor_shape); + if (global == NULL) + g_error ("Failed to register a global cursor-shape object"); + } + else if (!is_enabled) + { + g_clear_pointer (&global, wl_global_destroy); + } + + g_object_set_data (G_OBJECT (compositor), + "-meta-wayland-cursor-shape", + global); +} + +void +meta_wayland_init_cursor_shape (MetaWaylandCompositor *compositor) +{ + MetaDebugControl *debug_control = + meta_context_get_debug_control (compositor->context); + + g_signal_connect_data (debug_control, "notify::cursor-shape-protocol", + G_CALLBACK (update_enabled), + compositor, NULL, + G_CONNECT_SWAPPED | G_CONNECT_AFTER); + + update_enabled (compositor); +} diff --git a/src/wayland/meta-wayland-cursor-shape.h b/src/wayland/meta-wayland-cursor-shape.h new file mode 100644 index 000000000..f9bd3ea72 --- /dev/null +++ b/src/wayland/meta-wayland-cursor-shape.h @@ -0,0 +1,23 @@ +/* + * Copyright 2024 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +#pragma once + +#include "wayland/meta-wayland.h" + +void meta_wayland_init_cursor_shape (MetaWaylandCompositor *compositor); diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c index fcb447431..0baa53006 100644 --- a/src/wayland/meta-wayland-pointer.c +++ b/src/wayland/meta-wayland-pointer.c @@ -101,6 +101,8 @@ struct _MetaWaylandPointer MetaWaylandSurface *cursor_surface; gulong cursor_surface_destroy_id; + MetaCursor cursor_shape; + guint32 grab_button; guint32 grab_serial; guint32 grab_time; @@ -1150,14 +1152,24 @@ meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer) if (surface) { - MetaCursorSprite *cursor_sprite = NULL; + g_autoptr (MetaCursorSprite) cursor_sprite = NULL; if (pointer->cursor_surface) { MetaWaylandCursorSurface *cursor_surface = META_WAYLAND_CURSOR_SURFACE (pointer->cursor_surface->role); + MetaCursorSprite *sprite; - cursor_sprite = meta_wayland_cursor_surface_get_sprite (cursor_surface); + sprite = meta_wayland_cursor_surface_get_sprite (cursor_surface); + cursor_sprite = g_object_ref (sprite); + } + else if (pointer->cursor_shape != META_CURSOR_INVALID) + { + MetaCursorSpriteXcursor *sprite; + + sprite = meta_cursor_sprite_xcursor_new (pointer->cursor_shape, + cursor_tracker); + cursor_sprite = META_CURSOR_SPRITE (sprite); } meta_cursor_tracker_set_window_cursor (cursor_tracker, cursor_sprite); @@ -1191,6 +1203,7 @@ meta_wayland_pointer_set_cursor_surface (MetaWaylandPointer *pointer, return; pointer->cursor_surface = cursor_surface; + pointer->cursor_shape = META_CURSOR_INVALID; if (prev_cursor_surface) { @@ -1210,6 +1223,23 @@ meta_wayland_pointer_set_cursor_surface (MetaWaylandPointer *pointer, meta_wayland_pointer_update_cursor_surface (pointer); } +void +meta_wayland_pointer_set_cursor_shape (MetaWaylandPointer *pointer, + MetaCursor shape) +{ + if (pointer->cursor_surface) + { + meta_wayland_surface_update_outputs (pointer->cursor_surface); + g_clear_signal_handler (&pointer->cursor_surface_destroy_id, + pointer->cursor_surface); + } + + pointer->cursor_surface = NULL; + pointer->cursor_shape = shape; + + meta_wayland_pointer_update_cursor_surface (pointer); +} + static void pointer_set_cursor (struct wl_client *client, struct wl_resource *resource, diff --git a/src/wayland/meta-wayland-pointer.h b/src/wayland/meta-wayland-pointer.h index 5833a316c..72b7d9c5e 100644 --- a/src/wayland/meta-wayland-pointer.h +++ b/src/wayland/meta-wayland-pointer.h @@ -103,6 +103,9 @@ MetaWaylandSurface * meta_wayland_pointer_get_implicit_grab_surface (MetaWayland MetaWaylandPointerClient * meta_wayland_pointer_get_focus_client (MetaWaylandPointer *pointer); +void meta_wayland_pointer_set_cursor_shape (MetaWaylandPointer *pointer, + MetaCursor shape); + gboolean meta_wayland_pointer_check_focus_serial (MetaWaylandPointer *pointer, struct wl_client *client, uint32_t serial); diff --git a/src/wayland/meta-wayland-tablet-tool.c b/src/wayland/meta-wayland-tablet-tool.c index 08f6be19f..86523918b 100644 --- a/src/wayland/meta-wayland-tablet-tool.c +++ b/src/wayland/meta-wayland-tablet-tool.c @@ -53,6 +53,8 @@ struct _MetaWaylandTabletTool MetaCursorRenderer *cursor_renderer; MetaCursorSpriteXcursor *default_sprite; + MetaCursor cursor_shape; + MetaWaylandSurface *current; guint32 pressed_buttons; guint32 button_count; @@ -115,7 +117,10 @@ move_resources_for_client (struct wl_list *destination, static void meta_wayland_tablet_tool_update_cursor_surface (MetaWaylandTabletTool *tool) { - MetaCursorSprite *cursor = NULL; + MetaBackend *backend = backend_from_tool (tool); + MetaCursorTracker *cursor_tracker = + meta_backend_get_cursor_tracker (backend); + g_autoptr (MetaCursorSprite) cursor_sprite = NULL; if (tool->cursor_renderer == NULL) return; @@ -127,18 +132,29 @@ meta_wayland_tablet_tool_update_cursor_surface (MetaWaylandTabletTool *tool) { MetaWaylandCursorSurface *cursor_surface = META_WAYLAND_CURSOR_SURFACE (tool->cursor_surface->role); + MetaCursorSprite *sprite; - cursor = meta_wayland_cursor_surface_get_sprite (cursor_surface); + sprite = meta_wayland_cursor_surface_get_sprite (cursor_surface); + cursor_sprite = g_object_ref (sprite); + } + else if (tool->cursor_shape != META_CURSOR_INVALID) + { + MetaCursorSpriteXcursor *sprite; + + sprite = meta_cursor_sprite_xcursor_new (tool->cursor_shape, + cursor_tracker); + cursor_sprite = META_CURSOR_SPRITE (sprite); } - else - cursor = NULL; } else if (tool->current_tablet) - cursor = META_CURSOR_SPRITE (tool->default_sprite); - else - cursor = NULL; + { + MetaCursorSprite *sprite; - meta_cursor_renderer_set_cursor (tool->cursor_renderer, cursor); + sprite = META_CURSOR_SPRITE (tool->default_sprite); + cursor_sprite = g_object_ref (sprite); + } + + meta_cursor_renderer_set_cursor (tool->cursor_renderer, cursor_sprite); } static void @@ -160,6 +176,7 @@ meta_wayland_tablet_tool_set_cursor_surface (MetaWaylandTabletTool *tool, } tool->cursor_surface = surface; + tool->cursor_shape = META_CURSOR_INVALID; if (tool->cursor_surface) { @@ -171,6 +188,27 @@ meta_wayland_tablet_tool_set_cursor_surface (MetaWaylandTabletTool *tool, meta_wayland_tablet_tool_update_cursor_surface (tool); } +void +meta_wayland_tablet_tool_set_cursor_shape (MetaWaylandTabletTool *tool, + MetaCursor shape) +{ + if (tool->cursor_surface) + { + MetaWaylandCursorSurface *cursor_surface; + + cursor_surface = META_WAYLAND_CURSOR_SURFACE (tool->cursor_surface->role); + meta_wayland_cursor_surface_set_renderer (cursor_surface, NULL); + + meta_wayland_surface_update_outputs (tool->cursor_surface); + wl_list_remove (&tool->cursor_surface_destroy_listener.link); + } + + tool->cursor_surface = NULL; + tool->cursor_shape = shape; + + meta_wayland_tablet_tool_update_cursor_surface (tool); +} + static enum zwp_tablet_tool_v2_type input_device_tool_get_type (ClutterInputDeviceTool *device_tool) { diff --git a/src/wayland/meta-wayland-tablet-tool.h b/src/wayland/meta-wayland-tablet-tool.h index 6b798690a..00be37c9e 100644 --- a/src/wayland/meta-wayland-tablet-tool.h +++ b/src/wayland/meta-wayland-tablet-tool.h @@ -65,6 +65,9 @@ MetaWaylandSurface * meta_wayland_tablet_tool_get_current_surface (MetaWaylandTa void meta_wayland_tablet_tool_focus_surface (MetaWaylandTabletTool *tool, MetaWaylandSurface *surface); +void meta_wayland_tablet_tool_set_cursor_shape (MetaWaylandTabletTool *tool, + MetaCursor shape); + gboolean meta_wayland_tablet_tool_check_focus_serial (MetaWaylandTabletTool *tool, struct wl_client *client, uint32_t serial); diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h index 32eb4932d..543857b38 100644 --- a/src/wayland/meta-wayland-versions.h +++ b/src/wayland/meta-wayland-versions.h @@ -65,3 +65,4 @@ #define META_XDG_TOPLEVEL_DRAG_VERSION 1 #define META_WP_COMMIT_TIMING_V1_VERSION 1 #define META_WP_FIFO_V1_VERSION 1 +#define META_WP_CURSOR_SHAPE_VERSION 2 diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index 350a36600..211eeb0c2 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -41,6 +41,7 @@ #include "wayland/meta-wayland-buffer.h" #include "wayland/meta-wayland-color-management.h" #include "wayland/meta-wayland-commit-timing.h" +#include "wayland/meta-wayland-cursor-shape.h" #include "wayland/meta-wayland-fifo.h" #include "wayland/meta-wayland-data-device.h" #include "wayland/meta-wayland-dma-buf.h" @@ -999,7 +1000,6 @@ meta_wayland_compositor_new (MetaContext *context) meta_wayland_init_egl (compositor); meta_wayland_init_shm (compositor); - meta_wayland_outputs_init (compositor); meta_wayland_data_device_manager_init (compositor); meta_wayland_data_device_primary_manager_init (compositor); @@ -1026,12 +1026,12 @@ meta_wayland_compositor_new (MetaContext *context) meta_wayland_init_color_management (compositor); meta_wayland_xdg_session_management_init (compositor); meta_wayland_init_system_bell (compositor); - #ifdef HAVE_NATIVE_BACKEND meta_wayland_drm_lease_manager_init (compositor); #endif meta_wayland_commit_timing_init (compositor); meta_wayland_fifo_init (compositor); + meta_wayland_init_cursor_shape (compositor); #ifdef HAVE_WAYLAND_EGLSTREAM { diff --git a/src/wayland/protocol/cursor-shape-v1.xml b/src/wayland/protocol/cursor-shape-v1.xml new file mode 100644 index 000000000..dd8f86798 --- /dev/null +++ b/src/wayland/protocol/cursor-shape-v1.xml @@ -0,0 +1,163 @@ + + + + Copyright 2018 The Chromium Authors + Copyright 2023 Simon Ser + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + + This global offers an alternative, optional way to set cursor images. This + new way uses enumerated cursors instead of a wl_surface like + wl_pointer.set_cursor does. + + Warning! The protocol described in this file is currently in the testing + phase. Backward compatible changes may be added together with the + corresponding interface version bump. Backward incompatible changes can + only be done by creating a new major version of the extension. + + + + + Destroy the cursor shape manager. + + + + + + Obtain a wp_cursor_shape_device_v1 for a wl_pointer object. + + When the pointer capability is removed from the wl_seat, the + wp_cursor_shape_device_v1 object becomes inert. + + + + + + + + Obtain a wp_cursor_shape_device_v1 for a zwp_tablet_tool_v2 object. + + When the zwp_tablet_tool_v2 is removed, the wp_cursor_shape_device_v1 + object becomes inert. + + + + + + + + + This interface allows clients to set the cursor shape. + + + + + This enum describes cursor shapes. + + The names are taken from the CSS W3C specification: + https://w3c.github.io/csswg-drafts/css-ui/#cursor + with a few additions. + + Note that there are some groups of cursor shapes that are related: + The first group is drag-and-drop cursors which are used to indicate + the selected action during dnd operations. The second group is resize + cursors which are used to indicate resizing and moving possibilities + on window borders. It is recommended that the shapes in these groups + should use visually compatible images and metaphors. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Destroy the cursor shape device. + + The device cursor shape remains unchanged. + + + + + + Sets the device cursor to the specified shape. The compositor will + change the cursor image based on the specified shape. + + The cursor actually changes only if the input device focus is one of + the requesting client's surfaces. If any, the previous cursor image + (surface or shape) is replaced. + + The "shape" argument must be a valid enum entry, otherwise the + invalid_shape protocol error is raised. + + This is similar to the wl_pointer.set_cursor and + zwp_tablet_tool_v2.set_cursor requests, but this request accepts a + shape instead of contents in the form of a surface. Clients can mix + set_cursor and set_shape requests. + + The serial parameter must match the latest wl_pointer.enter or + zwp_tablet_tool_v2.proximity_in serial number sent to the client. + Otherwise the request will be ignored. + + + + + +