wayland: Add cursor-shape-v1 protocol support

This commit is contained in:
Frank Praznik
2024-03-12 19:49:36 -04:00
parent 9bdb992925
commit c2e9693de5
6 changed files with 307 additions and 39 deletions

View File

@@ -56,13 +56,14 @@
#define BTN_SIDE (0x113)
#define BTN_EXTRA (0x114)
#endif
#include "../../events/SDL_keysym_to_scancode_c.h"
#include "../../events/imKStoUCS.h"
#include <errno.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-compose.h>
#include "../../events/imKStoUCS.h"
#include "../../events/SDL_keysym_to_scancode_c.h"
#include <xkbcommon/xkbcommon.h>
#include "cursor-shape-v1-client-protocol.h"
/* Weston uses a ratio of 10 units per scroll tick */
#define WAYLAND_WHEEL_AXIS_UNIT 10
@@ -245,6 +246,17 @@ void Wayland_RegisterTimestampListeners(struct SDL_WaylandInput *input)
}
}
void Wayland_CreateCursorShapeDevice(struct SDL_WaylandInput *input)
{
SDL_VideoData *viddata = input->display;
if (viddata->cursor_shape_manager) {
if (input->pointer && !input->cursor_shape) {
input->cursor_shape = wp_cursor_shape_manager_v1_get_pointer(viddata->cursor_shape_manager, input->pointer);
}
}
}
/* Returns SDL_TRUE if a key repeat event was due */
static SDL_bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, Uint64 elapsed)
{
@@ -1696,10 +1708,17 @@ static void seat_handle_capabilities(void *data, struct wl_seat *seat,
input->pointer = wl_seat_get_pointer(seat);
SDL_memset(&input->pointer_curr_axis_info, 0, sizeof(input->pointer_curr_axis_info));
input->display->pointer = input->pointer;
Wayland_CreateCursorShapeDevice(input);
wl_pointer_set_user_data(input->pointer, input);
wl_pointer_add_listener(input->pointer, &pointer_listener,
input);
} else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
if (input->cursor_shape) {
wp_cursor_shape_device_v1_destroy(input->cursor_shape);
input->cursor_shape = NULL;
}
wl_pointer_destroy(input->pointer);
input->pointer = NULL;
input->display->pointer = NULL;
@@ -3066,6 +3085,10 @@ void Wayland_display_destroy_input(SDL_VideoData *d)
}
}
if (input->cursor_shape) {
wp_cursor_shape_device_v1_destroy(input->cursor_shape);
}
if (input->pointer) {
if (wl_pointer_get_version(input->pointer) >= WL_POINTER_RELEASE_SINCE_VERSION) {
wl_pointer_release(input->pointer);

View File

@@ -102,6 +102,7 @@ struct SDL_WaylandInput
SDL_WaylandDataDevice *data_device;
SDL_WaylandPrimarySelectionDevice *primary_selection_device;
SDL_WaylandTextInput *text_input;
struct wp_cursor_shape_device_v1 *cursor_shape;
struct zwp_relative_pointer_v1 *relative_pointer;
struct zwp_input_timestamps_v1 *keyboard_timestamps;
struct zwp_input_timestamps_v1 *pointer_timestamps;
@@ -209,6 +210,7 @@ extern void Wayland_input_add_tablet(struct SDL_WaylandInput *input, struct SDL_
extern void Wayland_input_destroy_tablet(struct SDL_WaylandInput *input);
extern void Wayland_RegisterTimestampListeners(struct SDL_WaylandInput *input);
extern void Wayland_CreateCursorShapeDevice(struct SDL_WaylandInput *input);
/* The implicit grab serial needs to be updated on:
* - Keyboard key down/up

View File

@@ -41,6 +41,8 @@
#include "wayland-cursor.h"
#include "SDL_waylandmouse.h"
#include "cursor-shape-v1-client-protocol.h"
#include "../../SDL_hints_c.h"
static SDL_Cursor *sys_cursors[SDL_HITTEST_RESIZE_LEFT + 1];
@@ -529,14 +531,19 @@ static SDL_Cursor *Wayland_CreateSystemCursor(SDL_SystemCursor id)
SDL_free(cursor);
return NULL;
}
cursor->driverdata = (void *)cdata;
cdata->surface = wl_compositor_create_surface(data->compositor);
wl_surface_set_user_data(cdata->surface, NULL);
/* Note that we can't actually set any other cursor properties, as this
/* The surface is only necessary if the cursor shape manager is not present.
*
* Note that we can't actually set any other cursor properties, as this
* is output-specific. See wayland_get_system_cursor for the rest!
*/
if (!data->cursor_shape_manager) {
cdata->surface = wl_compositor_create_surface(data->compositor);
wl_surface_set_user_data(cdata->surface, NULL);
}
cdata->system_cursor = id;
}
@@ -581,6 +588,79 @@ static void Wayland_FreeCursor(SDL_Cursor *cursor)
SDL_free(cursor);
}
static void Wayland_SetSystemCursorShape(struct SDL_WaylandInput *input, SDL_SystemCursor id)
{
Uint32 shape;
switch (id) {
case SDL_SYSTEM_CURSOR_ARROW:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
break;
case SDL_SYSTEM_CURSOR_IBEAM:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT;
break;
case SDL_SYSTEM_CURSOR_WAIT:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_WAIT;
break;
case SDL_SYSTEM_CURSOR_CROSSHAIR:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR;
break;
case SDL_SYSTEM_CURSOR_WAITARROW:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_PROGRESS;
break;
case SDL_SYSTEM_CURSOR_SIZENWSE:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE;
break;
case SDL_SYSTEM_CURSOR_SIZENESW:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE;
break;
case SDL_SYSTEM_CURSOR_SIZEWE:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE;
break;
case SDL_SYSTEM_CURSOR_SIZENS:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE;
break;
case SDL_SYSTEM_CURSOR_SIZEALL:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_SCROLL;
break;
case SDL_SYSTEM_CURSOR_NO:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NOT_ALLOWED;
break;
case SDL_SYSTEM_CURSOR_HAND:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER;
break;
case SDL_SYSTEM_CURSOR_WINDOW_TOPLEFT:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE;
break;
case SDL_SYSTEM_CURSOR_WINDOW_TOP:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_N_RESIZE;
break;
case SDL_SYSTEM_CURSOR_WINDOW_TOPRIGHT:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE;
break;
case SDL_SYSTEM_CURSOR_WINDOW_RIGHT:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_E_RESIZE;
break;
case SDL_SYSTEM_CURSOR_WINDOW_BOTTOMRIGHT:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SE_RESIZE;
break;
case SDL_SYSTEM_CURSOR_WINDOW_BOTTOM:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_S_RESIZE;
break;
case SDL_SYSTEM_CURSOR_WINDOW_BOTTOMLEFT:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE;
break;
case SDL_SYSTEM_CURSOR_WINDOW_LEFT:
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_W_RESIZE;
break;
default:
SDL_assert(0); /* Should never be here... */
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
}
wp_cursor_shape_device_v1_set_shape(input->cursor_shape, input->pointer_enter_serial, shape);
}
static int Wayland_ShowCursor(SDL_Cursor *cursor)
{
SDL_VideoDevice *vd = SDL_GetVideoDevice();
@@ -598,7 +678,10 @@ static int Wayland_ShowCursor(SDL_Cursor *cursor)
/* TODO: High-DPI custom cursors? -flibit */
if (!data->shm_data) {
if (!wayland_get_system_cursor(d, data, &scale)) {
if (input->cursor_shape) {
Wayland_SetSystemCursorShape(input, data->system_cursor);
return 0;
} else if (!wayland_get_system_cursor(d, data, &scale)) {
return -1;
}
}

View File

@@ -23,41 +23,42 @@
#ifdef SDL_VIDEO_DRIVER_WAYLAND
#include "../../events/SDL_events_c.h"
#include "../../core/linux/SDL_system_theme.h"
#include "../../events/SDL_events_c.h"
#include "SDL_waylandvideo.h"
#include "SDL_waylandevents_c.h"
#include "SDL_waylandwindow.h"
#include "SDL_waylandopengles.h"
#include "SDL_waylandmouse.h"
#include "SDL_waylandkeyboard.h"
#include "SDL_waylandclipboard.h"
#include "SDL_waylandvulkan.h"
#include "SDL_waylandevents_c.h"
#include "SDL_waylandkeyboard.h"
#include "SDL_waylandmessagebox.h"
#include "SDL_waylandmouse.h"
#include "SDL_waylandopengles.h"
#include "SDL_waylandvideo.h"
#include "SDL_waylandvulkan.h"
#include "SDL_waylandwindow.h"
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <xkbcommon/xkbcommon.h>
#include <wayland-util.h>
#include "xdg-shell-client-protocol.h"
#include "xdg-decoration-unstable-v1-client-protocol.h"
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"
#include "tablet-unstable-v2-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
#include "viewporter-client-protocol.h"
#include "primary-selection-unstable-v1-client-protocol.h"
#include "cursor-shape-v1-client-protocol.h"
#include "fractional-scale-v1-client-protocol.h"
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "input-timestamps-unstable-v1-client-protocol.h"
#include "relative-pointer-unstable-v1-client-protocol.h"
#include "pointer-constraints-unstable-v1-client-protocol.h"
#include "kde-output-order-v1-client-protocol.h"
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
#include "pointer-constraints-unstable-v1-client-protocol.h"
#include "primary-selection-unstable-v1-client-protocol.h"
#include "relative-pointer-unstable-v1-client-protocol.h"
#include "tablet-unstable-v2-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"
#include "viewporter-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
#include "xdg-decoration-unstable-v1-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
#include "xdg-shell-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
@@ -200,7 +201,8 @@ error:
static void Wayland_FlushOutputOrder(SDL_VideoData *vid)
{
SDL_WaylandConnectorName *c, *tmp;
wl_list_for_each_safe (c, tmp, &vid->output_order, link) {
wl_list_for_each_safe(c, tmp, &vid->output_order, link)
{
WAYLAND_wl_list_remove(&c->link);
SDL_free(c);
}
@@ -796,7 +798,7 @@ static void display_handle_done(void *data,
/* ...and the compositor scales the logical viewport... */
if (video->viewporter) {
/* ...and viewports are supported, calculate the true scale of the output. */
driverdata->scale_factor = (float) native_mode.w / (float)driverdata->screen_width;
driverdata->scale_factor = (float)native_mode.w / (float)driverdata->screen_width;
} else {
/* ...otherwise, the 'native' pixel values are a multiple of the logical screen size. */
driverdata->pixel_width = driverdata->screen_width * (int)driverdata->scale_factor;
@@ -906,11 +908,11 @@ static void display_handle_description(void *data, struct wl_output *wl_output,
}
static const struct wl_output_listener output_listener = {
display_handle_geometry, /* Version 1 */
display_handle_mode, /* Version 1 */
display_handle_done, /* Version 2 */
display_handle_scale, /* Version 2 */
display_handle_name, /* Version 4 */
display_handle_geometry, /* Version 1 */
display_handle_mode, /* Version 1 */
display_handle_done, /* Version 2 */
display_handle_scale, /* Version 2 */
display_handle_name, /* Version 4 */
display_handle_description /* Version 4 */
};
@@ -978,7 +980,7 @@ static void Wayland_FinalizeDisplays(SDL_VideoData *vid)
SDL_DisplayData *d;
Wayland_SortOutputs(vid);
wl_list_for_each(d, &vid->output_list, link) {
wl_list_for_each (d, &vid->output_list, link) {
d->display = SDL_AddVideoDisplay(&d->placeholder, SDL_FALSE);
SDL_free(d->placeholder.name);
SDL_zero(d->placeholder);
@@ -1072,6 +1074,11 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint
if (d->input) {
Wayland_RegisterTimestampListeners(d->input);
}
} else if (SDL_strcmp(interface, "wp_cursor_shape_manager_v1") == 0) {
d->cursor_shape_manager = wl_registry_bind(d->registry, id, &wp_cursor_shape_manager_v1_interface, 1);
if (d->input) {
Wayland_CreateCursorShapeDevice(d->input);
}
} else if (SDL_strcmp(interface, "kde_output_order_v1") == 0) {
d->kde_output_order = wl_registry_bind(d->registry, id, &kde_output_order_v1_interface, 1);
kde_output_order_v1_add_listener(d->kde_output_order, &kde_output_order_listener, d);
@@ -1081,7 +1088,7 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint
static void display_remove_global(void *data, struct wl_registry *registry, uint32_t id)
{
SDL_VideoData *d = data;
SDL_DisplayData *node;
SDL_DisplayData *node;
/* We don't get an interface, just an ID, so assume it's a wl_output :shrug: */
wl_list_for_each (node, &d->output_list, link) {
@@ -1320,6 +1327,11 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this)
data->input_timestamps_manager = NULL;
}
if (data->cursor_shape_manager) {
wp_cursor_shape_manager_v1_destroy(data->cursor_shape_manager);
data->cursor_shape_manager = NULL;
}
if (data->kde_output_order) {
Wayland_FlushOutputOrder(data);
kde_output_order_v1_destroy(data->kde_output_order);

View File

@@ -67,6 +67,7 @@ struct SDL_VideoData
} shell;
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
struct zwp_pointer_constraints_v1 *pointer_constraints;
struct wp_cursor_shape_manager_v1 *cursor_shape_manager;
struct wl_data_device_manager *data_device_manager;
struct zwp_primary_selection_device_manager_v1 *primary_selection_device_manager;
struct zxdg_decoration_manager_v1 *decoration_manager;