SDL: Add SDL_MOUSE_RELATIVE_CURSOR_VISIBLE (#7947) (8b204)

From 8b204815ccef946db9db28c3d2da0790a88f8c3c Mon Sep 17 00:00:00 2001
From: expikr <[EMAIL REDACTED]>
Date: Sun, 16 Jun 2024 06:21:29 -0700
Subject: [PATCH] Add SDL_MOUSE_RELATIVE_CURSOR_VISIBLE (#7947)

(cherry picked from commit ee559d51bed864968e529d4e63e2019d9de72291)
(cherry picked from commit 194d72bb29d22427a53bde63d1634bfdbd07fcc4)
---
 include/SDL_hints.h      | 14 +++++++++++++-
 src/events/SDL_mouse.c   | 15 ++++++++++++++-
 src/events/SDL_mouse_c.h |  1 +
 3 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index e775a6509bc0e..a26ab60e869d4 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -1424,7 +1424,19 @@ extern "C" {
 #define SDL_HINT_MOUSE_RELATIVE_WARP_MOTION  "SDL_MOUSE_RELATIVE_WARP_MOTION"
 
 /**
- *  \brief  A variable controlling whether mouse events should generate synthetic touch events
+ *  \brief  A variable controlling whether the hardware cursor stays visible when relative mode is active.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - The cursor will be hidden while relative mode is active (default)
+ *    "1"       - The cursor will remain visible while relative mode is active
+ *
+ *  Note that for systems without raw hardware inputs, relative mode is implemented using warping, so the hardware cursor will visibly warp between frames if this is enabled on those systems.
+ */
+#define SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE  "SDL_MOUSE_RELATIVE_CURSOR_VISIBLE"
+
+/**
+ * A variable controlling whether mouse events should generate synthetic touch
+ * events
  *
  *  This variable can be set to the following values:
  *    "0"       - Mouse events will not generate touch events (default for desktop platforms)
diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c
index 431354f88b39b..b13383279d768 100644
--- a/src/events/SDL_mouse.c
+++ b/src/events/SDL_mouse.c
@@ -170,6 +170,13 @@ static void SDLCALL SDL_MouseRelativeWarpMotionChanged(void *userdata, const cha
     mouse->relative_mode_warp_motion = SDL_GetStringBoolean(hint, SDL_FALSE);
 }
 
+static void SDLCALL SDL_MouseRelativeCursorVisibleChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
+{
+    SDL_Mouse *mouse = (SDL_Mouse *)userdata;
+
+    mouse->relative_mode_cursor_visible = SDL_GetStringBoolean(hint, SDL_FALSE);
+}
+
 /* Public functions */
 int SDL_MousePreInit(void)
 {
@@ -209,6 +216,9 @@ int SDL_MousePreInit(void)
     SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION,
                         SDL_MouseRelativeWarpMotionChanged, mouse);
 
+    SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE,
+                        SDL_MouseRelativeCursorVisibleChanged, mouse);
+
     mouse->was_touch_mouse_events = SDL_FALSE; /* no touch to mouse movement event pending */
 
     mouse->cursor_shown = SDL_TRUE;
@@ -992,6 +1002,9 @@ void SDL_MouseQuit(void)
 
     SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION,
                         SDL_MouseRelativeWarpMotionChanged, mouse);
+
+    SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE,
+                        SDL_MouseRelativeCursorVisibleChanged, mouse);
 }
 
 Uint32 SDL_GetMouseState(int *x, int *y)
@@ -1412,7 +1425,7 @@ void SDL_SetCursor(SDL_Cursor *cursor)
         }
     }
 
-    if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
+    if (cursor && mouse->cursor_shown && (!mouse->relative_mode || mouse->relative_mode_cursor_visible)) {
         if (mouse->ShowCursor) {
             mouse->ShowCursor(cursor);
         }
diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h
index 4204f6201f746..db1c6c4f6fd25 100644
--- a/src/events/SDL_mouse_c.h
+++ b/src/events/SDL_mouse_c.h
@@ -92,6 +92,7 @@ typedef struct
     SDL_bool relative_mode;
     SDL_bool relative_mode_warp;
     SDL_bool relative_mode_warp_motion;
+    SDL_bool relative_mode_cursor_visible;
     SDL_bool enable_normal_speed_scale;
     float normal_speed_scale;
     SDL_bool enable_relative_speed_scale;