SDL: Add `SDL_IsTV()` (#11004)

From 5f5379dc9920254fe817d4e56b408339e5d2b691 Mon Sep 17 00:00:00 2001
From: Anthony <[EMAIL REDACTED]>
Date: Tue, 1 Oct 2024 17:20:00 +0100
Subject: [PATCH] Add `SDL_IsTV()` (#11004)

Moved SDL_IsAndroidTV() out of public API, to match SDL_IsAndroidTablet().

Added SDL_IsTV(), to mirror existing SDL_IsTablet().
---
 build-scripts/SDL_migration.cocci |  5 +++++
 docs/README-migration.md          |  3 +++
 include/SDL3/SDL_system.h         | 20 +++++++++++---------
 src/SDL.c                         | 13 +++++++++++++
 src/core/SDL_core_unsupported.c   |  7 -------
 src/dynapi/SDL_dynapi.sym         |  2 +-
 src/dynapi/SDL_dynapi_overrides.h |  2 +-
 src/dynapi/SDL_dynapi_procs.h     |  2 +-
 src/video/uikit/SDL_uikitvideo.m  |  7 ++++++-
 9 files changed, 41 insertions(+), 20 deletions(-)

diff --git a/build-scripts/SDL_migration.cocci b/build-scripts/SDL_migration.cocci
index 9e3a4d6a24a0b..1db737a82de55 100644
--- a/build-scripts/SDL_migration.cocci
+++ b/build-scripts/SDL_migration.cocci
@@ -3699,3 +3699,8 @@ identifier func =~ "^(SDL_AddEventWatch|SDL_AddHintCallback|SDL_AddSurfaceAltern
 @@
 - SDL_FALSE
 + false
+@@
+@@
+- SDL_IsAndroidTV
++ SDL_IsTV
+  (...)
diff --git a/docs/README-migration.md b/docs/README-migration.md
index 27ef83256216e..47d0f6990839e 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -1888,6 +1888,8 @@ SDL_RequestAndroidPermission is no longer a blocking call; the caller now provid
 
 SDL_iPhoneSetAnimationCallback() and SDL_iPhoneSetEventPump() have been renamed to SDL_SetiOSAnimationCallback() and SDL_SetiOSEventPump(), respectively. SDL2 has had macros to provide this new name with the old symbol since the introduction of the iPad, but now the correctly-named symbol is the only option.
 
+SDL_IsAndroidTV() has been renamed SDL_IsTV() and is no longer Android-specific; an app running on an Apple TV device will also return true, for example.
+
 The following functions have been removed:
 * SDL_GetWinRTFSPathUNICODE() - WinRT support was removed in SDL3.
 * SDL_GetWinRTFSPathUTF8() - WinRT support was removed in SDL3.
@@ -1911,6 +1913,7 @@ The following functions have been renamed:
 * SDL_Direct3D9GetAdapterIndex() => SDL_GetDirect3D9AdapterIndex()
 * SDL_GDKGetDefaultUser() => SDL_GetGDKDefaultUser(), returns bool
 * SDL_GDKGetTaskQueue() => SDL_GetGDKTaskQueue(), returns bool
+* SDL_IsAndroidTV() => SDL_IsTV()
 * SDL_LinuxSetThreadPriority() => SDL_SetLinuxThreadPriority(), returns bool
 * SDL_LinuxSetThreadPriorityAndPolicy() => SDL_SetLinuxThreadPriorityAndPolicy(), returns bool
 * SDL_OnApplicationDidBecomeActive() => SDL_OnApplicationDidEnterForeground()
diff --git a/include/SDL3/SDL_system.h b/include/SDL3/SDL_system.h
index a005cfa5a2cb0..88e318ddf4e8a 100644
--- a/include/SDL3/SDL_system.h
+++ b/include/SDL3/SDL_system.h
@@ -346,15 +346,6 @@ extern SDL_DECLSPEC void * SDLCALL SDL_GetAndroidActivity(void);
  */
 extern SDL_DECLSPEC int SDLCALL SDL_GetAndroidSDKVersion(void);
 
-/**
- * Query if the application is running on Android TV.
- *
- * \returns true if this is Android TV, false otherwise.
- *
- * \since This function is available since SDL 3.0.0.
- */
-extern SDL_DECLSPEC bool SDLCALL SDL_IsAndroidTV(void);
-
 /**
  * Query if the application is running on a Chromebook.
  *
@@ -563,6 +554,17 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SendAndroidMessage(Uint32 command, int para
  */
 extern SDL_DECLSPEC bool SDLCALL SDL_IsTablet(void);
 
+/**
+ * Query if the current device is a TV.
+ *
+ * If SDL can't determine this, it will return false.
+ *
+ * \returns true if the device is a TV, false otherwise.
+ *
+ * \since This function is available since SDL 3.0.0.
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_IsTV(void);
+
 /* Functions used by iOS app delegates to notify SDL about state changes. */
 
 /**
diff --git a/src/SDL.c b/src/SDL.c
index 11623a3403e4c..c140ef36caeaf 100644
--- a/src/SDL.c
+++ b/src/SDL.c
@@ -721,6 +721,19 @@ bool SDL_IsTablet(void)
 #endif
 }
 
+bool SDL_IsTV(void)
+{
+#ifdef SDL_PLATFORM_ANDROID
+    extern bool SDL_IsAndroidTV(void);
+    return SDL_IsAndroidTV();
+#elif defined(SDL_PLATFORM_IOS)
+    extern bool SDL_IsAppleTV(void);
+    return SDL_IsAppleTV();
+#else
+    return false;
+#endif
+}
+
 #ifdef SDL_PLATFORM_WIN32
 
 #if (!defined(HAVE_LIBC) || defined(__WATCOMC__)) && !defined(SDL_STATIC_LIB)
diff --git a/src/core/SDL_core_unsupported.c b/src/core/SDL_core_unsupported.c
index 244a596a65b29..b36c7f7441ec7 100644
--- a/src/core/SDL_core_unsupported.c
+++ b/src/core/SDL_core_unsupported.c
@@ -188,13 +188,6 @@ int SDL_GetAndroidSDKVersion(void)
     return SDL_Unsupported();
 }
 
-SDL_DECLSPEC bool SDLCALL SDL_IsAndroidTV(void);
-bool SDL_IsAndroidTV(void)
-{
-    SDL_Unsupported();
-    return false;
-}
-
 SDL_DECLSPEC bool SDLCALL SDL_IsChromebook(void);
 bool SDL_IsChromebook(void)
 {
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 2b6bd0c2e45a7..f0141fbd8f9f2 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -594,7 +594,6 @@ SDL3_0.0.0 {
     SDL_InitHapticRumble;
     SDL_InitSubSystem;
     SDL_InsertGPUDebugLabel;
-    SDL_IsAndroidTV;
     SDL_IsChromebook;
     SDL_IsDeXMode;
     SDL_IsGamepad;
@@ -602,6 +601,7 @@ SDL3_0.0.0 {
     SDL_IsJoystickVirtual;
     SDL_IsMouseHaptic;
     SDL_IsTablet;
+    SDL_IsTV;
     SDL_JoystickConnected;
     SDL_JoystickEventsEnabled;
     SDL_KillProcess;
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 44e7c67d58c76..697fbb5d927d3 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -619,7 +619,6 @@
 #define SDL_InitHapticRumble SDL_InitHapticRumble_REAL
 #define SDL_InitSubSystem SDL_InitSubSystem_REAL
 #define SDL_InsertGPUDebugLabel SDL_InsertGPUDebugLabel_REAL
-#define SDL_IsAndroidTV SDL_IsAndroidTV_REAL
 #define SDL_IsChromebook    SDL_IsChromebook_REAL
 #define SDL_IsDeXMode   SDL_IsDeXMode_REAL
 #define SDL_IsGamepad SDL_IsGamepad_REAL
@@ -627,6 +626,7 @@
 #define SDL_IsJoystickVirtual SDL_IsJoystickVirtual_REAL
 #define SDL_IsMouseHaptic SDL_IsMouseHaptic_REAL
 #define SDL_IsTablet SDL_IsTablet_REAL
+#define SDL_IsTV SDL_IsTV_REAL
 #define SDL_JoystickConnected SDL_JoystickConnected_REAL
 #define SDL_JoystickEventsEnabled SDL_JoystickEventsEnabled_REAL
 #define SDL_KillProcess SDL_KillProcess_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 214ced1bf6c30..1ece8bd1d5d76 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -639,7 +639,6 @@ SDL_DYNAPI_PROC(bool,SDL_Init,(SDL_InitFlags a),(a),return)
 SDL_DYNAPI_PROC(bool,SDL_InitHapticRumble,(SDL_Haptic *a),(a),return)
 SDL_DYNAPI_PROC(bool,SDL_InitSubSystem,(SDL_InitFlags a),(a),return)
 SDL_DYNAPI_PROC(void,SDL_InsertGPUDebugLabel,(SDL_GPUCommandBuffer *a, const char *b),(a,b),)
-SDL_DYNAPI_PROC(bool,SDL_IsAndroidTV,(void),(),return)
 SDL_DYNAPI_PROC(bool,SDL_IsChromebook,(void),(),return)
 SDL_DYNAPI_PROC(bool,SDL_IsDeXMode,(void),(),return)
 SDL_DYNAPI_PROC(bool,SDL_IsGamepad,(SDL_JoystickID a),(a),return)
@@ -647,6 +646,7 @@ SDL_DYNAPI_PROC(bool,SDL_IsJoystickHaptic,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(bool,SDL_IsJoystickVirtual,(SDL_JoystickID a),(a),return)
 SDL_DYNAPI_PROC(bool,SDL_IsMouseHaptic,(void),(),return)
 SDL_DYNAPI_PROC(bool,SDL_IsTablet,(void),(),return)
+SDL_DYNAPI_PROC(bool,SDL_IsTV,(void),(),return)
 SDL_DYNAPI_PROC(bool,SDL_JoystickConnected,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(bool,SDL_JoystickEventsEnabled,(void),(),return)
 SDL_DYNAPI_PROC(bool,SDL_KillProcess,(SDL_Process *a, bool b),(a,b),return)
diff --git a/src/video/uikit/SDL_uikitvideo.m b/src/video/uikit/SDL_uikitvideo.m
index 02f903edfe83e..4866de9785637 100644
--- a/src/video/uikit/SDL_uikitvideo.m
+++ b/src/video/uikit/SDL_uikitvideo.m
@@ -297,7 +297,7 @@ void SDL_NSLog(const char *prefix, const char *text)
 #endif // SDL_VIDEO_DRIVER_COCOA
 
 /*
- * iOS Tablet detection
+ * iOS Tablet, etc, detection
  *
  * This doesn't really have anything to do with the interfaces of the SDL video
  * subsystem, but we need to stuff this into an Objective-C source code file.
@@ -307,4 +307,9 @@ bool SDL_IsIPad(void)
     return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad);
 }
 
+bool SDL_IsAppleTV(void)
+{
+    return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomTV);
+}
+
 #endif // SDL_VIDEO_DRIVER_UIKIT