From 30f41c02aec763d32e62351452da9ef582bc3472 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 6 Mar 2026 13:30:59 -0800 Subject: Move contrib libraries to contrib repo --- .../SDL-3.2.8/src/video/wayland/SDL_waylandmouse.c | 1057 -------------------- 1 file changed, 1057 deletions(-) delete mode 100644 contrib/SDL-3.2.8/src/video/wayland/SDL_waylandmouse.c (limited to 'contrib/SDL-3.2.8/src/video/wayland/SDL_waylandmouse.c') diff --git a/contrib/SDL-3.2.8/src/video/wayland/SDL_waylandmouse.c b/contrib/SDL-3.2.8/src/video/wayland/SDL_waylandmouse.c deleted file mode 100644 index 8075c3a..0000000 --- a/contrib/SDL-3.2.8/src/video/wayland/SDL_waylandmouse.c +++ /dev/null @@ -1,1057 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -#include "SDL_internal.h" - -#ifdef SDL_VIDEO_DRIVER_WAYLAND - -#include "../SDL_sysvideo.h" -#include "../SDL_video_c.h" - -#include "../../events/SDL_mouse_c.h" -#include "SDL_waylandvideo.h" -#include "../SDL_pixels_c.h" -#include "SDL_waylandevents_c.h" - -#include "wayland-cursor.h" -#include "SDL_waylandmouse.h" -#include "SDL_waylandshmbuffer.h" - -#include "cursor-shape-v1-client-protocol.h" -#include "pointer-constraints-unstable-v1-client-protocol.h" -#include "viewporter-client-protocol.h" - -#include "../../SDL_hints_c.h" - -static SDL_Cursor *sys_cursors[SDL_HITTEST_RESIZE_LEFT + 1]; - -static bool Wayland_SetRelativeMouseMode(bool enabled); - -typedef struct -{ - struct Wayland_SHMBuffer shmBuffer; - double scale; - struct wl_list node; -} Wayland_ScaledCustomCursor; - -typedef struct -{ - SDL_Surface *sdl_cursor_surface; - int hot_x; - int hot_y; - struct wl_list scaled_cursor_cache; -} Wayland_CustomCursor; - -typedef struct -{ - struct wl_buffer *wl_buffer; - Uint32 duration; -} Wayland_SystemCursorFrame; - -typedef struct -{ - Wayland_SystemCursorFrame *frames; - struct wl_callback *frame_callback; - Uint64 last_frame_callback_time_ms; - Uint64 current_frame_time_ms; - Uint32 total_duration; - int num_frames; - int current_frame; - SDL_SystemCursor id; -} Wayland_SystemCursor; - -struct SDL_CursorData -{ - union - { - Wayland_CustomCursor custom; - Wayland_SystemCursor system; - } cursor_data; - - struct wl_surface *surface; - struct wp_viewport *viewport; - - bool is_system_cursor; -}; - -static int dbus_cursor_size; -static char *dbus_cursor_theme; - -static void Wayland_FreeCursorThemes(SDL_VideoData *vdata) -{ - for (int i = 0; i < vdata->num_cursor_themes; i += 1) { - WAYLAND_wl_cursor_theme_destroy(vdata->cursor_themes[i].theme); - } - vdata->num_cursor_themes = 0; - SDL_free(vdata->cursor_themes); - vdata->cursor_themes = NULL; -} - -#ifdef SDL_USE_LIBDBUS - -#include "../../core/linux/SDL_dbus.h" - -#define CURSOR_NODE "org.freedesktop.portal.Desktop" -#define CURSOR_PATH "/org/freedesktop/portal/desktop" -#define CURSOR_INTERFACE "org.freedesktop.portal.Settings" -#define CURSOR_NAMESPACE "org.gnome.desktop.interface" -#define CURSOR_SIGNAL_NAME "SettingChanged" -#define CURSOR_SIZE_KEY "cursor-size" -#define CURSOR_THEME_KEY "cursor-theme" - -static DBusMessage *Wayland_ReadDBusProperty(SDL_DBusContext *dbus, const char *key) -{ - static const char *iface = "org.gnome.desktop.interface"; - - DBusMessage *reply = NULL; - DBusMessage *msg = dbus->message_new_method_call(CURSOR_NODE, - CURSOR_PATH, - CURSOR_INTERFACE, - "Read"); // Method - - if (msg) { - if (dbus->message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_STRING, &key, DBUS_TYPE_INVALID)) { - reply = dbus->connection_send_with_reply_and_block(dbus->session_conn, msg, DBUS_TIMEOUT_USE_DEFAULT, NULL); - } - dbus->message_unref(msg); - } - - return reply; -} - -static bool Wayland_ParseDBusReply(SDL_DBusContext *dbus, DBusMessage *reply, int type, void *value) -{ - DBusMessageIter iter[3]; - - dbus->message_iter_init(reply, &iter[0]); - if (dbus->message_iter_get_arg_type(&iter[0]) != DBUS_TYPE_VARIANT) { - return false; - } - - dbus->message_iter_recurse(&iter[0], &iter[1]); - if (dbus->message_iter_get_arg_type(&iter[1]) != DBUS_TYPE_VARIANT) { - return false; - } - - dbus->message_iter_recurse(&iter[1], &iter[2]); - if (dbus->message_iter_get_arg_type(&iter[2]) != type) { - return false; - } - - dbus->message_iter_get_basic(&iter[2], value); - - return true; -} - -static DBusHandlerResult Wayland_DBusCursorMessageFilter(DBusConnection *conn, DBusMessage *msg, void *data) -{ - SDL_DBusContext *dbus = SDL_DBus_GetContext(); - SDL_VideoData *vdata = (SDL_VideoData *)data; - - if (dbus->message_is_signal(msg, CURSOR_INTERFACE, CURSOR_SIGNAL_NAME)) { - DBusMessageIter signal_iter, variant_iter; - const char *namespace, *key; - - dbus->message_iter_init(msg, &signal_iter); - // Check if the parameters are what we expect - if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_STRING) { - goto not_our_signal; - } - dbus->message_iter_get_basic(&signal_iter, &namespace); - if (SDL_strcmp(CURSOR_NAMESPACE, namespace) != 0) { - goto not_our_signal; - } - if (!dbus->message_iter_next(&signal_iter)) { - goto not_our_signal; - } - if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_STRING) { - goto not_our_signal; - } - dbus->message_iter_get_basic(&signal_iter, &key); - if (SDL_strcmp(CURSOR_SIZE_KEY, key) == 0) { - int new_cursor_size; - - if (!dbus->message_iter_next(&signal_iter)) { - goto not_our_signal; - } - if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_VARIANT) { - goto not_our_signal; - } - dbus->message_iter_recurse(&signal_iter, &variant_iter); - if (dbus->message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_INT32) { - goto not_our_signal; - } - dbus->message_iter_get_basic(&variant_iter, &new_cursor_size); - - if (dbus_cursor_size != new_cursor_size) { - dbus_cursor_size = new_cursor_size; - SDL_SetCursor(NULL); // Force cursor update - } - } else if (SDL_strcmp(CURSOR_THEME_KEY, key) == 0) { - const char *new_cursor_theme = NULL; - - if (!dbus->message_iter_next(&signal_iter)) { - goto not_our_signal; - } - if (dbus->message_iter_get_arg_type(&signal_iter) != DBUS_TYPE_VARIANT) { - goto not_our_signal; - } - dbus->message_iter_recurse(&signal_iter, &variant_iter); - if (dbus->message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRING) { - goto not_our_signal; - } - dbus->message_iter_get_basic(&variant_iter, &new_cursor_theme); - - if (!dbus_cursor_theme || !new_cursor_theme || SDL_strcmp(dbus_cursor_theme, new_cursor_theme) != 0) { - SDL_free(dbus_cursor_theme); - if (new_cursor_theme) { - dbus_cursor_theme = SDL_strdup(new_cursor_theme); - } else { - dbus_cursor_theme = NULL; - } - - // Purge the current cached themes and force a cursor refresh. - Wayland_FreeCursorThemes(vdata); - SDL_SetCursor(NULL); - } - } else { - goto not_our_signal; - } - - return DBUS_HANDLER_RESULT_HANDLED; - } - -not_our_signal: - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -static void Wayland_DBusInitCursorProperties(SDL_VideoData *vdata) -{ - DBusMessage *reply; - SDL_DBusContext *dbus = SDL_DBus_GetContext(); - bool add_filter = false; - - if (!dbus) { - return; - } - - if ((reply = Wayland_ReadDBusProperty(dbus, CURSOR_SIZE_KEY))) { - if (Wayland_ParseDBusReply(dbus, reply, DBUS_TYPE_INT32, &dbus_cursor_size)) { - add_filter = true; - } - dbus->message_unref(reply); - } - - if ((reply = Wayland_ReadDBusProperty(dbus, CURSOR_THEME_KEY))) { - const char *temp = NULL; - if (Wayland_ParseDBusReply(dbus, reply, DBUS_TYPE_STRING, &temp)) { - add_filter = true; - - if (temp) { - dbus_cursor_theme = SDL_strdup(temp); - } - } - dbus->message_unref(reply); - } - - // Only add the filter if at least one of the settings we want is present. - if (add_filter) { - dbus->bus_add_match(dbus->session_conn, - "type='signal', interface='" CURSOR_INTERFACE "'," - "member='" CURSOR_SIGNAL_NAME "', arg0='" CURSOR_NAMESPACE "'", - NULL); - dbus->connection_add_filter(dbus->session_conn, &Wayland_DBusCursorMessageFilter, vdata, NULL); - dbus->connection_flush(dbus->session_conn); - } -} - -static void Wayland_DBusFinishCursorProperties(void) -{ - SDL_free(dbus_cursor_theme); - dbus_cursor_theme = NULL; -} - -#endif - -static void cursor_frame_done(void *data, struct wl_callback *cb, uint32_t time); -struct wl_callback_listener cursor_frame_listener = { - cursor_frame_done -}; - -static void cursor_frame_done(void *data, struct wl_callback *cb, uint32_t time) -{ - SDL_CursorData *c = (SDL_CursorData *)data; - - const Uint64 now = SDL_GetTicks(); - const Uint64 elapsed = (now - c->cursor_data.system.last_frame_callback_time_ms) % c->cursor_data.system.total_duration; - Uint64 advance = 0; - int next = c->cursor_data.system.current_frame; - - wl_callback_destroy(cb); - c->cursor_data.system.frame_callback = wl_surface_frame(c->surface); - wl_callback_add_listener(c->cursor_data.system.frame_callback, &cursor_frame_listener, data); - - c->cursor_data.system.current_frame_time_ms += elapsed; - - // Calculate the next frame based on the elapsed duration. - for (Uint64 t = c->cursor_data.system.frames[next].duration; t <= c->cursor_data.system.current_frame_time_ms; t += c->cursor_data.system.frames[next].duration) { - next = (next + 1) % c->cursor_data.system.num_frames; - advance = t; - - // Make sure we don't end up in an infinite loop if a cursor has frame durations of 0. - if (!c->cursor_data.system.frames[next].duration) { - break; - } - } - - c->cursor_data.system.current_frame_time_ms -= advance; - c->cursor_data.system.last_frame_callback_time_ms = now; - c->cursor_data.system.current_frame = next; - wl_surface_attach(c->surface, c->cursor_data.system.frames[next].wl_buffer, 0, 0); - if (wl_surface_get_version(c->surface) >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) { - wl_surface_damage_buffer(c->surface, 0, 0, SDL_MAX_SINT32, SDL_MAX_SINT32); - } else { - wl_surface_damage(c->surface, 0, 0, SDL_MAX_SINT32, SDL_MAX_SINT32); - } - wl_surface_commit(c->surface); -} - -static bool Wayland_GetSystemCursor(SDL_VideoData *vdata, SDL_CursorData *cdata, int *scale, int *dst_size, int *hot_x, int *hot_y) -{ - struct wl_cursor_theme *theme = NULL; - struct wl_cursor *cursor; - const char *css_name = "default"; - const char *fallback_name = NULL; - double scale_factor = 1.0; - int theme_size = dbus_cursor_size; - - // Fallback envvar if the DBus properties don't exist - if (theme_size <= 0) { - const char *xcursor_size = SDL_getenv("XCURSOR_SIZE"); - if (xcursor_size) { - theme_size = SDL_atoi(xcursor_size); - } - } - if (theme_size <= 0) { - theme_size = 24; - } - // First, find the appropriate theme based on the current scale... - SDL_Window *focus = SDL_GetMouse()->focus; - if (focus) { - // TODO: Use the fractional scale once GNOME supports viewports on cursor surfaces. - scale_factor = SDL_ceil(focus->internal->scale_factor); - } - - const int scaled_size = (int)SDL_lround(theme_size * scale_factor); - for (int i = 0; i < vdata->num_cursor_themes; ++i) { - if (vdata->cursor_themes[i].size == scaled_size) { - theme = vdata->cursor_themes[i].theme; - break; - } - } - if (!theme) { - const char *xcursor_theme = dbus_cursor_theme; - - SDL_WaylandCursorTheme *new_cursor_themes = SDL_realloc(vdata->cursor_themes, - sizeof(SDL_WaylandCursorTheme) * (vdata->num_cursor_themes + 1)); - if (!new_cursor_themes) { - return false; - } - vdata->cursor_themes = new_cursor_themes; - - // Fallback envvar if the DBus properties don't exist - if (!xcursor_theme) { - xcursor_theme = SDL_getenv("XCURSOR_THEME"); - } - - theme = WAYLAND_wl_cursor_theme_load(xcursor_theme, scaled_size, vdata->shm); - vdata->cursor_themes[vdata->num_cursor_themes].size = scaled_size; - vdata->cursor_themes[vdata->num_cursor_themes++].theme = theme; - } - - css_name = SDL_GetCSSCursorName(cdata->cursor_data.system.id, &fallback_name); - cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, css_name); - if (!cursor && fallback_name) { - cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, fallback_name); - } - - // Fallback to the default cursor if the chosen one wasn't found - if (!cursor) { - cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "default"); - } - // Try the old X11 name as a last resort - if (!cursor) { - cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "left_ptr"); - } - if (!cursor) { - return false; - } - - if (cdata->cursor_data.system.num_frames != cursor->image_count) { - SDL_free(cdata->cursor_data.system.frames); - cdata->cursor_data.system.frames = SDL_calloc(cursor->image_count, sizeof(Wayland_SystemCursorFrame)); - if (!cdata->cursor_data.system.frames) { - return false; - } - } - - // ... Set the cursor data, finally. - cdata->cursor_data.system.num_frames = cursor->image_count; - cdata->cursor_data.system.total_duration = 0; - for (int i = 0; i < cursor->image_count; ++i) { - cdata->cursor_data.system.frames[i].wl_buffer = WAYLAND_wl_cursor_image_get_buffer(cursor->images[i]); - cdata->cursor_data.system.frames[i].duration = cursor->images[i]->delay; - cdata->cursor_data.system.total_duration += cursor->images[i]->delay; - } - - *scale = SDL_ceil(scale_factor) == scale_factor ? (int)scale_factor : 0; - - if (scaled_size != cursor->images[0]->width) { - /* If the cursor size isn't an exact match for the target size, use a viewport - * to avoid a possible "Buffer size is not divisible by scale" protocol error. - * - * If viewports are unavailable, find an integer scale that works. - */ - if (vdata->viewporter) { - // A scale of 0 indicates that a viewport set to the destination size should be used. - *scale = 0; - } else { - for (; *scale > 1; --*scale) { - if (cursor->images[0]->width % *scale == 0) { - break; - } - } - // Set the scale factor to the new value for the hotspot calculations. - scale_factor = *scale; - } - } - - *dst_size = (int)SDL_lround(cursor->images[0]->width / scale_factor); - - *hot_x = (int)SDL_lround(cursor->images[0]->hotspot_x / scale_factor); - *hot_y = (int)SDL_lround(cursor->images[0]->hotspot_y / scale_factor); - - return true; -} - -static Wayland_ScaledCustomCursor *Wayland_CacheScaledCustomCursor(SDL_CursorData *cdata, double scale) -{ - Wayland_ScaledCustomCursor *cache = NULL; - - // Is this cursor already cached at the target scale? - if (!WAYLAND_wl_list_empty(&cdata->cursor_data.custom.scaled_cursor_cache)) { - Wayland_ScaledCustomCursor *c = NULL; - wl_list_for_each (c, &cdata->cursor_data.custom.scaled_cursor_cache, node) { - if (c->scale == scale) { - cache = c; - break; - } - } - } - - if (!cache) { - cache = SDL_calloc(1, sizeof(Wayland_ScaledCustomCursor)); - if (!cache) { - return NULL; - } - - SDL_Surface *surface = SDL_GetSurfaceImage(cdata->cursor_data.custom.sdl_cursor_surface, (float)scale); - if (!surface) { - SDL_free(cache); - return NULL; - } - - // Allocate the shared memory buffer for this cursor. - if (!Wayland_AllocSHMBuffer(surface->w, surface->h, &cache->shmBuffer)) { - SDL_free(cache); - SDL_DestroySurface(surface); - return NULL; - } - - // Wayland requires premultiplied alpha for its surfaces. - SDL_PremultiplyAlpha(surface->w, surface->h, - surface->format, surface->pixels, surface->pitch, - SDL_PIXELFORMAT_ARGB8888, cache->shmBuffer.shm_data, surface->w * 4, true); - - cache->scale = scale; - WAYLAND_wl_list_insert(&cdata->cursor_data.custom.scaled_cursor_cache, &cache->node); - SDL_DestroySurface(surface); - } - - return cache; -} - -static bool Wayland_GetCustomCursor(SDL_Cursor *cursor, struct wl_buffer **buffer, int *scale, int *dst_width, int *dst_height, int *hot_x, int *hot_y) -{ - SDL_VideoDevice *vd = SDL_GetVideoDevice(); - SDL_VideoData *wd = vd->internal; - SDL_CursorData *data = cursor->internal; - SDL_Window *focus = SDL_GetMouseFocus(); - double scale_factor = 1.0; - - if (focus && SDL_SurfaceHasAlternateImages(data->cursor_data.custom.sdl_cursor_surface)) { - scale_factor = focus->internal->scale_factor; - } - - // Only use fractional scale values if viewports are available. - if (!wd->viewporter) { - scale_factor = SDL_ceil(scale_factor); - } - - Wayland_ScaledCustomCursor *c = Wayland_CacheScaledCustomCursor(data, scale_factor); - if (!c) { - return false; - } - - *buffer = c->shmBuffer.wl_buffer; - *scale = SDL_ceil(scale_factor) == scale_factor ? (int)scale_factor : 0; - *dst_width = data->cursor_data.custom.sdl_cursor_surface->w; - *dst_height = data->cursor_data.custom.sdl_cursor_surface->h; - *hot_x = data->cursor_data.custom.hot_x; - *hot_y = data->cursor_data.custom.hot_y; - - return true; -} - -static SDL_Cursor *Wayland_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y) -{ - SDL_VideoDevice *vd = SDL_GetVideoDevice(); - SDL_VideoData *wd = vd->internal; - - SDL_Cursor *cursor = SDL_calloc(1, sizeof(*cursor)); - if (cursor) { - SDL_CursorData *data = SDL_calloc(1, sizeof(*data)); - if (!data) { - SDL_free(cursor); - return NULL; - } - cursor->internal = data; - WAYLAND_wl_list_init(&data->cursor_data.custom.scaled_cursor_cache); - data->cursor_data.custom.hot_x = hot_x; - data->cursor_data.custom.hot_y = hot_y; - data->surface = wl_compositor_create_surface(wd->compositor); - - data->cursor_data.custom.sdl_cursor_surface = surface; - ++surface->refcount; - - // If the cursor has only one size, just prepare it now. - if (!SDL_SurfaceHasAlternateImages(surface)) { - Wayland_CacheScaledCustomCursor(data, 1.0); - } - } - - return cursor; -} - -static SDL_Cursor *Wayland_CreateSystemCursor(SDL_SystemCursor id) -{ - SDL_VideoData *data = SDL_GetVideoDevice()->internal; - SDL_Cursor *cursor = SDL_calloc(1, sizeof(*cursor)); - if (cursor) { - SDL_CursorData *cdata = SDL_calloc(1, sizeof(*cdata)); - if (!cdata) { - SDL_free(cursor); - return NULL; - } - cursor->internal = cdata; - - /* 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 window-specific. See Wayland_GetSystemCursor 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->cursor_data.system.id = id; - cdata->is_system_cursor = true; - } - - return cursor; -} - -static SDL_Cursor *Wayland_CreateDefaultCursor(void) -{ - SDL_SystemCursor id = SDL_GetDefaultSystemCursor(); - return Wayland_CreateSystemCursor(id); -} - -static void Wayland_FreeCursorData(SDL_CursorData *d) -{ - SDL_VideoDevice *vd = SDL_GetVideoDevice(); - struct SDL_WaylandInput *input = vd->internal->input; - - if (input->current_cursor == d) { - input->current_cursor = NULL; - } - - // Buffers for system cursors must not be destroyed. - if (d->is_system_cursor) { - if (d->cursor_data.system.frame_callback) { - wl_callback_destroy(d->cursor_data.system.frame_callback); - } - SDL_free(d->cursor_data.system.frames); - } else { - Wayland_ScaledCustomCursor *c, *temp; - wl_list_for_each_safe(c, temp, &d->cursor_data.custom.scaled_cursor_cache, node) { - Wayland_ReleaseSHMBuffer(&c->shmBuffer); - SDL_free(c); - } - - SDL_DestroySurface(d->cursor_data.custom.sdl_cursor_surface); - } - - if (d->viewport) { - wp_viewport_destroy(d->viewport); - d->viewport = NULL; - } - - if (d->surface) { - wl_surface_destroy(d->surface); - d->surface = NULL; - } -} - -static void Wayland_FreeCursor(SDL_Cursor *cursor) -{ - if (!cursor) { - return; - } - - // Probably not a cursor we own - if (!cursor->internal) { - return; - } - - Wayland_FreeCursorData(cursor->internal); - - SDL_free(cursor->internal); - SDL_free(cursor); -} - -static void Wayland_SetSystemCursorShape(struct SDL_WaylandInput *input, SDL_SystemCursor id) -{ - Uint32 shape; - - switch (id) { - case SDL_SYSTEM_CURSOR_DEFAULT: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT; - break; - case SDL_SYSTEM_CURSOR_TEXT: - 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_PROGRESS: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_PROGRESS; - break; - case SDL_SYSTEM_CURSOR_NWSE_RESIZE: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE; - break; - case SDL_SYSTEM_CURSOR_NESW_RESIZE: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE; - break; - case SDL_SYSTEM_CURSOR_EW_RESIZE: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE; - break; - case SDL_SYSTEM_CURSOR_NS_RESIZE: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE; - break; - case SDL_SYSTEM_CURSOR_MOVE: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_SCROLL; - break; - case SDL_SYSTEM_CURSOR_NOT_ALLOWED: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NOT_ALLOWED; - break; - case SDL_SYSTEM_CURSOR_POINTER: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER; - break; - case SDL_SYSTEM_CURSOR_NW_RESIZE: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE; - break; - case SDL_SYSTEM_CURSOR_N_RESIZE: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_N_RESIZE; - break; - case SDL_SYSTEM_CURSOR_NE_RESIZE: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE; - break; - case SDL_SYSTEM_CURSOR_E_RESIZE: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_E_RESIZE; - break; - case SDL_SYSTEM_CURSOR_SE_RESIZE: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SE_RESIZE; - break; - case SDL_SYSTEM_CURSOR_S_RESIZE: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_S_RESIZE; - break; - case SDL_SYSTEM_CURSOR_SW_RESIZE: - shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE; - break; - case SDL_SYSTEM_CURSOR_W_RESIZE: - 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 bool Wayland_ShowCursor(SDL_Cursor *cursor) -{ - SDL_VideoDevice *vd = SDL_GetVideoDevice(); - SDL_VideoData *d = vd->internal; - struct SDL_WaylandInput *input = d->input; - struct wl_pointer *pointer = d->pointer; - struct wl_buffer *buffer = NULL; - int scale = 1; - int dst_width = 0; - int dst_height = 0; - int hot_x; - int hot_y; - - if (!pointer) { - return false; - } - - // Stop the frame callback for old animated cursors. - if (input->current_cursor && input->current_cursor->is_system_cursor && - input->current_cursor->cursor_data.system.frame_callback) { - wl_callback_destroy(input->current_cursor->cursor_data.system.frame_callback); - input->current_cursor->cursor_data.system.frame_callback = NULL; - } - - if (cursor) { - SDL_CursorData *data = cursor->internal; - - if (data->is_system_cursor) { - // If the cursor shape protocol is supported, the compositor will draw nicely scaled cursors for us, so nothing more to do. - if (input->cursor_shape) { - Wayland_SetSystemCursorShape(input, data->cursor_data.system.id); - input->current_cursor = data; - return true; - } - - if (!Wayland_GetSystemCursor(d, data, &scale, &dst_width, &hot_x, &hot_y)) { - return false; - } - - dst_height = dst_width; - wl_surface_attach(data->surface, data->cursor_data.system.frames[0].wl_buffer, 0, 0); - - // If more than one frame is available, create a frame callback to run the animation. - if (data->cursor_data.system.num_frames > 1) { - data->cursor_data.system.last_frame_callback_time_ms = SDL_GetTicks(); - data->cursor_data.system.current_frame_time_ms = 0; - data->cursor_data.system.current_frame = 0; - data->cursor_data.system.frame_callback = wl_surface_frame(data->surface); - wl_callback_add_listener(data->cursor_data.system.frame_callback, &cursor_frame_listener, data); - } - } else { - if (!Wayland_GetCustomCursor(cursor, &buffer, &scale, &dst_width, &dst_height, &hot_x, &hot_y)) { - return false; - } - - wl_surface_attach(data->surface, buffer, 0, 0); - } - - // A scale value of 0 indicates that a viewport with the returned destination size should be used. - if (!scale) { - if (!data->viewport) { - data->viewport = wp_viewporter_get_viewport(d->viewporter, data->surface); - } - wl_surface_set_buffer_scale(data->surface, 1); - wp_viewport_set_source(data->viewport, wl_fixed_from_int(-1), wl_fixed_from_int(-1), wl_fixed_from_int(-1), wl_fixed_from_int(-1)); - wp_viewport_set_destination(data->viewport, dst_width, dst_height); - } else { - if (data->viewport) { - wp_viewport_destroy(data->viewport); - data->viewport = NULL; - } - wl_surface_set_buffer_scale(data->surface, scale); - } - - wl_pointer_set_cursor(pointer, input->pointer_enter_serial, data->surface, hot_x, hot_y); - - if (wl_surface_get_version(data->surface) >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) { - wl_surface_damage_buffer(data->surface, 0, 0, SDL_MAX_SINT32, SDL_MAX_SINT32); - } else { - wl_surface_damage(data->surface, 0, 0, SDL_MAX_SINT32, SDL_MAX_SINT32); - } - - wl_surface_commit(data->surface); - input->current_cursor = data; - } else { - input->current_cursor = NULL; - wl_pointer_set_cursor(pointer, input->pointer_enter_serial, NULL, 0, 0); - } - - return true; -} - -static bool Wayland_WarpMouse(SDL_Window *window, float x, float y) -{ - SDL_VideoDevice *vd = SDL_GetVideoDevice(); - SDL_VideoData *d = vd->internal; - SDL_WindowData *wind = window->internal; - struct SDL_WaylandInput *input = d->input; - - if (d->pointer_constraints) { - const bool toggle_lock = !wind->locked_pointer; - - /* The pointer confinement protocol allows setting a hint to warp the pointer, - * but only when the pointer is locked. - * - * Lock the pointer, set the position hint, unlock, and hope for the best. - */ - if (toggle_lock) { - Wayland_input_lock_pointer(input, window); - } - if (wind->locked_pointer) { - const wl_fixed_t f_x = wl_fixed_from_double(x / wind->pointer_scale.x); - const wl_fixed_t f_y = wl_fixed_from_double(y / wind->pointer_scale.y); - zwp_locked_pointer_v1_set_cursor_position_hint(wind->locked_pointer, f_x, f_y); - wl_surface_commit(wind->surface); - } - if (toggle_lock) { - Wayland_input_unlock_pointer(input, window); - } - - /* NOTE: There is a pending warp event under discussion that should replace this when available. - * https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/340 - */ - SDL_SendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, false, x, y); - } else { - return SDL_SetError("wayland: mouse warp failed; compositor lacks support for the required zwp_pointer_confinement_v1 protocol"); - } - - return true; -} - -static bool Wayland_WarpMouseGlobal(float x, float y) -{ - SDL_VideoDevice *vd = SDL_GetVideoDevice(); - SDL_VideoData *d = vd->internal; - struct SDL_WaylandInput *input = d->input; - SDL_WindowData *wind = input->pointer_focus; - - // If the client wants the coordinates warped to within the focused window, just convert the coordinates to relative. - if (wind) { - SDL_Window *window = wind->sdlwindow; - return Wayland_WarpMouse(window, x - (float)window->x, y - (float)window->y); - } - - return SDL_SetError("wayland: can't warp the mouse when a window does not have focus"); -} - -static bool Wayland_SetRelativeMouseMode(bool enabled) -{ - SDL_VideoDevice *vd = SDL_GetVideoDevice(); - SDL_VideoData *data = vd->internal; - - if (enabled) { - return Wayland_input_enable_relative_pointer(data->input); - } else { - return Wayland_input_disable_relative_pointer(data->input); - } -} - -/* Wayland doesn't support getting the true global cursor position, but it can - * be faked well enough for what most applications use it for: querying the - * global cursor coordinates and transforming them to the window-relative - * coordinates manually. - * - * The global position is derived by taking the cursor position relative to the - * toplevel window, and offsetting it by the origin of the output the window is - * currently considered to be on. The cursor position and button state when the - * cursor is outside an application window are unknown, but this gives 'correct' - * coordinates when the window has focus, which is good enough for most - * applications. - */ -static SDL_MouseButtonFlags SDLCALL Wayland_GetGlobalMouseState(float *x, float *y) -{ - SDL_Window *focus = SDL_GetMouseFocus(); - SDL_MouseButtonFlags result = 0; - - if (focus) { - SDL_VideoData *viddata = SDL_GetVideoDevice()->internal; - int off_x, off_y; - - result = viddata->input->buttons_pressed; - SDL_RelativeToGlobalForWindow(focus, focus->x, focus->y, &off_x, &off_y); - *x += off_x; - *y += off_y; - } - - return result; -} - -#if 0 // TODO RECONNECT: See waylandvideo.c for more information! -static void Wayland_RecreateCursor(SDL_Cursor *cursor, SDL_VideoData *vdata) -{ - SDL_CursorData *cdata = cursor->internal; - - // Probably not a cursor we own - if (cdata == NULL) { - return; - } - - Wayland_FreeCursorData(cdata); - - // We're not currently freeing this, so... yolo? - if (cdata->shm_data != NULL) { - void *old_data_pointer = cdata->shm_data; - int stride = cdata->w * 4; - - create_buffer_from_shm(cdata, cdata->w, cdata->h, WL_SHM_FORMAT_ARGB8888); - - SDL_memcpy(cdata->shm_data, old_data_pointer, stride * cdata->h); - } - cdata->surface = wl_compositor_create_surface(vdata->compositor); - wl_surface_set_user_data(cdata->surface, NULL); -} - -void Wayland_RecreateCursors(void) -{ - SDL_Cursor *cursor; - SDL_Mouse *mouse = SDL_GetMouse(); - SDL_VideoData *vdata = SDL_GetVideoDevice()->internal; - - if (vdata && vdata->cursor_themes) { - SDL_free(vdata->cursor_themes); - vdata->cursor_themes = NULL; - vdata->num_cursor_themes = 0; - } - - if (mouse == NULL) { - return; - } - - for (cursor = mouse->cursors; cursor != NULL; cursor = cursor->next) { - Wayland_RecreateCursor(cursor, vdata); - } - if (mouse->def_cursor) { - Wayland_RecreateCursor(mouse->def_cursor, vdata); - } - if (mouse->cur_cursor) { - Wayland_RecreateCursor(mouse->cur_cursor, vdata); - if (mouse->cursor_shown) { - Wayland_ShowCursor(mouse->cur_cursor); - } - } -} -#endif // 0 - -void Wayland_InitMouse(void) -{ - SDL_Mouse *mouse = SDL_GetMouse(); - SDL_VideoDevice *vd = SDL_GetVideoDevice(); - SDL_VideoData *d = vd->internal; - - mouse->CreateCursor = Wayland_CreateCursor; - mouse->CreateSystemCursor = Wayland_CreateSystemCursor; - mouse->ShowCursor = Wayland_ShowCursor; - mouse->FreeCursor = Wayland_FreeCursor; - mouse->WarpMouse = Wayland_WarpMouse; - mouse->WarpMouseGlobal = Wayland_WarpMouseGlobal; - mouse->SetRelativeMouseMode = Wayland_SetRelativeMouseMode; - mouse->GetGlobalMouseState = Wayland_GetGlobalMouseState; - - SDL_HitTestResult r = SDL_HITTEST_NORMAL; - while (r <= SDL_HITTEST_RESIZE_LEFT) { - switch (r) { - case SDL_HITTEST_NORMAL: - sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT); - break; - case SDL_HITTEST_DRAGGABLE: - sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT); - break; - case SDL_HITTEST_RESIZE_TOPLEFT: - sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_NW_RESIZE); - break; - case SDL_HITTEST_RESIZE_TOP: - sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_N_RESIZE); - break; - case SDL_HITTEST_RESIZE_TOPRIGHT: - sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_NE_RESIZE); - break; - case SDL_HITTEST_RESIZE_RIGHT: - sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_E_RESIZE); - break; - case SDL_HITTEST_RESIZE_BOTTOMRIGHT: - sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_SE_RESIZE); - break; - case SDL_HITTEST_RESIZE_BOTTOM: - sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_S_RESIZE); - break; - case SDL_HITTEST_RESIZE_BOTTOMLEFT: - sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_SW_RESIZE); - break; - case SDL_HITTEST_RESIZE_LEFT: - sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_W_RESIZE); - break; - } - r++; - } - -#ifdef SDL_USE_LIBDBUS - /* The DBus cursor properties are only needed when manually loading themes and cursors. - * If the cursor shape protocol is present, the compositor will handle it internally. - */ - if (!d->cursor_shape_manager) { - Wayland_DBusInitCursorProperties(d); - } -#endif - - SDL_SetDefaultCursor(Wayland_CreateDefaultCursor()); -} - -void Wayland_FiniMouse(SDL_VideoData *data) -{ - Wayland_FreeCursorThemes(data); - -#ifdef SDL_USE_LIBDBUS - Wayland_DBusFinishCursorProperties(); -#endif - - for (int i = 0; i < SDL_arraysize(sys_cursors); i++) { - Wayland_FreeCursor(sys_cursors[i]); - sys_cursors[i] = NULL; - } -} - -void Wayland_SetHitTestCursor(SDL_HitTestResult rc) -{ - if (rc == SDL_HITTEST_NORMAL || rc == SDL_HITTEST_DRAGGABLE) { - SDL_SetCursor(NULL); - } else { - Wayland_ShowCursor(sys_cursors[rc]); - } -} - -#endif // SDL_VIDEO_DRIVER_WAYLAND -- cgit v1.2.3