diff --git a/gen/cursors.py b/gen/cursors.py index 03b539b7c..a27ee4dc3 100755 --- a/gen/cursors.py +++ b/gen/cursors.py @@ -70,6 +70,7 @@ def main(args: List[str]=sys.argv) -> None: glfw_css_map = {} css_to_enum = {} xc_to_enum = {} + glfw_wayland = {} for line in cursors.splitlines(): line = line.strip() if line: @@ -83,6 +84,7 @@ def main(args: List[str]=sys.argv) -> None: glfw_css_map[glfw_name] = css css_to_enum[css] = enum_name css_names.append(css) + glfw_wayland[glfw_name] = 'WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_' + wayland.replace('-', '_').upper() for n in names: kitty_to_enum_map[n] = enum_name glfw_enum.append(glfw_name) @@ -112,6 +114,7 @@ def main(args: List[str]=sys.argv) -> None: glfw_enum.append('GLFW_INVALID_CURSOR') patch_file('glfw/glfw3.h', 'mouse cursor shapes', '\n'.join(f' {x},' for x in glfw_enum)) + patch_file('glfw/wl_window.c', 'glfw to wayland mapping', '\n'.join(f' C({g}, {x});' for g, x in glfw_wayland.items())) patch_file('glfw/wl_window.c', 'glfw to xc mapping', '\n'.join(f' C({g}, {x});' for g, x in glfw_xc_map.items())) patch_file('glfw/x11_window.c', 'glfw to xc mapping', '\n'.join(f' {x}' for x in glfw_xfont_map)) patch_file('kitty/data-types.h', 'mouse shapes', '\n'.join(f' {x},' for x in enum_to_glfw_map)) @@ -139,7 +142,7 @@ def main(args: List[str]=sys.argv) -> None: f'\t{x} PointerShape = {i}' for i, x in enumerate(enum_to_glfw_map)), start_marker='// ', end_marker='') patch_file('tools/tui/loop/mouse.go', 'pointer shape tostring', '\n'.join( f'''\tcase {x}: return "{x.lower().rpartition('_')[0].replace('_', '-')}"''' for x in enum_to_glfw_map), start_marker='// ', end_marker='') - patch_file('kittens/mouse_demo/main.go', 'all pointer shapes', '\n'.join( + patch_file('tools/cmd/mouse_demo/main.go', 'all pointer shapes', '\n'.join( f'\tloop.{x},' for x in enum_to_glfw_map), start_marker='// ', end_marker='') subprocess.check_call(['glfw/glfw.py']) diff --git a/glfw/wl_init.c b/glfw/wl_init.c index 502ce761d..7b9aabf00 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -572,9 +572,16 @@ static void seatHandleCapabilities(void* data UNUSED, { _glfw.wl.pointer = wl_seat_get_pointer(seat); wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL); + if (_glfw.wl.wp_cursor_shape_manager_v1) { + if (_glfw.wl.wp_cursor_shape_device_v1) wp_cursor_shape_device_v1_destroy(_glfw.wl.wp_cursor_shape_device_v1); + _glfw.wl.wp_cursor_shape_device_v1 = NULL; + _glfw.wl.wp_cursor_shape_device_v1 = wp_cursor_shape_manager_v1_get_pointer(_glfw.wl.wp_cursor_shape_manager_v1, _glfw.wl.pointer); + } } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer) { + if (_glfw.wl.wp_cursor_shape_device_v1) wp_cursor_shape_device_v1_destroy(_glfw.wl.wp_cursor_shape_device_v1); + _glfw.wl.wp_cursor_shape_device_v1 = NULL; wl_pointer_destroy(_glfw.wl.pointer); _glfw.wl.pointer = NULL; if (_glfw.wl.cursorAnimationTimer) toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 0); @@ -716,6 +723,9 @@ static void registryHandleGlobal(void* data UNUSED, else if (is(xdg_activation_v1)) { _glfw.wl.xdg_activation_v1 = wl_registry_bind(registry, name, &xdg_activation_v1_interface, 1); } + else if (false && is(wp_cursor_shape_manager_v1)) { + _glfw.wl.wp_cursor_shape_manager_v1 = wl_registry_bind(registry, name, &wp_cursor_shape_manager_v1_interface, 1); + } #undef is } @@ -950,6 +960,9 @@ void _glfwPlatformTerminate(void) zwp_primary_selection_device_manager_v1_destroy(_glfw.wl.primarySelectionDeviceManager); if (_glfw.wl.xdg_activation_v1) xdg_activation_v1_destroy(_glfw.wl.xdg_activation_v1); + if (_glfw.wl.wp_cursor_shape_manager_v1) + wp_cursor_shape_manager_v1_destroy(_glfw.wl.wp_cursor_shape_manager_v1); + if (_glfw.wl.registry) wl_registry_destroy(_glfw.wl.registry); if (_glfw.wl.display) diff --git a/glfw/wl_platform.h b/glfw/wl_platform.h index 5490e8133..60b77efbe 100644 --- a/glfw/wl_platform.h +++ b/glfw/wl_platform.h @@ -60,6 +60,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #include "wayland-primary-selection-unstable-v1-client-protocol.h" #include "wl_text_input.h" #include "wayland-xdg-activation-v1-client-protocol.h" +#include "wayland-cursor-shape-v1-client-protocol.h" #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) @@ -286,6 +287,8 @@ typedef struct _GLFWlibraryWayland struct zwp_primary_selection_device_v1* primarySelectionDevice; struct zwp_primary_selection_source_v1* dataSourceForPrimarySelection; struct xdg_activation_v1* xdg_activation_v1; + struct wp_cursor_shape_manager_v1* wp_cursor_shape_manager_v1; + struct wp_cursor_shape_device_v1* wp_cursor_shape_device_v1; int compositorVersion; int seatVersion; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index b64a29ca6..3775a4ef0 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -152,10 +152,58 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image, bool is_opaque, return buffer; } +static int +glfw_cursor_shape_to_wayland_cursor_shape(GLFWCursorShape g) { +#define C(g, w) case g: return w; + switch(g) { + /* start glfw to wayland mapping (auto generated by gen-key-constants.py do not edit) */ + C(GLFW_DEFAULT_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT); + C(GLFW_TEXT_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT); + C(GLFW_POINTER_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER); + C(GLFW_HELP_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_HELP); + C(GLFW_WAIT_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_WAIT); + C(GLFW_PROGRESS_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_PROGRESS); + C(GLFW_CROSSHAIR_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR); + C(GLFW_CELL_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CELL); + C(GLFW_VERTICAL_TEXT_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_VERTICAL_TEXT); + C(GLFW_MOVE_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE); + C(GLFW_E_RESIZE_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_E_RESIZE); + C(GLFW_NE_RESIZE_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE); + C(GLFW_NW_RESIZE_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE); + C(GLFW_N_RESIZE_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_N_RESIZE); + C(GLFW_SE_RESIZE_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SE_RESIZE); + C(GLFW_SW_RESIZE_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE); + C(GLFW_S_RESIZE_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_S_RESIZE); + C(GLFW_W_RESIZE_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_W_RESIZE); + C(GLFW_EW_RESIZE_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE); + C(GLFW_NS_RESIZE_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE); + C(GLFW_NESW_RESIZE_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE); + C(GLFW_NWSE_RESIZE_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE); + C(GLFW_ZOOM_IN_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_IN); + C(GLFW_ZOOM_OUT_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_OUT); + C(GLFW_ALIAS_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALIAS); + C(GLFW_COPY_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_COPY); + C(GLFW_NOT_ALLOWED_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NOT_ALLOWED); + C(GLFW_NO_DROP_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NO_DROP); + C(GLFW_GRAB_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRAB); + C(GLFW_GRABBING_CURSOR, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRABBING); +/* end glfw to wayland mapping */ + default: return -1; + } +#undef C +} + static void setCursorImage(_GLFWwindow* window, bool on_theme_change) { _GLFWcursorWayland defaultCursor = {.shape = GLFW_DEFAULT_CURSOR}; _GLFWcursorWayland* cursorWayland = window->cursor ? &window->cursor->wl : &defaultCursor; + if (_glfw.wl.wp_cursor_shape_device_v1) { + int which = glfw_cursor_shape_to_wayland_cursor_shape(cursorWayland->shape); + if (which > -1) { + wp_cursor_shape_device_v1_set_shape(_glfw.wl.wp_cursor_shape_device_v1, _glfw.wl.serial, (uint32_t)which); + return; + } + } struct wl_cursor_image* image = NULL; struct wl_buffer* buffer = NULL; struct wl_surface* surface = _glfw.wl.cursorSurface; @@ -717,7 +765,7 @@ static void incrementCursorImage(_GLFWwindow* window) { if (window && window->wl.decorations.focus == CENTRAL_WINDOW && window->cursorMode != GLFW_CURSOR_HIDDEN) { _GLFWcursor* cursor = window->wl.currentCursor; - if (cursor && cursor->wl.cursor) + if (cursor && cursor->wl.cursor && cursor->wl.cursor->image_count) { cursor->wl.currentImage += 1; cursor->wl.currentImage %= cursor->wl.cursor->image_count;