diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 27 | ||||
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Screen_Driver.H | 6 | ||||
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx | 105 | ||||
| -rw-r--r-- | src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx | 13 |
4 files changed, 137 insertions, 14 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b5f10cc0d..55f5166b2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ # # CMakeLists.txt to build the FLTK library using CMake (www.cmake.org) # -# 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 @@ -835,6 +835,31 @@ if(UNIX AND FLTK_USE_WAYLAND) list(APPEND SHARED_FILES "xdg-dialog-protocol.c") endif() + if(HAVE_CURSOR_SHAPE) + set(INFILE ${PROTOCOLS}/staging/cursor-shape/cursor-shape-v1.xml) + add_custom_command( + OUTPUT cursor-shape-protocol.c cursor-shape-client-protocol.h + COMMAND wayland-scanner private-code ${INFILE} cursor-shape-protocol.c + COMMAND wayland-scanner client-header ${INFILE} cursor-shape-client-protocol.h + DEPENDS ${INFILE} + VERBATIM + ) + list(APPEND STATIC_FILES "cursor-shape-protocol.c") + list(APPEND SHARED_FILES "cursor-shape-protocol.c") +# File cursor-shape-protocol.c requires memory data allocated by the "Tablet" protocol +# but that protocol's header file is not necessary for the "cursor shape" protocol itself. + set(INFILE ${PROTOCOLS}/stable/tablet/tablet-v2.xml) + add_custom_command( + OUTPUT tablet-protocol.c # tablet-client-protocol.h + COMMAND wayland-scanner private-code ${INFILE} tablet-protocol.c +# COMMAND wayland-scanner client-header ${INFILE} tablet-client-protocol.h + DEPENDS ${INFILE} + VERBATIM + ) + list(APPEND STATIC_FILES "tablet-protocol.c") + list(APPEND SHARED_FILES "tablet-protocol.c") + endif() + if(STOP_REQUIRED) message(FATAL_ERROR "*** Terminating: one or more required file(s) were not found. ***") endif() 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'. |
