diff --git a/src/backends/meta-cursor-sprite-xcursor.c b/src/backends/meta-cursor-sprite-xcursor.c
index df49b7ab8..e6209fb93 100644
--- a/src/backends/meta-cursor-sprite-xcursor.c
+++ b/src/backends/meta-cursor-sprite-xcursor.c
@@ -43,56 +43,220 @@ struct _MetaCursorSpriteXcursor
G_DEFINE_TYPE (MetaCursorSpriteXcursor, meta_cursor_sprite_xcursor,
META_TYPE_CURSOR_SPRITE)
-static const char *
-translate_meta_cursor (MetaCursor cursor)
+const char *
+meta_cursor_get_name (MetaCursor cursor)
{
switch (cursor)
{
case META_CURSOR_DEFAULT:
return "left_ptr";
- case META_CURSOR_NORTH_RESIZE:
+ case META_CURSOR_CONTEXT_MENU:
+ return "left_ptr";
+ case META_CURSOR_HELP:
+ return "question_arrow";
+ case META_CURSOR_POINTER:
+ return "hand";
+ case META_CURSOR_PROGRESS:
+ return "left_ptr_watch";
+ case META_CURSOR_WAIT:
+ return "watch";
+ case META_CURSOR_CELL:
+ return "crosshair";
+ case META_CURSOR_CROSSHAIR:
+ return "cross";
+ case META_CURSOR_TEXT:
+ return "xterm";
+ case META_CURSOR_VERTICAL_TEXT:
+ return "xterm";
+ case META_CURSOR_ALIAS:
+ return "dnd-link";
+ case META_CURSOR_COPY:
+ return "dnd-copy";
+ case META_CURSOR_MOVE:
+ return "dnd-move";
+ case META_CURSOR_NO_DROP:
+ return "dnd-none";
+ case META_CURSOR_NOT_ALLOWED:
+ return "crossed_circle";
+ case META_CURSOR_GRAB:
+ return "hand2";
+ case META_CURSOR_GRABBING:
+ return "hand2";
+ case META_CURSOR_E_RESIZE:
+ return "right_side";
+ case META_CURSOR_N_RESIZE:
return "top_side";
- case META_CURSOR_SOUTH_RESIZE:
+ case META_CURSOR_NE_RESIZE:
+ return "top_right_corner";
+ case META_CURSOR_NW_RESIZE:
+ return "top_left_corner";
+ case META_CURSOR_S_RESIZE:
return "bottom_side";
- case META_CURSOR_WEST_RESIZE:
- return "left_side";
- case META_CURSOR_EAST_RESIZE:
- return "right_side";
case META_CURSOR_SE_RESIZE:
return "bottom_right_corner";
case META_CURSOR_SW_RESIZE:
return "bottom_left_corner";
+ case META_CURSOR_W_RESIZE:
+ return "left_side";
+ case META_CURSOR_EW_RESIZE:
+ return "h_double_arrow";
+ case META_CURSOR_NS_RESIZE:
+ return "v_double_arrow";
+ case META_CURSOR_NESW_RESIZE:
+ return "fd_double_arrow";
+ case META_CURSOR_NWSE_RESIZE:
+ return "bd_double_arrow";
+ case META_CURSOR_COL_RESIZE:
+ return "h_double_arrow";
+ case META_CURSOR_ROW_RESIZE:
+ return "v_double_arrow";
+ case META_CURSOR_ALL_SCROLL:
+ return "left_ptr";
+ case META_CURSOR_ZOOM_IN:
+ return "left_ptr";
+ case META_CURSOR_ZOOM_OUT:
+ return "left_ptr";
+ case META_CURSOR_DND_ASK:
+ return "dnd-copy";
+ case META_CURSOR_ALL_RESIZE:
+ return "dnd-move";
+ case META_CURSOR_INVALID:
+ case META_CURSOR_NONE:
+ break;
+ }
+
+ g_assert_not_reached ();
+ return NULL;
+}
+
+const char *
+meta_cursor_get_legacy_name (MetaCursor cursor)
+{
+ switch (cursor)
+ {
+ case META_CURSOR_DEFAULT:
+ return "left_ptr";
+ case META_CURSOR_CONTEXT_MENU:
+ return "left_ptr";
+ case META_CURSOR_HELP:
+ return "question_arrow";
+ case META_CURSOR_POINTER:
+ return "hand";
+ case META_CURSOR_PROGRESS:
+ return "left_ptr_watch";
+ case META_CURSOR_WAIT:
+ return "watch";
+ case META_CURSOR_CELL:
+ return "crosshair";
+ case META_CURSOR_CROSSHAIR:
+ return "cross";
+ case META_CURSOR_TEXT:
+ return "xterm";
+ case META_CURSOR_VERTICAL_TEXT:
+ return "xterm";
+ case META_CURSOR_ALIAS:
+ return "dnd-link";
+ case META_CURSOR_COPY:
+ return "dnd-copy";
+ case META_CURSOR_MOVE:
+ return "dnd-move";
+ case META_CURSOR_NO_DROP:
+ return "dnd-none";
+ case META_CURSOR_NOT_ALLOWED:
+ return "crossed_circle";
+ case META_CURSOR_GRAB:
+ return "hand2";
+ case META_CURSOR_GRABBING:
+ return "hand2";
+ case META_CURSOR_E_RESIZE:
+ return "right_side";
+ case META_CURSOR_N_RESIZE:
+ return "top_side";
case META_CURSOR_NE_RESIZE:
return "top_right_corner";
case META_CURSOR_NW_RESIZE:
return "top_left_corner";
- case META_CURSOR_MOVE_OR_RESIZE_WINDOW:
- return "fleur";
- case META_CURSOR_BUSY:
- return "watch";
- case META_CURSOR_DND_IN_DRAG:
- return "dnd-none";
- case META_CURSOR_DND_MOVE:
- return "dnd-move";
- case META_CURSOR_DND_COPY:
+ case META_CURSOR_S_RESIZE:
+ return "bottom_side";
+ case META_CURSOR_SE_RESIZE:
+ return "bottom_right_corner";
+ case META_CURSOR_SW_RESIZE:
+ return "bottom_left_corner";
+ case META_CURSOR_W_RESIZE:
+ return "left_side";
+ case META_CURSOR_EW_RESIZE:
+ return "h_double_arrow";
+ case META_CURSOR_NS_RESIZE:
+ return "v_double_arrow";
+ case META_CURSOR_NESW_RESIZE:
+ return "fd_double_arrow";
+ case META_CURSOR_NWSE_RESIZE:
+ return "bd_double_arrow";
+ case META_CURSOR_COL_RESIZE:
+ return "h_double_arrow";
+ case META_CURSOR_ROW_RESIZE:
+ return "v_double_arrow";
+ case META_CURSOR_ALL_SCROLL:
+ return "left_ptr";
+ case META_CURSOR_ZOOM_IN:
+ return "left_ptr";
+ case META_CURSOR_ZOOM_OUT:
+ return "left_ptr";
+ case META_CURSOR_DND_ASK:
return "dnd-copy";
- case META_CURSOR_DND_UNSUPPORTED_TARGET:
- return "dnd-none";
- case META_CURSOR_POINTING_HAND:
- return "hand2";
- case META_CURSOR_CROSSHAIR:
- return "crosshair";
- case META_CURSOR_IBEAM:
- return "xterm";
+ case META_CURSOR_ALL_RESIZE:
+ return "dnd-move";
+ case META_CURSOR_INVALID:
case META_CURSOR_NONE:
- case META_CURSOR_LAST:
break;
- }
+ }
g_assert_not_reached ();
return NULL;
}
+static Cursor
+create_blank_cursor (Display *xdisplay)
+{
+ Pixmap pixmap;
+ XColor color;
+ Cursor cursor;
+ XGCValues gc_values;
+ GC gc;
+
+ pixmap = XCreatePixmap (xdisplay, DefaultRootWindow (xdisplay), 1, 1, 1);
+
+ gc_values.foreground = BlackPixel (xdisplay, DefaultScreen (xdisplay));
+ gc = XCreateGC (xdisplay, pixmap, GCForeground, &gc_values);
+
+ XFillRectangle (xdisplay, pixmap, gc, 0, 0, 1, 1);
+
+ color.pixel = 0;
+ color.red = color.blue = color.green = 0;
+
+ cursor = XCreatePixmapCursor (xdisplay, pixmap, pixmap, &color, &color, 1, 1);
+
+ XFreeGC (xdisplay, gc);
+ XFreePixmap (xdisplay, pixmap);
+
+ return cursor;
+}
+
+static XcursorImages *
+create_blank_cursor_images (void)
+{
+ XcursorImages *images;
+
+ images = XcursorImagesCreate (1);
+ images->images[0] = XcursorImageCreate (1, 1);
+
+ images->images[0]->xhot = 0;
+ images->images[0]->yhot = 0;
+ memset (images->images[0]->pixels, 0, sizeof(int32_t));
+
+ return images;
+}
+
MetaCursor
meta_cursor_sprite_xcursor_get_cursor (MetaCursorSpriteXcursor *sprite_xcursor)
{
@@ -103,17 +267,30 @@ Cursor
meta_create_x_cursor (Display *xdisplay,
MetaCursor cursor)
{
- return XcursorLibraryLoadCursor (xdisplay, translate_meta_cursor (cursor));
+ Cursor result;
+
+ if (cursor == META_CURSOR_NONE)
+ return create_blank_cursor (xdisplay);
+
+ result = XcursorLibraryLoadCursor (xdisplay, meta_cursor_get_name (cursor));
+ if (!result)
+ result = XcursorLibraryLoadCursor (xdisplay, meta_cursor_get_legacy_name (cursor));
+
+ return result;
}
static XcursorImages *
-load_cursor_on_client (MetaCursor cursor, int scale)
+load_cursor_on_client (MetaCursor cursor,
+ int scale)
{
+ if (cursor == META_CURSOR_INVALID)
+ return create_blank_cursor_images ();
+
XcursorImages *xcursor_images;
int fallback_size;
xcursor_images =
- XcursorLibraryLoadImages (translate_meta_cursor (cursor),
+ XcursorLibraryLoadImages (meta_cursor_get_name (cursor),
meta_prefs_get_cursor_theme (),
meta_prefs_get_cursor_size () * scale);
if (xcursor_images)
@@ -248,7 +425,7 @@ load_cursor_from_theme (MetaCursorSprite *sprite)
{
MetaCursorSpriteXcursor *sprite_xcursor = META_CURSOR_SPRITE_XCURSOR (sprite);
- g_assert (sprite_xcursor->cursor != META_CURSOR_NONE);
+ g_assert (sprite_xcursor->cursor != META_CURSOR_INVALID);
sprite_xcursor->theme_dirty = FALSE;
diff --git a/src/backends/meta-cursor-sprite-xcursor.h b/src/backends/meta-cursor-sprite-xcursor.h
index dbc927484..adeb233a9 100644
--- a/src/backends/meta-cursor-sprite-xcursor.h
+++ b/src/backends/meta-cursor-sprite-xcursor.h
@@ -40,4 +40,8 @@ XcursorImage * meta_cursor_sprite_xcursor_get_current_image (MetaCursorSpriteXcu
Cursor meta_create_x_cursor (Display *xdisplay,
MetaCursor cursor);
+const char * meta_cursor_get_name (MetaCursor cursor);
+
+const char * meta_cursor_get_legacy_name (MetaCursor cursor);
+
#endif /* META_CURSOR_SPRITE_XCURSOR_H */
diff --git a/src/backends/x11/meta-cursor-renderer-x11.c b/src/backends/x11/meta-cursor-renderer-x11.c
index 1f198c130..f045e156c 100644
--- a/src/backends/x11/meta-cursor-renderer-x11.c
+++ b/src/backends/x11/meta-cursor-renderer-x11.c
@@ -72,11 +72,14 @@ meta_cursor_renderer_x11_update_cursor (MetaCursorRenderer *renderer,
Cursor xcursor;
xcursor = meta_create_x_cursor (xdisplay, cursor);
- XDefineCursor (xdisplay, xwindow, xcursor);
- XFlush (xdisplay);
- XFreeCursor (xdisplay, xcursor);
-
- has_server_cursor = TRUE;
+ if (xcursor)
+ {
+ XDefineCursor (xdisplay, xwindow, xcursor);
+ XFlush (xdisplay);
+ XFreeCursor (xdisplay, xcursor);
+
+ has_server_cursor = TRUE;
+ }
}
}
diff --git a/src/core/display.c b/src/core/display.c
index f15f26fae..b4fbcff29 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -1662,7 +1662,7 @@ meta_cursor_for_grab_op (MetaGrabOp op)
break;
case META_GRAB_OP_RESIZING_S:
case META_GRAB_OP_KEYBOARD_RESIZING_S:
- return META_CURSOR_SOUTH_RESIZE;
+ return META_CURSOR_S_RESIZE;
break;
case META_GRAB_OP_RESIZING_SW:
case META_GRAB_OP_KEYBOARD_RESIZING_SW:
@@ -1670,7 +1670,7 @@ meta_cursor_for_grab_op (MetaGrabOp op)
break;
case META_GRAB_OP_RESIZING_N:
case META_GRAB_OP_KEYBOARD_RESIZING_N:
- return META_CURSOR_NORTH_RESIZE;
+ return META_CURSOR_N_RESIZE;
break;
case META_GRAB_OP_RESIZING_NE:
case META_GRAB_OP_KEYBOARD_RESIZING_NE:
@@ -1682,16 +1682,16 @@ meta_cursor_for_grab_op (MetaGrabOp op)
break;
case META_GRAB_OP_RESIZING_W:
case META_GRAB_OP_KEYBOARD_RESIZING_W:
- return META_CURSOR_WEST_RESIZE;
+ return META_CURSOR_W_RESIZE;
break;
case META_GRAB_OP_RESIZING_E:
case META_GRAB_OP_KEYBOARD_RESIZING_E:
- return META_CURSOR_EAST_RESIZE;
+ return META_CURSOR_E_RESIZE;
break;
case META_GRAB_OP_MOVING:
case META_GRAB_OP_KEYBOARD_MOVING:
case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
- return META_CURSOR_MOVE_OR_RESIZE_WINDOW;
+ return META_CURSOR_MOVE;
break;
default:
break;
diff --git a/src/core/startup-notification.c b/src/core/startup-notification.c
index b7b7dbec6..e1831616c 100644
--- a/src/core/startup-notification.c
+++ b/src/core/startup-notification.c
@@ -137,7 +137,7 @@ meta_startup_notification_update_feedback (MetaStartupNotification *sn)
{
meta_topic (META_DEBUG_STARTUP,
"Setting busy cursor\n");
- meta_display_set_cursor (display, META_CURSOR_BUSY);
+ meta_display_set_cursor (display, META_CURSOR_WAIT);
}
else
{
diff --git a/src/meson.build b/src/meson.build
index 10fb80dc5..95dbf4d22 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -498,6 +498,8 @@ if have_wayland
'wayland/meta-wayland.c',
'wayland/meta-wayland-cursor-surface.c',
'wayland/meta-wayland-cursor-surface.h',
+ 'wayland/meta-wayland-cursor-shape.c',
+ 'wayland/meta-wayland-cursor-shape.h',
'wayland/meta-wayland-data-device.c',
'wayland/meta-wayland-data-device.h',
'wayland/meta-wayland-data-device-primary.c',
@@ -798,6 +800,7 @@ if have_wayland
# - protocol stability ('private', 'stable' or 'unstable')
# - protocol version (if stability is 'unstable')
wayland_protocols = [
+ ['cursor-shape-v1', 'private', ],
['gtk-shell', 'private', ],
['keyboard-shortcuts-inhibit', 'unstable', 'v1', ],
['linux-dmabuf', 'unstable', 'v1', ],
diff --git a/src/meta/common.h b/src/meta/common.h
index 99e1cf20f..fa75f1ad0 100644
--- a/src/meta/common.h
+++ b/src/meta/common.h
@@ -205,47 +205,85 @@ typedef enum
/**
* MetaCursor:
+ * @META_CURSOR_INVALID: No cursor
+ * @META_CURSOR_NONE: No cursor
* @META_CURSOR_DEFAULT: Default cursor
- * @META_CURSOR_NORTH_RESIZE: Resize northern edge cursor
- * @META_CURSOR_SOUTH_RESIZE: Resize southern edge cursor
- * @META_CURSOR_WEST_RESIZE: Resize western edge cursor
- * @META_CURSOR_EAST_RESIZE: Resize eastern edge cursor
- * @META_CURSOR_SE_RESIZE: Resize south-eastern corner cursor
- * @META_CURSOR_SW_RESIZE: Resize south-western corner cursor
+ * @META_CURSOR_CONTEXT_MENU: Context menu cursor
+ * @META_CURSOR_HELP: Help cursor
+ * @META_CURSOR_POINTER: Pointer cursor
+ * @META_CURSOR_PROGRESS: Progress cursor
+ * @META_CURSOR_WAIT: Wait cursor
+ * @META_CURSOR_CELL: Cell cursor
+ * @META_CURSOR_CROSSHAIR: Crosshair cursor
+ * @META_CURSOR_TEXT: Text cursor
+ * @META_CURSOR_VERTICAL_TEXT: Vertical text cursor
+ * @META_CURSOR_ALIAS: DnD alias cursor
+ * @META_CURSOR_COPY: DnD copy cursor
+ * @META_CURSOR_MOVE: DnD move cursor
+ * @META_CURSOR_NO_DROP: DnD no drop cursor
+ * @META_CURSOR_NOT_ALLOWED: DnD not allowed cursor
+ * @META_CURSOR_GRAB: DnD grab cursor
+ * @META_CURSOR_GRABBING: DnD grabbing cursor
+ * @META_CURSOR_E_RESIZE: Resize eastern edge cursor
+ * @META_CURSOR_N_RESIZE: Resize northern edge cursor
* @META_CURSOR_NE_RESIZE: Resize north-eastern corner cursor
* @META_CURSOR_NW_RESIZE: Resize north-western corner cursor
- * @META_CURSOR_MOVE_OR_RESIZE_WINDOW: Move or resize cursor
- * @META_CURSOR_BUSY: Busy cursor
- * @META_CURSOR_DND_IN_DRAG: DND in drag cursor
- * @META_CURSOR_DND_MOVE: DND move cursor
- * @META_CURSOR_DND_COPY: DND copy cursor
- * @META_CURSOR_DND_UNSUPPORTED_TARGET: DND unsupported target
- * @META_CURSOR_POINTING_HAND: pointing hand
- * @META_CURSOR_CROSSHAIR: crosshair (action forbidden)
- * @META_CURSOR_IBEAM: I-beam (text input)
+ * @META_CURSOR_S_RESIZE: Resize southern edge cursor
+ * @META_CURSOR_SE_RESIZE: Resize south-eastern corner cursor
+ * @META_CURSOR_SW_RESIZE: Resize south-western corner cursor
+ * @META_CURSOR_W_RESIZE: Resize western edge cursor
+ * @META_CURSOR_EW_RESIZE: Resize eastern and western edges cursor
+ * @META_CURSOR_NS_RESIZE: Resize northern and eastern edges cursor
+ * @META_CURSOR_NESW_RESIZE: Resize north-east and south-west corners cursor
+ * @META_CURSOR_NWSE_RESIZE: Resize north-west and south-east corners cursor
+ * @META_CURSOR_COL_RESIZE: Resize column cursor
+ * @META_CURSOR_ROW_RESIZE: Resize row cursor
+ * @META_CURSOR_ALL_SCROLL: Scroll all directions cursor
+ * @META_CURSOR_ZOOM_IN: Zoom in cursor
+ * @META_CURSOR_ZOOM_OUT: Zoom out cursor
+ * @META_CURSOR_DND_ASK: DnD ask cursor
+ * @META_CURSOR_ALL_RESIZE: Resize all directions
*/
typedef enum
{
- META_CURSOR_NONE = 0,
+ META_CURSOR_INVALID = 0,
+ META_CURSOR_NONE,
META_CURSOR_DEFAULT,
- META_CURSOR_NORTH_RESIZE,
- META_CURSOR_SOUTH_RESIZE,
- META_CURSOR_WEST_RESIZE,
- META_CURSOR_EAST_RESIZE,
- META_CURSOR_SE_RESIZE,
- META_CURSOR_SW_RESIZE,
+ META_CURSOR_CONTEXT_MENU,
+ META_CURSOR_HELP,
+ META_CURSOR_POINTER,
+ META_CURSOR_PROGRESS,
+ META_CURSOR_WAIT,
+ META_CURSOR_CELL,
+ META_CURSOR_CROSSHAIR,
+ META_CURSOR_TEXT,
+ META_CURSOR_VERTICAL_TEXT,
+ META_CURSOR_ALIAS,
+ META_CURSOR_COPY,
+ META_CURSOR_MOVE,
+ META_CURSOR_NO_DROP,
+ META_CURSOR_NOT_ALLOWED,
+ META_CURSOR_GRAB,
+ META_CURSOR_GRABBING,
+ META_CURSOR_E_RESIZE,
+ META_CURSOR_N_RESIZE,
META_CURSOR_NE_RESIZE,
META_CURSOR_NW_RESIZE,
- META_CURSOR_MOVE_OR_RESIZE_WINDOW,
- META_CURSOR_BUSY,
- META_CURSOR_DND_IN_DRAG,
- META_CURSOR_DND_MOVE,
- META_CURSOR_DND_COPY,
- META_CURSOR_DND_UNSUPPORTED_TARGET,
- META_CURSOR_POINTING_HAND,
- META_CURSOR_CROSSHAIR,
- META_CURSOR_IBEAM,
- META_CURSOR_LAST
+ META_CURSOR_S_RESIZE,
+ META_CURSOR_SE_RESIZE,
+ META_CURSOR_SW_RESIZE,
+ META_CURSOR_W_RESIZE,
+ META_CURSOR_EW_RESIZE,
+ META_CURSOR_NS_RESIZE,
+ META_CURSOR_NESW_RESIZE,
+ META_CURSOR_NWSE_RESIZE,
+ META_CURSOR_COL_RESIZE,
+ META_CURSOR_ROW_RESIZE,
+ META_CURSOR_ALL_SCROLL,
+ META_CURSOR_ZOOM_IN,
+ META_CURSOR_ZOOM_OUT,
+ META_CURSOR_DND_ASK, /* not css */
+ META_CURSOR_ALL_RESIZE, /* not css */
} MetaCursor;
/**
diff --git a/src/ui/frames.c b/src/ui/frames.c
index 3c076b691..1f52aa097 100644
--- a/src/ui/frames.c
+++ b/src/ui/frames.c
@@ -1408,13 +1408,13 @@ meta_ui_frame_update_prelit_control (MetaUIFrame *frame,
cursor = META_CURSOR_SE_RESIZE;
break;
case META_FRAME_CONTROL_RESIZE_S:
- cursor = META_CURSOR_SOUTH_RESIZE;
+ cursor = META_CURSOR_S_RESIZE;
break;
case META_FRAME_CONTROL_RESIZE_SW:
cursor = META_CURSOR_SW_RESIZE;
break;
case META_FRAME_CONTROL_RESIZE_N:
- cursor = META_CURSOR_NORTH_RESIZE;
+ cursor = META_CURSOR_N_RESIZE;
break;
case META_FRAME_CONTROL_RESIZE_NE:
cursor = META_CURSOR_NE_RESIZE;
@@ -1423,10 +1423,10 @@ meta_ui_frame_update_prelit_control (MetaUIFrame *frame,
cursor = META_CURSOR_NW_RESIZE;
break;
case META_FRAME_CONTROL_RESIZE_W:
- cursor = META_CURSOR_WEST_RESIZE;
+ cursor = META_CURSOR_W_RESIZE;
break;
case META_FRAME_CONTROL_RESIZE_E:
- cursor = META_CURSOR_EAST_RESIZE;
+ cursor = META_CURSOR_E_RESIZE;
break;
}
diff --git a/src/wayland/meta-wayland-cursor-shape.c b/src/wayland/meta-wayland-cursor-shape.c
new file mode 100644
index 000000000..96a9dbae6
--- /dev/null
+++ b/src/wayland/meta-wayland-cursor-shape.c
@@ -0,0 +1,288 @@
+/*
+ * 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/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 MetaCursor
+shape_map[] = {
+ /* version 1 */
+ [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,
+ /* version 2 */
+ [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];
+}
+
+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;
+
+ 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);
+
+ 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 *tool_resource)
+{
+ MetaWaylandTabletTool *tool = wl_resource_get_user_data (tool_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);
+}
+
+void
+meta_wayland_init_cursor_shape (MetaWaylandCompositor *compositor)
+{
+ if (wl_global_create (compositor->wayland_display,
+ &wp_cursor_shape_manager_v1_interface,
+ META_WP_CURSOR_SHAPE_VERSION,
+ NULL, bind_cursor_shape) == NULL)
+ g_error ("Failed to register a global cursor-shape object");
+}
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 43d8be9b5..2016a930f 100644
--- a/src/wayland/meta-wayland-pointer.c
+++ b/src/wayland/meta-wayland-pointer.c
@@ -513,6 +513,7 @@ meta_wayland_pointer_enable (MetaWaylandPointer *pointer)
(GDestroyNotify) meta_wayland_pointer_client_free);
pointer->cursor_surface = NULL;
+ pointer->cursor_shape = META_CURSOR_INVALID;
clutter_seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
pointer->device = clutter_seat_get_pointer (clutter_seat);
@@ -566,6 +567,7 @@ meta_wayland_pointer_disable (MetaWaylandPointer *pointer)
g_clear_pointer (&pointer->pointer_clients, g_hash_table_unref);
pointer->cursor_surface = NULL;
+ pointer->cursor_shape = META_CURSOR_INVALID;
}
static int
@@ -1089,14 +1091,23 @@ meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer)
if (pointer->current)
{
- 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_sprite = META_CURSOR_SPRITE (sprite);
}
meta_cursor_tracker_set_window_cursor (cursor_tracker, cursor_sprite);
@@ -1126,10 +1137,12 @@ meta_wayland_pointer_set_cursor_surface (MetaWaylandPointer *pointer,
prev_cursor_surface = pointer->cursor_surface;
- if (prev_cursor_surface == cursor_surface)
+ if (prev_cursor_surface == cursor_surface &&
+ pointer->cursor_shape == META_CURSOR_INVALID)
return;
pointer->cursor_surface = cursor_surface;
+ pointer->cursor_shape = META_CURSOR_INVALID;
if (prev_cursor_surface)
{
@@ -1149,6 +1162,27 @@ 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);
+ }
+ else if (pointer->cursor_shape == shape)
+ {
+ return;
+ }
+
+ 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,
@@ -1159,15 +1193,11 @@ pointer_set_cursor (struct wl_client *client,
MetaWaylandPointer *pointer = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface;
- surface = (surface_resource ? wl_resource_get_user_data (surface_resource) : NULL);
-
- if (pointer->focus_surface == NULL)
- return;
- if (wl_resource_get_client (pointer->focus_surface->resource) != client)
- return;
- if (pointer->focus_serial - serial > G_MAXUINT32 / 2)
+ if (!meta_wayland_pointer_check_focus_serial (pointer, client, serial))
return;
+ surface = (surface_resource ? wl_resource_get_user_data (surface_resource) : NULL);
+
if (surface &&
!meta_wayland_surface_assign_role (surface,
META_TYPE_WAYLAND_CURSOR_SURFACE,
@@ -1402,3 +1432,18 @@ meta_wayland_pointer_class_init (MetaWaylandPointerClass *klass)
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
+
+gboolean
+meta_wayland_pointer_check_focus_serial (MetaWaylandPointer *pointer,
+ struct wl_client *client,
+ uint32_t serial)
+{
+ if (pointer->focus_surface == NULL)
+ return FALSE;
+ if (wl_resource_get_client (pointer->focus_surface->resource) != client)
+ return FALSE;
+ if (pointer->focus_serial - serial > G_MAXUINT32 / 2)
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/src/wayland/meta-wayland-pointer.h b/src/wayland/meta-wayland-pointer.h
index 80087c0be..1b0cdecd1 100644
--- a/src/wayland/meta-wayland-pointer.h
+++ b/src/wayland/meta-wayland-pointer.h
@@ -80,6 +80,7 @@ struct _MetaWaylandPointer
MetaWaylandPointerGrab *grab;
MetaWaylandPointerGrab default_grab;
+ MetaCursor cursor_shape;
guint32 grab_button;
guint32 grab_serial;
guint32 grab_time;
@@ -159,4 +160,11 @@ void meta_wayland_surface_cursor_update (MetaWaylandSurface *cursor_surface);
void meta_wayland_pointer_update_cursor_surface (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);
+
#endif /* META_WAYLAND_POINTER_H */
diff --git a/src/wayland/meta-wayland-tablet-tool.c b/src/wayland/meta-wayland-tablet-tool.c
index e960cc63b..72a8e887f 100644
--- a/src/wayland/meta-wayland-tablet-tool.c
+++ b/src/wayland/meta-wayland-tablet-tool.c
@@ -81,7 +81,7 @@ move_resources_for_client (struct wl_list *destination,
static void
meta_wayland_tablet_tool_update_cursor_surface (MetaWaylandTabletTool *tool)
{
- MetaCursorSprite *cursor = NULL;
+ g_autoptr (MetaCursorSprite) cursor_sprite = NULL;
if (tool->cursor_renderer == NULL)
return;
@@ -93,18 +93,29 @@ meta_wayland_tablet_tool_update_cursor_surface (MetaWaylandTabletTool *tool)
{
MetaWaylandCursorSurface *cursor_surface =
META_WAYLAND_CURSOR_SURFACE (tool->cursor_surface->role);
+ MetaCursorSprite *sprite;
+
+ 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_sprite = META_CURSOR_SPRITE (sprite);
- cursor = meta_wayland_cursor_surface_get_sprite (cursor_surface);
}
- else
- cursor = NULL;
}
else if (tool->current_tablet)
- cursor = META_CURSOR_SPRITE (tool->default_sprite);
- else
- cursor = NULL;
+ {
+ MetaCursorSprite *sprite;
+
+ sprite = META_CURSOR_SPRITE (tool->default_sprite);
+ cursor_sprite = g_object_ref (sprite);
+ }
- meta_cursor_renderer_set_cursor (tool->cursor_renderer, cursor);
+ meta_cursor_renderer_set_cursor (tool->cursor_renderer, cursor_sprite);
}
static void
@@ -126,6 +137,7 @@ meta_wayland_tablet_tool_set_cursor_surface (MetaWaylandTabletTool *tool,
}
tool->cursor_surface = surface;
+ tool->cursor_shape = META_CURSOR_INVALID;
if (tool->cursor_surface)
{
@@ -393,6 +405,27 @@ tablet_tool_handle_cursor_surface_destroy (struct wl_listener *listener,
meta_wayland_tablet_tool_set_cursor_surface (tool, NULL);
}
+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 void
tool_cursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor,
int x,
@@ -483,17 +516,11 @@ tool_set_cursor (struct wl_client *client,
MetaWaylandTabletTool *tool = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface;
- surface = (surface_resource ? wl_resource_get_user_data (surface_resource) : NULL);
-
- if (tool->focus_surface == NULL)
- return;
- if (tool->cursor_renderer == NULL)
- return;
- if (wl_resource_get_client (tool->focus_surface->resource) != client)
- return;
- if (tool->proximity_serial - serial > G_MAXUINT32 / 2)
+ if (!meta_wayland_tablet_tool_check_focus_serial (tool, client, serial))
return;
+ surface = (surface_resource ? wl_resource_get_user_data (surface_resource) : NULL);
+
if (surface &&
!meta_wayland_surface_assign_role (surface,
META_TYPE_WAYLAND_TABLET_CURSOR_SURFACE,
@@ -1018,3 +1045,20 @@ meta_wayland_tablet_tool_can_popup (MetaWaylandTabletTool *tool,
{
return tool->down_serial == serial || tool->button_serial == serial;
}
+
+gboolean
+meta_wayland_tablet_tool_check_focus_serial (MetaWaylandTabletTool *tool,
+ struct wl_client *client,
+ uint32_t serial)
+{
+ if (tool->focus_surface == NULL)
+ return FALSE;
+ if (tool->cursor_renderer == NULL)
+ return FALSE;
+ if (wl_resource_get_client (tool->focus_surface->resource) != client)
+ return FALSE;
+ if (tool->proximity_serial - serial > G_MAXUINT32 / 2)
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/src/wayland/meta-wayland-tablet-tool.h b/src/wayland/meta-wayland-tablet-tool.h
index 7cf1d9077..a9c3b60d8 100644
--- a/src/wayland/meta-wayland-tablet-tool.h
+++ b/src/wayland/meta-wayland-tablet-tool.h
@@ -46,6 +46,8 @@ struct _MetaWaylandTabletTool
MetaCursorSpriteXcursor *default_sprite;
gulong prepare_at_signal_id;
+ MetaCursor cursor_shape;
+
MetaWaylandSurface *current;
guint32 pressed_buttons;
guint32 button_count;
@@ -88,4 +90,11 @@ gboolean meta_wayland_tablet_tool_can_grab_surface (MetaWaylandTabletTool *tool,
gboolean meta_wayland_tablet_tool_can_popup (MetaWaylandTabletTool *tool,
uint32_t serial);
+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);
+
#endif /* META_WAYLAND_TABLET_TOOL_H */
diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h
index 6d2dbd7bc..4ac4716da 100644
--- a/src/wayland/meta-wayland-versions.h
+++ b/src/wayland/meta-wayland-versions.h
@@ -57,5 +57,6 @@
#define META_XDG_ACTIVATION_V1_VERSION 1
#define META_XDG_DIALOG_VERSION 1
#define META_ZWP_PRIMARY_SELECTION_V1_VERSION 1
+#define META_WP_CURSOR_SHAPE_VERSION 2
#endif
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index aeb39ec5d..8b8d4f8cf 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -32,6 +32,7 @@
#include "clutter/wayland/clutter-wayland-compositor.h"
#include "core/main-private.h"
#include "wayland/meta-wayland-activation.h"
+#include "wayland/meta-wayland-cursor-shape.h"
#include "wayland/meta-wayland-data-device.h"
#include "wayland/meta-wayland-dma-buf.h"
#include "wayland/meta-wayland-egl-stream.h"
@@ -442,6 +443,7 @@ meta_wayland_compositor_setup (MetaWaylandCompositor *wayland_compositor)
meta_wayland_text_input_init (compositor);
meta_wayland_activation_init (compositor);
meta_wayland_init_xdg_wm_dialog (compositor);
+ meta_wayland_init_cursor_shape (compositor);
/* Xwayland specific protocol, needs to be filtered out for all other clients */
if (meta_xwayland_grab_keyboard_init (compositor))
diff --git a/src/wayland/protocol/cursor-shape-v1.xml b/src/wayland/protocol/cursor-shape-v1.xml
new file mode 100644
index 000000000..64b2f9b2c
--- /dev/null
+++ b/src/wayland/protocol/cursor-shape-v1.xml
@@ -0,0 +1,162 @@
+
+
+
+ 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.
+
+
+
+
+
+
diff --git a/src/x11/meta-x11-display.c b/src/x11/meta-x11-display.c
index 53dc3450e..2af3b39de 100644
--- a/src/x11/meta-x11-display.c
+++ b/src/x11/meta-x11-display.c
@@ -1580,10 +1580,16 @@ void
meta_x11_display_reload_cursor (MetaX11Display *x11_display)
{
Cursor xcursor;
- MetaCursor cursor = x11_display->display->current_cursor;
/* Set a cursor for X11 applications that don't specify their own */
- xcursor = meta_x11_display_create_x_cursor (x11_display, cursor);
+ xcursor = XcursorLibraryLoadCursor (x11_display->xdisplay,
+ meta_cursor_get_name (META_CURSOR_DEFAULT));
+
+ if (!xcursor)
+ {
+ xcursor = XcursorLibraryLoadCursor (x11_display->xdisplay,
+ meta_cursor_get_legacy_name (META_CURSOR_DEFAULT));
+ }
XDefineCursor (x11_display->xdisplay, x11_display->xroot, xcursor);
XFlush (x11_display->xdisplay);