SDL: hint for which system cursor to use as default

From d55e6dfc5e6a3074e624b7f4710a329b71a4f5be Mon Sep 17 00:00:00 2001
From: expikr <[EMAIL REDACTED]>
Date: Mon, 25 Nov 2024 10:54:27 +0800
Subject: [PATCH] hint for which system cursor to use as default

Co-Authored-By: Sam Lantinga <slouken@libsdl.org>
---
 include/SDL3/SDL_hints.h                   | 11 ++++++++++
 src/events/SDL_mouse.c                     | 13 +++++++++++
 src/events/SDL_mouse_c.h                   |  3 +++
 src/video/android/SDL_androidmouse.c       |  3 ++-
 src/video/cocoa/SDL_cocoamouse.m           | 25 ++++++----------------
 src/video/emscripten/SDL_emscriptenmouse.c |  4 +++-
 src/video/haiku/SDL_bvideo.cc              |  3 ++-
 src/video/wayland/SDL_waylandmouse.c       |  3 ++-
 src/video/windows/SDL_windowsmouse.c       | 11 +++++-----
 src/video/x11/SDL_x11mouse.c               | 12 +++++------
 10 files changed, 54 insertions(+), 34 deletions(-)

diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h
index a8e03d03a82a0..313cdf474e9b1 100644
--- a/include/SDL3/SDL_hints.h
+++ b/include/SDL3/SDL_hints.h
@@ -2401,6 +2401,17 @@ extern "C" {
  */
 #define SDL_HINT_MOUSE_DOUBLE_CLICK_TIME "SDL_MOUSE_DOUBLE_CLICK_TIME"
 
+/**
+ * A variable setting which system cursor to use as the default cursor.
+ * This should be an integer corresponding to the SDL_SystemCursor enum.
+ * The default value is zero (SDL_SYSTEM_CURSOR_DEFAULT).
+ *
+ * This hint needs to be set before SDL_Init().
+ *
+ * \since This hint is available since SDL 3.1.3.
+ */
+#define SDL_HINT_MOUSE_DEFAULT_SYSTEM_CURSOR "SDL_MOUSE_DEFAULT_SYSTEM_CURSOR"
+
 /**
  * A variable controlling whether warping a hidden mouse cursor will activate
  * relative mouse mode.
diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c
index 2923e8b52b415..657bad9a6c237 100644
--- a/src/events/SDL_mouse.c
+++ b/src/events/SDL_mouse.c
@@ -440,6 +440,19 @@ void SDL_SetDefaultCursor(SDL_Cursor *cursor)
     }
 }
 
+SDL_SystemCursor SDL_GetDefaultSystemCursor(void) 
+{
+    SDL_SystemCursor id = SDL_SYSTEM_CURSOR_DEFAULT;
+    const char *value = SDL_GetHint(SDL_HINT_MOUSE_DEFAULT_SYSTEM_CURSOR);
+    if (value) {
+        int index = SDL_atoi(value);
+        if (0 <= index && index < (int)SDL_SYSTEM_CURSOR_COUNT) {
+            id = (SDL_SystemCursor)index;
+        }
+    }
+    return id;
+}
+
 SDL_Mouse *SDL_GetMouse(void)
 {
     return &SDL_mouse;
diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h
index 6b646a72b8fc4..d77d0a7e10bf4 100644
--- a/src/events/SDL_mouse_c.h
+++ b/src/events/SDL_mouse_c.h
@@ -158,6 +158,9 @@ extern SDL_Mouse *SDL_GetMouse(void);
 // Set the default mouse cursor
 extern void SDL_SetDefaultCursor(SDL_Cursor *cursor);
 
+// Get the preferred default system cursor
+extern SDL_SystemCursor SDL_GetDefaultSystemCursor(void);
+
 // Set the mouse focus window
 extern void SDL_SetMouseFocus(SDL_Window *window);
 
diff --git a/src/video/android/SDL_androidmouse.c b/src/video/android/SDL_androidmouse.c
index 42a91800b3435..b243c2b429a43 100644
--- a/src/video/android/SDL_androidmouse.c
+++ b/src/video/android/SDL_androidmouse.c
@@ -75,7 +75,8 @@ static SDL_Cursor *Android_WrapCursor(int custom_cursor, int system_cursor)
 
 static SDL_Cursor *Android_CreateDefaultCursor(void)
 {
-    return Android_WrapCursor(0, SDL_SYSTEM_CURSOR_DEFAULT);
+    SDL_SystemCursor id = SDL_GetDefaultSystemCursor();
+    return Android_WrapCursor(0, id);
 }
 
 static SDL_Cursor *Android_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
diff --git a/src/video/cocoa/SDL_cocoamouse.m b/src/video/cocoa/SDL_cocoamouse.m
index 24d7863bed1df..8f2cef5816887 100644
--- a/src/video/cocoa/SDL_cocoamouse.m
+++ b/src/video/cocoa/SDL_cocoamouse.m
@@ -63,25 +63,6 @@ + (NSCursor *)invisibleCursor
 }
 @end
 
-static SDL_Cursor *Cocoa_CreateDefaultCursor(void)
-{
-    @autoreleasepool {
-        NSCursor *nscursor;
-        SDL_Cursor *cursor = NULL;
-
-        nscursor = [NSCursor arrowCursor];
-
-        if (nscursor) {
-            cursor = SDL_calloc(1, sizeof(*cursor));
-            if (cursor) {
-                cursor->internal = (void *)CFBridgingRetain(nscursor);
-            }
-        }
-
-        return cursor;
-    }
-}
-
 static SDL_Cursor *Cocoa_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
 {
     @autoreleasepool {
@@ -229,6 +210,12 @@ + (NSCursor *)invisibleCursor
     }
 }
 
+static SDL_Cursor *Cocoa_CreateDefaultCursor(void)
+{
+    SDL_SystemCursor id = SDL_GetDefaultSystemCursor();
+    return Cocoa_CreateSystemCursor(id);
+}
+
 static void Cocoa_FreeCursor(SDL_Cursor *cursor)
 {
     @autoreleasepool {
diff --git a/src/video/emscripten/SDL_emscriptenmouse.c b/src/video/emscripten/SDL_emscriptenmouse.c
index 44ca4dd773c9f..64f49a5e7b58e 100644
--- a/src/video/emscripten/SDL_emscriptenmouse.c
+++ b/src/video/emscripten/SDL_emscriptenmouse.c
@@ -62,7 +62,9 @@ static SDL_Cursor *Emscripten_CreateCursorFromString(const char *cursor_str, boo
 
 static SDL_Cursor *Emscripten_CreateDefaultCursor(void)
 {
-    return Emscripten_CreateCursorFromString("default", false);
+    SDL_SystemCursor id = SDL_GetDefaultSystemCursor();
+    const char *cursor_name = SDL_GetCSSCursorName(id, NULL);
+    return Emscripten_CreateCursorFromString(cursor_name, false);
 }
 
 EM_JS_DEPS(sdlmouse, "$stringToUTF8,$UTF8ToString");
diff --git a/src/video/haiku/SDL_bvideo.cc b/src/video/haiku/SDL_bvideo.cc
index 23521f73f29b8..854c1b39c5895 100644
--- a/src/video/haiku/SDL_bvideo.cc
+++ b/src/video/haiku/SDL_bvideo.cc
@@ -180,7 +180,8 @@ static SDL_Cursor * HAIKU_CreateSystemCursor(SDL_SystemCursor id)
 
 static SDL_Cursor * HAIKU_CreateDefaultCursor()
 {
-    return HAIKU_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT);
+    SDL_SystemCursor id = SDL_GetDefaultSystemCursor();
+    return HAIKU_CreateSystemCursor(id);
 }
 
 static void HAIKU_FreeCursor(SDL_Cursor * cursor)
diff --git a/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c
index 3c35424a2b35d..cdce66b1ed407 100644
--- a/src/video/wayland/SDL_waylandmouse.c
+++ b/src/video/wayland/SDL_waylandmouse.c
@@ -592,7 +592,8 @@ static SDL_Cursor *Wayland_CreateSystemCursor(SDL_SystemCursor id)
 
 static SDL_Cursor *Wayland_CreateDefaultCursor(void)
 {
-    return Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT);
+    SDL_SystemCursor id = SDL_GetDefaultSystemCursor();
+    return Wayland_CreateSystemCursor(id);
 }
 
 static void Wayland_FreeCursorData(SDL_CursorData *d)
diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c
index 3e09b92be54b3..d53a1f20c544c 100644
--- a/src/video/windows/SDL_windowsmouse.c
+++ b/src/video/windows/SDL_windowsmouse.c
@@ -84,11 +84,6 @@ static SDL_Cursor *WIN_CreateCursorAndData(HCURSOR hcursor)
     return cursor;
 }
 
-static SDL_Cursor *WIN_CreateDefaultCursor(void)
-{
-    return WIN_CreateCursorAndData(LoadCursor(NULL, IDC_ARROW));
-}
-
 static bool IsMonochromeSurface(SDL_Surface *surface)
 {
     int x, y;
@@ -342,6 +337,12 @@ static SDL_Cursor *WIN_CreateSystemCursor(SDL_SystemCursor id)
     return WIN_CreateCursorAndData(LoadCursor(NULL, name));
 }
 
+static SDL_Cursor *WIN_CreateDefaultCursor(void)
+{
+    SDL_SystemCursor id = SDL_GetDefaultSystemCursor();
+    return WIN_CreateSystemCursor(id);
+}
+
 static void WIN_FreeCursor(SDL_Cursor *cursor)
 {
     SDL_CursorData *data = cursor->internal;
diff --git a/src/video/x11/SDL_x11mouse.c b/src/video/x11/SDL_x11mouse.c
index 8a366ad58946a..5015d957156af 100644
--- a/src/video/x11/SDL_x11mouse.c
+++ b/src/video/x11/SDL_x11mouse.c
@@ -89,12 +89,6 @@ static SDL_Cursor *X11_CreateCursorAndData(Cursor x11_cursor)
     return cursor;
 }
 
-static SDL_Cursor *X11_CreateDefaultCursor(void)
-{
-    // None is used to indicate the default cursor
-    return X11_CreateCursorAndData(None);
-}
-
 #ifdef SDL_VIDEO_DRIVER_X11_XCURSOR
 static Cursor X11_CreateXCursorCursor(SDL_Surface *surface, int hot_x, int hot_y)
 {
@@ -279,6 +273,12 @@ static SDL_Cursor *X11_CreateSystemCursor(SDL_SystemCursor id)
     return cursor;
 }
 
+static SDL_Cursor *X11_CreateDefaultCursor(void)
+{
+    SDL_SystemCursor id = SDL_GetDefaultSystemCursor();
+    return X11_CreateSystemCursor(id);
+}
+
 static void X11_FreeCursor(SDL_Cursor *cursor)
 {
     Cursor x11_cursor = cursor->internal->cursor;