From 466ca58b040ab9bc7f9f208d144e8b5993fa9f57 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 9 Dec 2025 16:38:43 -0800 Subject: [PATCH] Added SDL_HINT_MOUSE_DPI_SCALE_CURSORS We only want to change cursor display scale if the application or the user opts in by setting a hint. Otherwise cursors could change size unexpectedly when upgrading to SDL 3.4.0. --- WhatsNew.txt | 1 + include/SDL3/SDL_hints.h | 14 ++++++++++++++ include/SDL3/SDL_mouse.h | 2 +- src/video/wayland/SDL_waylandmouse.c | 21 +++++++++++++++++---- src/video/windows/SDL_windowsmouse.c | 9 ++++++--- 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/WhatsNew.txt b/WhatsNew.txt index e085707a5..67a50be68 100644 --- a/WhatsNew.txt +++ b/WhatsNew.txt @@ -7,6 +7,7 @@ This is a list of major changes in SDL's version history. General: * Added SDL_CreateAnimatedCursor() to create animated color cursors +* Added SDL_HINT_MOUSE_DPI_SCALE_CURSORS to automatically scale cursors based on the display scale * Added SDL_SetWindowProgressState(), SDL_SetWindowProgressValue(), SDL_GetWindowProgressState(), and SDL_GetWindowProgressValue() to show progress in the window's taskbar icon on Windows and Linux * Added GPU device creation properties to enable the GPU API on older hardware if you're not using these features: - SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h index 42627c824..531b9810b 100644 --- a/include/SDL3/SDL_hints.h +++ b/include/SDL3/SDL_hints.h @@ -2692,6 +2692,20 @@ extern "C" { */ #define SDL_HINT_MOUSE_DEFAULT_SYSTEM_CURSOR "SDL_MOUSE_DEFAULT_SYSTEM_CURSOR" +/** + * A variable setting whether we should scale cursors by the current display scale. + * + * The variable can be set to the following values: + * + * - "0": Cursors will not change size based on the display content scale. (default) + * - "1": Cursors will automatically match the display content scale (e.g. a 2x sized cursor will be used when the window is on a monitor with 200% scale). This is currently implemented on Windows and Wayland. + * + * This hint needs to be set before creating cursors. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_MOUSE_DPI_SCALE_CURSORS "SDL_MOUSE_DPI_SCALE_CURSORS" + /** * A variable controlling whether warping a hidden mouse cursor will activate * relative mouse mode. diff --git a/include/SDL3/SDL_mouse.h b/include/SDL3/SDL_mouse.h index 7a3be231d..752e8d894 100644 --- a/include/SDL3/SDL_mouse.h +++ b/include/SDL3/SDL_mouse.h @@ -593,7 +593,7 @@ extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_CreateCursor(const Uint8 *data, * If this function is passed a surface with alternate representations added * with SDL_AddSurfaceAlternateImage(), the surface will be interpreted as the * content to be used for 100% display scale, and the alternate - * representations will be used for high DPI situations. For example, if the + * representations will be used for high DPI situations if SDL_HINT_MOUSE_DPI_SCALE_CURSORS is enabled. For example, if the * original surface is 32x32, then on a 2x macOS display or 200% display scale * on Windows, a 64x64 version of the image will be used, if available. If a * matching version of the image isn't available, the closest larger size diff --git a/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c index 180192489..2d9726634 100644 --- a/src/video/wayland/SDL_waylandmouse.c +++ b/src/video/wayland/SDL_waylandmouse.c @@ -1025,6 +1025,21 @@ typedef struct Wayland_PointerObject bool is_pointer; } Wayland_PointerObject; +static float Wayland_GetCursorScale(SDL_WindowData *focus) +{ + SDL_VideoData *viddata = SDL_GetVideoDevice()->internal; + + if (!SDL_GetHintBoolean(SDL_HINT_MOUSE_DPI_SCALE_CURSORS, false)) { + return 1.0f; + } + + // If viewports aren't available, the scale is always 1.0. + if (viddata->viewporter && focus) { + return (float)focus->scale_factor; + } + return 1.0f; +} + static void Wayland_CursorStateSetCursor(SDL_WaylandCursorState *state, const Wayland_PointerObject *obj, SDL_WindowData *focus, Uint32 serial, SDL_Cursor *cursor) { SDL_VideoData *viddata = SDL_GetVideoDevice()->internal; @@ -1079,16 +1094,14 @@ static void Wayland_CursorStateSetCursor(SDL_WaylandCursorState *state, const Wa return; } - // If viewports aren't available, the scale is always 1.0. - state->scale = viddata->viewporter && focus ? focus->scale_factor : 1.0; + state->scale = Wayland_GetCursorScale(focus); if (!Wayland_GetSystemCursor(cursor_data, state, &dst_width, &hot_x, &hot_y)) { return; } dst_height = dst_width; } else { - // If viewports aren't available, the scale is always 1.0. - state->scale = viddata->viewporter && focus ? focus->scale_factor : 1.0; + state->scale = Wayland_GetCursorScale(focus); dst_width = cursor_data->cursor_data.custom.width; dst_height = cursor_data->cursor_data.custom.height; hot_x = cursor_data->cursor_data.custom.hot_x; diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c index db4d42d6b..6328bfa4a 100644 --- a/src/video/windows/SDL_windowsmouse.c +++ b/src/video/windows/SDL_windowsmouse.c @@ -566,9 +566,12 @@ static HCURSOR GetCachedCursor(SDL_Cursor *cursor) { SDL_CursorData *data = cursor->internal; - float scale = SDL_GetDisplayContentScale(SDL_GetDisplayForWindow(SDL_GetMouseFocus())); - if (scale == 0.0f) { - scale = 1.0f; + float scale = 1.0f; + if (SDL_GetHintBoolean(SDL_HINT_MOUSE_DPI_SCALE_CURSORS, false)) { + scale = SDL_GetDisplayContentScale(SDL_GetDisplayForWindow(SDL_GetMouseFocus())); + if (scale == 0.0f) { + scale = 1.0f; + } } for (CachedCursor *entry = data->cache; entry; entry = entry->next) { if (scale == entry->scale) {