SDL: touch: Replace GetNumTouchDevices/GetTouchDevice with a single function.

From daa38dc79312955fa6cffcc1bc7cc90113e9a006 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Wed, 29 Nov 2023 13:08:52 -0500
Subject: [PATCH] touch: Replace GetNumTouchDevices/GetTouchDevice with a
 single function.

Now it returns an array and optional count, to match other SDL3 APIs.

SDL_GetTouchName() was replaced with a function that takes an instance ID
instead of an index, too.
---
 docs/README-migration.md              |  7 +++++
 docs/README-touch.md                  |  9 +++---
 include/SDL3/SDL_touch.h              | 36 ++++++++--------------
 src/dynapi/SDL_dynapi.sym             |  5 ++-
 src/dynapi/SDL_dynapi_overrides.h     |  5 ++-
 src/dynapi/SDL_dynapi_procs.h         |  5 ++-
 src/events/SDL_touch.c                | 44 ++++++++++++++++-----------
 src/events/SDL_touch_c.h              |  3 ++
 src/video/windows/SDL_windowsevents.c |  2 +-
 9 files changed, 61 insertions(+), 55 deletions(-)

diff --git a/docs/README-migration.md b/docs/README-migration.md
index 14d172f76bda..f19c6159bc87 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -1240,6 +1240,13 @@ If you were using this macro for other things besides SDL ticks values, you can
 
 SDL_GetNumTouchFingers() returns a negative error code if there was an error.
 
+SDL_GetTouchName is replaced with SDL_GetTouchDeviceName(), which takes an SDL_TouchID instead of an index.
+
+The following functions have been removed:
+* SDL_GetNumTouchDevices() - replaced with SDL_GetTouchDevices()
+* SDL_GetTouchDevice() - replaced with SDL_GetTouchDevices()
+
+
 ## SDL_version.h
 
 SDL_GetRevisionNumber() has been removed from the API, it always returned 0 in SDL 2.0.
diff --git a/docs/README-touch.md b/docs/README-touch.md
index 569feb606304..979252797e76 100644
--- a/docs/README-touch.md
+++ b/docs/README-touch.md
@@ -47,11 +47,12 @@ These structures should _never_ be modified.
 
 The following functions are included from SDL_touch.h
 
-To get a SDL_TouchID call SDL_GetTouchDevice(int index).
-This returns a SDL_TouchID.
-IMPORTANT: If the touch has been removed, or there is no touch with the given index, SDL_GetTouchDevice() will return 0. Be sure to check for this!
+Devices are tracked by instance ID, of type SDL_TouchID.
 
-The number of touch devices can be queried with SDL_GetNumTouchDevices().
+To get a list of available device SDL_TouchID values, call SDL_GetTouchDevices().
+This returns an array of device IDs, terminated by a zero ID. Optionally, you can
+get a count of IDs by passing a non-NULL int* to SDL_GetTouchDevices() if you'd
+rather not iterate the whole array to get this number.
 
 A SDL_TouchID may be used to get pointers to SDL_Finger.
 
diff --git a/include/SDL3/SDL_touch.h b/include/SDL3/SDL_touch.h
index fc96305d95e2..9f3d216016d6 100644
--- a/include/SDL3/SDL_touch.h
+++ b/include/SDL3/SDL_touch.h
@@ -65,46 +65,36 @@ typedef struct SDL_Finger
 
 
 /**
- * Get the number of registered touch devices.
+ * Get a list of registered touch devices.
  *
  * On some platforms SDL first sees the touch device if it was actually used.
- * Therefore SDL_GetNumTouchDevices() may return 0 although devices are
+ * Therefore the returned list might be empty, although devices are
  * available. After using all devices at least once the number will be
  * correct.
  *
  * This was fixed for Android in SDL 2.0.1.
  *
- * \returns the number of registered touch devices.
+ * \param count a pointer filled in with the number of devices returned
+ * \returns a 0 terminated array of touch device IDs which should be
+ *          freed with SDL_free(), or NULL on error; call SDL_GetError() for
+ *          more details.
  *
  * \since This function is available since SDL 3.0.0.
- *
- * \sa SDL_GetTouchDevice
  */
-extern DECLSPEC int SDLCALL SDL_GetNumTouchDevices(void);
+extern DECLSPEC SDL_TouchID *SDLCALL SDL_GetTouchDevices(int *count);
 
 /**
- * Get the touch ID with the given index.
- *
- * \param index the touch device index
- * \returns the touch ID with the given index on success or 0 if the index is
- *          invalid; call SDL_GetError() for more information.
- *
- * \since This function is available since SDL 3.0.0.
+ * Get the touch device name as reported from the driver.
  *
- * \sa SDL_GetNumTouchDevices
- */
-extern DECLSPEC SDL_TouchID SDLCALL SDL_GetTouchDevice(int index);
-
-/**
- * Get the touch device name as reported from the driver or NULL if the index
- * is invalid.
+ * You do not own the returned string, do not modify or free it.
  *
- * \param index the touch device index
- * \returns touch device name
+ * \param touchID the touch device instance ID.
+ * \returns touch device name, or NULL on error; call SDL_GetError() for
+ *          more details.
  *
  * \since This function is available since SDL 3.0.0.
  */
-extern DECLSPEC const char* SDLCALL SDL_GetTouchName(int index);
+extern DECLSPEC const char* SDLCALL SDL_GetTouchDeviceName(SDL_TouchID touchID);
 
 /**
  * Get the type of the given touch device.
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 4e8c1cf8721d..8d1bd4811ae3 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -255,7 +255,6 @@ SDL3_0.0.0 {
     SDL_GetNumJoystickButtons;
     SDL_GetNumJoystickHats;
     SDL_GetNumRenderDrivers;
-    SDL_GetNumTouchDevices;
     SDL_GetNumTouchFingers;
     SDL_GetNumVideoDrivers;
     SDL_GetOriginalMemoryFunctions;
@@ -328,10 +327,8 @@ SDL3_0.0.0 {
     SDL_GetThreadName;
     SDL_GetTicks;
     SDL_GetTicksNS;
-    SDL_GetTouchDevice;
     SDL_GetTouchDeviceType;
     SDL_GetTouchFinger;
-    SDL_GetTouchName;
     SDL_GetVersion;
     SDL_GetVideoDriver;
     SDL_GetWindowBordersSize;
@@ -962,6 +959,8 @@ SDL3_0.0.0 {
     SDL_CreateTextureWithProperties;
     SDL_CreateRendererWithProperties;
     SDL_GetGamepadMappings;
+    SDL_GetTouchDevices;
+    SDL_GetTouchDeviceName;
     # extra symbols go here (don't modify this line)
   local: *;
 };
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 8676e44138ca..3be07fa25529 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -279,7 +279,6 @@
 #define SDL_GetNumJoystickButtons SDL_GetNumJoystickButtons_REAL
 #define SDL_GetNumJoystickHats SDL_GetNumJoystickHats_REAL
 #define SDL_GetNumRenderDrivers SDL_GetNumRenderDrivers_REAL
-#define SDL_GetNumTouchDevices SDL_GetNumTouchDevices_REAL
 #define SDL_GetNumTouchFingers SDL_GetNumTouchFingers_REAL
 #define SDL_GetNumVideoDrivers SDL_GetNumVideoDrivers_REAL
 #define SDL_GetOriginalMemoryFunctions SDL_GetOriginalMemoryFunctions_REAL
@@ -352,10 +351,8 @@
 #define SDL_GetThreadName SDL_GetThreadName_REAL
 #define SDL_GetTicks SDL_GetTicks_REAL
 #define SDL_GetTicksNS SDL_GetTicksNS_REAL
-#define SDL_GetTouchDevice SDL_GetTouchDevice_REAL
 #define SDL_GetTouchDeviceType SDL_GetTouchDeviceType_REAL
 #define SDL_GetTouchFinger SDL_GetTouchFinger_REAL
-#define SDL_GetTouchName SDL_GetTouchName_REAL
 #define SDL_GetVersion SDL_GetVersion_REAL
 #define SDL_GetVideoDriver SDL_GetVideoDriver_REAL
 #define SDL_GetWindowBordersSize SDL_GetWindowBordersSize_REAL
@@ -987,3 +984,5 @@
 #define SDL_CreateTextureWithProperties SDL_CreateTextureWithProperties_REAL
 #define SDL_CreateRendererWithProperties SDL_CreateRendererWithProperties_REAL
 #define SDL_GetGamepadMappings SDL_GetGamepadMappings_REAL
+#define SDL_GetTouchDevices SDL_GetTouchDevices_REAL
+#define SDL_GetTouchDeviceName SDL_GetTouchDeviceName_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 5cce83c8abaf..0ae19f03064c 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -338,7 +338,6 @@ SDL_DYNAPI_PROC(int,SDL_GetNumJoystickAxes,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumJoystickButtons,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumJoystickHats,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumRenderDrivers,(void),(),return)
-SDL_DYNAPI_PROC(int,SDL_GetNumTouchDevices,(void),(),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumTouchFingers,(SDL_TouchID a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumVideoDrivers,(void),(),return)
 SDL_DYNAPI_PROC(void,SDL_GetOriginalMemoryFunctions,(SDL_malloc_func *a, SDL_calloc_func *b, SDL_realloc_func *c, SDL_free_func *d),(a,b,c,d),)
@@ -411,10 +410,8 @@ SDL_DYNAPI_PROC(SDL_threadID,SDL_GetThreadID,(SDL_Thread *a),(a),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetThreadName,(SDL_Thread *a),(a),return)
 SDL_DYNAPI_PROC(Uint64,SDL_GetTicks,(void),(),return)
 SDL_DYNAPI_PROC(Uint64,SDL_GetTicksNS,(void),(),return)
-SDL_DYNAPI_PROC(SDL_TouchID,SDL_GetTouchDevice,(int a),(a),return)
 SDL_DYNAPI_PROC(SDL_TouchDeviceType,SDL_GetTouchDeviceType,(SDL_TouchID a),(a),return)
 SDL_DYNAPI_PROC(SDL_Finger*,SDL_GetTouchFinger,(SDL_TouchID a, int b),(a,b),return)
-SDL_DYNAPI_PROC(const char*,SDL_GetTouchName,(int a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetVersion,(SDL_version *a),(a),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetVideoDriver,(int a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetWindowBordersSize,(SDL_Window *a, int *b, int *c, int *d, int *e),(a,b,c,d,e),return)
@@ -1012,3 +1009,5 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_GetBooleanProperty,(SDL_PropertiesID a, const char
 SDL_DYNAPI_PROC(SDL_Texture*,SDL_CreateTextureWithProperties,(SDL_Renderer *a, SDL_PropertiesID b),(a,b),return)
 SDL_DYNAPI_PROC(SDL_Renderer*,SDL_CreateRendererWithProperties,(SDL_PropertiesID a),(a),return)
 SDL_DYNAPI_PROC(char**,SDL_GetGamepadMappings,(int *a),(a),return)
+SDL_DYNAPI_PROC(SDL_TouchID*,SDL_GetTouchDevices,(int *a),(a),return)
+SDL_DYNAPI_PROC(const char*,SDL_GetTouchDeviceName,(SDL_TouchID a),(a),return)
diff --git a/src/events/SDL_touch.c b/src/events/SDL_touch.c
index 9671f49b46bf..08e570909fd8 100644
--- a/src/events/SDL_touch.c
+++ b/src/events/SDL_touch.c
@@ -44,27 +44,32 @@ int SDL_InitTouch(void)
     return 0;
 }
 
-int SDL_GetNumTouchDevices(void)
+SDL_bool SDL_TouchDevicesAvailable(void)
 {
-    return SDL_num_touch;
+    return SDL_num_touch > 0;
 }
 
-SDL_TouchID SDL_GetTouchDevice(int index)
+SDL_TouchID *SDL_GetTouchDevices(int *count)
 {
-    if (index < 0 || index >= SDL_num_touch) {
-        SDL_SetError("Unknown touch device index %d", index);
-        return 0;
+    if (count) {
+        *count = 0;
     }
-    return SDL_touchDevices[index]->id;
-}
 
-const char *SDL_GetTouchName(int index)
-{
-    if (index < 0 || index >= SDL_num_touch) {
-        SDL_SetError("Unknown touch device");
-        return NULL;
+    const int total = SDL_num_touch;
+    SDL_TouchID *retval = (SDL_TouchID *) SDL_malloc(sizeof (SDL_TouchID) * (total + 1));
+    if (!retval) {
+        SDL_OutOfMemory();
+    } else {
+        for (int i = 0; i < total; i++) {
+            retval[i] = SDL_touchDevices[i]->id;
+        }
+        retval[total] = 0;
+        if (count) {
+            *count = SDL_num_touch;
+        }
     }
-    return SDL_touchDevices[index]->name;
+
+    return retval;
 }
 
 static int SDL_GetTouchIndex(SDL_TouchID id)
@@ -96,13 +101,16 @@ SDL_Touch *SDL_GetTouch(SDL_TouchID id)
     return SDL_touchDevices[index];
 }
 
+const char *SDL_GetTouchDeviceName(SDL_TouchID id)
+{
+    SDL_Touch *touch = SDL_GetTouch(id);
+    return touch ? touch->name : NULL;
+}
+
 SDL_TouchDeviceType SDL_GetTouchDeviceType(SDL_TouchID id)
 {
     SDL_Touch *touch = SDL_GetTouch(id);
-    if (touch) {
-        return touch->type;
-    }
-    return SDL_TOUCH_DEVICE_INVALID;
+    return touch ? touch->type : SDL_TOUCH_DEVICE_INVALID;
 }
 
 static int SDL_GetFingerIndex(const SDL_Touch *touch, SDL_FingerID fingerid)
diff --git a/src/events/SDL_touch_c.h b/src/events/SDL_touch_c.h
index c768de8a3d24..34d7e290b618 100644
--- a/src/events/SDL_touch_c.h
+++ b/src/events/SDL_touch_c.h
@@ -36,6 +36,9 @@ typedef struct SDL_Touch
 /* Initialize the touch subsystem */
 extern int SDL_InitTouch(void);
 
+/* Returns SDL_TRUE if _any_ connected touch devices are known to SDL */
+extern SDL_bool SDL_TouchDevicesAvailable(void);
+
 /* Add a touch, returning the index of the touch, or -1 if there was an error. */
 extern int SDL_AddTouch(SDL_TouchID id, SDL_TouchDeviceType type, const char *name);
 
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 8624b92dc9d5..620ab332bd1b 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -668,7 +668,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         if (inp.header.dwType == RIM_TYPEMOUSE) {
             SDL_MouseID mouseID;
             RAWMOUSE *rawmouse;
-            if (SDL_GetNumTouchDevices() > 0 &&
+            if (SDL_TouchDevicesAvailable() &&
                 (GetMouseMessageSource() == SDL_MOUSE_EVENT_SOURCE_TOUCH || (GetMessageExtraInfo() & 0x82) == 0x82)) {
                 break;
             }