summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
authorManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2026-01-05 15:05:25 +0100
committerManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2026-01-05 15:05:25 +0100
commit522728de8cf1d4f24ab5d56ab400b8d6676228b4 (patch)
treebf7595024fdcb59e4f6db4bc9726d2ed02eef161 /src/drivers
parent11325da073a78b5a012e64b9732e253b50289763 (diff)
Wayland: use modern approach to cursor shapes with the "Cursor shape" protocol.
This removes the need to guess names of files each theme gives to cursor shapes and makes linking with dbus superfluous when the compositor supports the new protocol. The old, surface-based approach to cursor shapes remains used for custom shapes.
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Screen_Driver.H6
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx105
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx13
3 files changed, 111 insertions, 13 deletions
diff --git a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H
index 084e0c967..8ef7a1e10 100644
--- a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H
+++ b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H
@@ -2,7 +2,7 @@
// Definition of the Wayland Screen interface
// for the Fast Light Tool Kit (FLTK).
//
-// Copyright 2010-2024 by Bill Spitzak and others.
+// Copyright 2010-2026 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -110,6 +110,10 @@ public:
#if HAVE_XDG_DIALOG
struct xdg_wm_dialog_v1 *xdg_wm_dialog;
#endif
+#if HAVE_CURSOR_SHAPE
+ struct wp_cursor_shape_manager_v1 *wp_cursor_shape_manager;
+ struct wp_cursor_shape_device_v1 *wp_cursor_shape_device;
+#endif
// constructor
Fl_Wayland_Screen_Driver();
diff --git a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx
index a0911cb51..ea4c8f97c 100644
--- a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx
+++ b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx
@@ -1,7 +1,7 @@
//
// Implementation of Wayland Screen interface
//
-// Copyright 1998-2025 by Bill Spitzak and others.
+// Copyright 1998-2026 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -39,6 +39,9 @@
#if HAVE_XDG_DIALOG
# include "xdg-dialog-client-protocol.h"
#endif
+#if HAVE_CURSOR_SHAPE
+# include "cursor-shape-client-protocol.h"
+#endif
#include <assert.h>
#include <sys/mman.h>
#include <poll.h>
@@ -127,7 +130,7 @@ void Fl_Wayland_Screen_Driver::do_set_cursor(
struct wl_buffer *buffer;
const int scale = seat->pointer_scale;
- if (!seat->cursor_theme || !seat->wl_pointer)
+ if ((!seat->cursor_theme && !wl_cursor) || !seat->wl_pointer)
return;
if (!wl_cursor) wl_cursor = seat->default_cursor;
@@ -226,7 +229,48 @@ static void pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t se
// use custom cursor if present
struct wl_cursor *cursor =
fl_wl_xid(win)->custom_cursor ? fl_wl_xid(win)->custom_cursor->wl_cursor : NULL;
- Fl_Wayland_Screen_Driver::do_set_cursor(seat, cursor);
+#if HAVE_CURSOR_SHAPE
+ static struct cursor_shape_struct {
+ Fl_Cursor c;
+ int shape;
+ } cursor_shape_array[] = {
+ {FL_CURSOR_ARROW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT },
+ {FL_CURSOR_CROSS, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR },
+ {FL_CURSOR_WAIT, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_WAIT },
+ {FL_CURSOR_INSERT, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT },
+ {FL_CURSOR_HAND, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRAB },
+ {FL_CURSOR_HELP, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_HELP },
+ {FL_CURSOR_MOVE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE },
+ {FL_CURSOR_N, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_N_RESIZE },
+ {FL_CURSOR_E, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_E_RESIZE },
+ {FL_CURSOR_W, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_W_RESIZE },
+ {FL_CURSOR_S, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_S_RESIZE },
+ {FL_CURSOR_NS, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE },
+ {FL_CURSOR_WE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE },
+ {FL_CURSOR_SW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE },
+ {FL_CURSOR_SE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SE_RESIZE },
+ {FL_CURSOR_NE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE },
+ {FL_CURSOR_NW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE },
+ {FL_CURSOR_NESW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE },
+ {FL_CURSOR_NWSE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE }
+ };
+
+ Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
+ if (scr_driver->wp_cursor_shape_device && !cursor) {
+ int shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
+ for (int i = 0; i < sizeof(cursor_shape_array)/sizeof(cursor_shape_struct); i++) {
+ if (cursor_shape_array[i].c == Fl_Wayland_Window_Driver::driver(win)->standard_cursor()) {
+ shape = cursor_shape_array[i].shape;
+ break;
+ }
+ }
+ wp_cursor_shape_device_v1_set_shape(scr_driver->wp_cursor_shape_device, serial, shape);
+ } else {
+#endif
+ Fl_Wayland_Screen_Driver::do_set_cursor(seat, cursor);
+#if HAVE_CURSOR_SHAPE
+ }
+#endif
seat->serial = serial;
seat->pointer_enter_serial = serial;
set_event_xy(win);
@@ -472,6 +516,15 @@ static struct wl_surface_listener cursor_surface_listener = {
static void init_cursors(struct Fl_Wayland_Screen_Driver::seat *seat) {
+ Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
+ if (!seat->cursor_surface) {
+ seat->cursor_surface = wl_compositor_create_surface(scr_driver->wl_compositor);
+ wl_surface_add_listener(seat->cursor_surface, &cursor_surface_listener, seat);
+ }
+#if HAVE_CURSOR_SHAPE
+ if (scr_driver->wp_cursor_shape_manager) return;
+#endif
+
char *name;
int size;
struct wl_cursor_theme *theme;
@@ -481,10 +534,8 @@ static void init_cursors(struct Fl_Wayland_Screen_Driver::seat *seat) {
size = 24;
}
size *= seat->pointer_scale;
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
theme = wl_cursor_theme_load(name, size, scr_driver->wl_shm);
free(name);
- //struct wl_cursor_theme *old_theme = seat->cursor_theme;
if (theme != NULL) {
if (seat->cursor_theme) {
// caution to destroy theme because Fl_Wayland_Window_Driver::set_cursor(Fl_Cursor) caches used cursors
@@ -497,10 +548,6 @@ static void init_cursors(struct Fl_Wayland_Screen_Driver::seat *seat) {
seat->default_cursor = scr_driver->xc_cursor[Fl_Wayland_Screen_Driver::arrow] =
wl_cursor_theme_get_cursor(seat->cursor_theme, "left_ptr");
}
- if (!seat->cursor_surface) {
- seat->cursor_surface = wl_compositor_create_surface(scr_driver->wl_compositor);
- wl_surface_add_listener(seat->cursor_surface, &cursor_surface_listener, seat);
- }
}
@@ -1043,12 +1090,19 @@ void Fl_Wayland_Screen_Driver::disable_im() {
static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
{
+ Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
struct Fl_Wayland_Screen_Driver::seat *seat =
(struct Fl_Wayland_Screen_Driver::seat*)data;
if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !seat->wl_pointer) {
seat->wl_pointer = wl_seat_get_pointer(wl_seat);
wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, seat);
seat->pointer_scale = 1;
+#if HAVE_CURSOR_SHAPE
+ if (scr_driver->wp_cursor_shape_manager) {
+ scr_driver->wp_cursor_shape_device =
+ wp_cursor_shape_manager_v1_get_pointer(scr_driver->wp_cursor_shape_manager, seat->wl_pointer);
+ }
+#endif // HAVE_CURSOR_SHAPE
init_cursors(seat);
} else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && seat->wl_pointer) {
wl_pointer_release(seat->wl_pointer);
@@ -1066,7 +1120,6 @@ static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capa
wl_keyboard_release(seat->wl_keyboard);
seat->wl_keyboard = NULL;
}
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
scr_driver->enable_im();
}
@@ -1334,6 +1387,11 @@ static void registry_handle_global(void *user_data, struct wl_registry *wl_regis
scr_driver->xdg_wm_dialog = (struct xdg_wm_dialog_v1 *)
wl_registry_bind(wl_registry, id, &xdg_wm_dialog_v1_interface, 1);
#endif // HAVE_XDG_DIALOG
+#if HAVE_CURSOR_SHAPE
+ } else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) {
+ scr_driver->wp_cursor_shape_manager = (struct wp_cursor_shape_manager_v1 *)
+ wl_registry_bind(wl_registry, id, &wp_cursor_shape_manager_v1_interface, 1);
+#endif // HAVE_CURSOR_SHAPE
}
}
@@ -1412,6 +1470,10 @@ Fl_Wayland_Screen_Driver::Fl_Wayland_Screen_Driver() : Fl_Unix_Screen_Driver() {
#if HAVE_XDG_DIALOG
xdg_wm_dialog = NULL;
#endif
+#if HAVE_CURSOR_SHAPE
+ wp_cursor_shape_manager = NULL;
+ wp_cursor_shape_device = NULL;
+#endif
}
@@ -1432,7 +1494,12 @@ static void sync_done(void *data, struct wl_callback *cb, uint32_t time) {
Fl_Wayland_Screen_Driver::compositor = (pair->found_wf_shell ?
Fl_Wayland_Screen_Driver::WAYFIRE : Fl_Wayland_Screen_Driver::MUTTER);
}
- if (scr_driver->seat) try_update_cursor(scr_driver->seat);
+ if (scr_driver->seat) {
+#if HAVE_CURSOR_SHAPE
+ if (!scr_driver->wp_cursor_shape_manager)
+#endif
+ try_update_cursor(scr_driver->seat);
+ }
if (Fl_Wayland_Screen_Driver::compositor != Fl_Wayland_Screen_Driver::OWL) scr_driver->init_workarea();
}
@@ -1566,6 +1633,22 @@ void Fl_Wayland_Screen_Driver::close_display() {
xdg_wm_base_destroy(xdg_wm_base); xdg_wm_base = NULL;
Fl_Wayland_Plugin *plugin = Fl_Wayland_Window_Driver::gl_plugin();
if (plugin) plugin->terminate();
+#if HAVE_XDG_DIALOG
+ if (xdg_wm_dialog) {
+ xdg_wm_dialog_v1_destroy(xdg_wm_dialog);
+ xdg_wm_dialog = NULL;
+ }
+#endif // HAVE_XDG_DIALOG
+#if HAVE_CURSOR_SHAPE
+ if (wp_cursor_shape_device ) {
+ wp_cursor_shape_device_v1_destroy(wp_cursor_shape_device);
+ wp_cursor_shape_device = NULL;
+ }
+ if (wp_cursor_shape_manager ) {
+ wp_cursor_shape_manager_v1_destroy(wp_cursor_shape_manager);
+ wp_cursor_shape_manager = NULL;
+ }
+#endif // HAVE_CURSOR_SHAPE
Fl::remove_fd(wl_display_get_fd(Fl_Wayland_Screen_Driver::wl_display));
wl_registry_destroy(wl_registry); wl_registry = NULL;
diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
index 7cd9810a9..9b709ee0a 100644
--- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
+++ b/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx
@@ -1,7 +1,7 @@
//
// Implementation of the Wayland window driver.
//
-// Copyright 1998-2025 by Bill Spitzak and others.
+// Copyright 1998-2026 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -1682,6 +1682,17 @@ void Fl_Wayland_Window_Driver::makeWindow()
int Fl_Wayland_Window_Driver::set_cursor(Fl_Cursor c) {
Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
struct wld_window *xid = (struct wld_window *)Fl_Window_Driver::xid(pWindow);
+#if HAVE_CURSOR_SHAPE
+ if (scr_driver->wp_cursor_shape_device) {
+ if (xid->custom_cursor) {
+ delete_cursor(xid->custom_cursor);
+ xid->custom_cursor = NULL;
+ }
+ if (c == FL_CURSOR_NONE) return 0;
+ standard_cursor_ = c;
+ return 1;
+ }
+#endif // HAVE_CURSOR_SHAPE
if (!scr_driver->seat->cursor_theme) return 1;
// Cursor names are the files of directory /usr/share/icons/XXXX/cursors/
// where XXXX is the name of the current 'cursor theme'.