sdl2-compat: logging: Wrap log output function to fixup log priority values

From e810efc0ad93efb2583f32ceeb7e9972b00eef84 Mon Sep 17 00:00:00 2001
From: Cameron Gutman <[EMAIL REDACTED]>
Date: Sat, 8 Feb 2025 15:42:41 -0600
Subject: [PATCH] logging: Wrap log output function to fixup log priority
 values

---
 src/dynapi/SDL_dynapi_procs.h |  4 ++--
 src/sdl2_compat.c             | 26 ++++++++++++++++++++++++++
 src/sdl2_compat.h             |  2 ++
 src/sdl2_protos.h             |  4 ++--
 src/sdl3_syms.h               |  5 +++--
 5 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 1cd4c25..3e045d9 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -264,8 +264,8 @@ SDL_DYNAPI_PROC(void,SDL_LogSetPriority,(int a, SDL2_LogPriority b),(a,b),)
 SDL_DYNAPI_PROC(SDL2_LogPriority,SDL_LogGetPriority,(int a),(a),return)
 SDL_DYNAPI_PROC(void,SDL_LogResetPriorities,(void),(),)
 SDL_DYNAPI_PROC(void,SDL_LogMessageV,(int a, SDL2_LogPriority b, const char *c, va_list d),(a,b,c,d),)
-SDL_DYNAPI_PROC(void,SDL_LogGetOutputFunction,(SDL_LogOutputFunction *a, void **b),(a,b),)
-SDL_DYNAPI_PROC(void,SDL_LogSetOutputFunction,(SDL_LogOutputFunction a, void *b),(a,b),)
+SDL_DYNAPI_PROC(void,SDL_LogGetOutputFunction,(SDL2_LogOutputFunction *a, void **b),(a,b),)
+SDL_DYNAPI_PROC(void,SDL_LogSetOutputFunction,(SDL2_LogOutputFunction a, void *b),(a,b),)
 SDL_DYNAPI_PROC(void,SDL_SetMainReady,(void),(),)
 SDL_DYNAPI_PROC(int,SDL_ShowMessageBox,(const SDL_MessageBoxData *a, int *b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_ShowSimpleMessageBox,(Uint32 a, const char *b, const char *c, SDL_Window *d),(a,b,c,d),return)
diff --git a/src/sdl2_compat.c b/src/sdl2_compat.c
index b544a6b..0f4b3a8 100644
--- a/src/sdl2_compat.c
+++ b/src/sdl2_compat.c
@@ -955,6 +955,7 @@ static SDL2_Surface *OldWindowSurfaces[16];
 static SDL2_EventFilter EventFilter2 = NULL;
 static void *EventFilterUserData2 = NULL;
 static SDL_mutex *EventWatchListMutex = NULL;
+static SDL2_LogOutputFunction LogOutputFunction2 = NULL;
 static EventFilterWrapperData *EventWatchers2 = NULL;
 static SDL2_bool relative_mouse_mode = SDL2_FALSE;
 static SDL_JoystickID *joystick_list = NULL;
@@ -1333,6 +1334,31 @@ SDL_LOG_IMPL(Error, ERROR)
 SDL_LOG_IMPL(Critical, CRITICAL)
 #undef SDL_LOG_IMPL
 
+static void SDLCALL LogOutputFunction3to2(void *userdata, int category, SDL_LogPriority priority, const char *message)
+{
+    LogOutputFunction2(userdata, category, LogPriority3to2(priority), message);
+}
+
+SDL_DECLSPEC void SDLCALL SDL_LogSetOutputFunction(SDL2_LogOutputFunction callback, void *userdata)
+{
+    if (callback == NULL || (SDL_LogOutputFunction)callback == SDL3_GetDefaultLogOutputFunction()) {
+        /* This is the original SDL3 default logger or NULL logger. Don't use the 3to2 thunk. */
+        SDL3_SetLogOutputFunction((SDL_LogOutputFunction)callback, userdata);
+    } else {
+        LogOutputFunction2 = callback;
+        SDL3_SetLogOutputFunction(LogOutputFunction3to2, userdata);
+    }
+}
+
+SDL_DECLSPEC void SDLCALL SDL_LogGetOutputFunction(SDL2_LogOutputFunction *callback, void **userdata)
+{
+    SDL3_GetLogOutputFunction((SDL_LogOutputFunction *)callback, userdata);
+    if (callback && (SDL_LogOutputFunction)*callback == LogOutputFunction3to2) {
+        /* Return the real function, not our 3to2 thunk */
+        *callback = LogOutputFunction2;
+    }
+}
+
 static void UpdateGamepadButtonSwap(SDL_Gamepad *gamepad)
 {
     int i;
diff --git a/src/sdl2_compat.h b/src/sdl2_compat.h
index 17ac80f..9a8561f 100644
--- a/src/sdl2_compat.h
+++ b/src/sdl2_compat.h
@@ -126,6 +126,8 @@ typedef enum SDL2_LogPriority
     SDL2_NUM_LOG_PRIORITIES
 } SDL2_LogPriority;
 
+typedef void (SDLCALL *SDL2_LogOutputFunction)(void *userdata, int category, SDL2_LogPriority priority, const char *message);
+
 typedef SDL_AtomicInt SDL_atomic_t;
 
 typedef SDL_Condition SDL_cond;
diff --git a/src/sdl2_protos.h b/src/sdl2_protos.h
index 3fb2229..0630cc2 100644
--- a/src/sdl2_protos.h
+++ b/src/sdl2_protos.h
@@ -262,8 +262,8 @@ SDL2_PROTO(void,LogSetPriority,(int a, SDL2_LogPriority b))
 SDL2_PROTO(SDL2_LogPriority,LogGetPriority,(int a))
 SDL2_PROTO(void,LogResetPriorities,(void))
 SDL2_PROTO(void,LogMessageV,(int a, SDL2_LogPriority b, const char *c, va_list d))
-SDL2_PROTO(void,LogGetOutputFunction,(SDL_LogOutputFunction *a, void **b))
-SDL2_PROTO(void,LogSetOutputFunction,(SDL_LogOutputFunction a, void *b))
+SDL2_PROTO(void,LogGetOutputFunction,(SDL2_LogOutputFunction *a, void **b))
+SDL2_PROTO(void,LogSetOutputFunction,(SDL2_LogOutputFunction a, void *b))
 SDL2_PROTO(void,SetMainReady,(void))
 SDL2_PROTO(int,ShowMessageBox,(const SDL_MessageBoxData *a, int *b))
 SDL2_PROTO(int,ShowSimpleMessageBox,(Uint32 a, const char *b, const char *c, SDL_Window *d))
diff --git a/src/sdl3_syms.h b/src/sdl3_syms.h
index bb7155d..3738e55 100644
--- a/src/sdl3_syms.h
+++ b/src/sdl3_syms.h
@@ -516,13 +516,14 @@ SDL3_SYM(void,LockMutex,(SDL_Mutex *a),(a),)
 SDL3_SYM(bool,LockSurface,(SDL_Surface *a),(a),return)
 SDL3_SYM_PASSTHROUGH_RETCODE(bool,LockTexture,(SDL_Texture *a, const SDL_Rect *b, void **c, int *d),(a,b,c,d),return)
 SDL3_SYM(bool,LockTextureToSurface,(SDL_Texture *a, const SDL_Rect *b, SDL_Surface **c),(a,b,c),return)
-SDL3_SYM_RENAMED(void,LogGetOutputFunction,GetLogOutputFunction,(SDL_LogOutputFunction *a, void **b),(a,b),)
+SDL3_SYM(void,GetLogOutputFunction,(SDL_LogOutputFunction *a, void **b),(a,b),)
 SDL3_SYM(SDL_LogPriority,GetLogPriority,(int a),(a),return)
 SDL3_SYM(void,LogMessageV,(int a, SDL_LogPriority b, const char *c, va_list d),(a,b,c,d),)
 SDL3_SYM_RENAMED(void,LogResetPriorities,ResetLogPriorities,(void),(),)
 SDL3_SYM(void,SetLogPriorities,(SDL_LogPriority a),(a),)
-SDL3_SYM_RENAMED(void,LogSetOutputFunction,SetLogOutputFunction,(SDL_LogOutputFunction a, void *b),(a,b),)
+SDL3_SYM(void,SetLogOutputFunction,(SDL_LogOutputFunction a, void *b),(a,b),)
 SDL3_SYM(void,SetLogPriority,(int a, SDL_LogPriority b),(a,b),)
+SDL3_SYM(SDL_LogOutputFunction,GetDefaultLogOutputFunction,(void),(),return)
 SDL3_SYM(Uint32,MapRGB,(const SDL_PixelFormatDetails *a, const SDL_Palette *b, Uint8 c, Uint8 d, Uint8 e),(a,b,c,d,e),return)
 SDL3_SYM(Uint32,MapRGBA,(const SDL_PixelFormatDetails *a, const SDL_Palette *b, Uint8 c, Uint8 d, Uint8 e, Uint8 f),(a,b,c,d,e,f),return)
 SDL3_SYM(bool,MaximizeWindow,(SDL_Window *a),(a),return)