Wayland: Add support for the new cursor-shape protocol

It is currently disabled because no compositor seems to support it.
Hyprland reports it as available but using it causes Hyprland to crash.
Plasma 6 is supposed to have it but I am not installing a beta just for
this.

Typical Wayland.
This commit is contained in:
Kovid Goyal 2023-12-24 18:45:17 +05:30
parent 7d8c017215
commit cff490f881
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 69 additions and 2 deletions

View File

@ -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'])

13
glfw/wl_init.c vendored
View File

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

3
glfw/wl_platform.h vendored
View File

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

50
glfw/wl_window.c vendored
View File

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