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);