SDL: Changed main callback return values to an enumeration

From 438a2144207b71418927cc45d72c774bb12dec06 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 16 Aug 2024 09:54:35 -0700
Subject: [PATCH] Changed main callback return values to an enumeration

Fixes https://github.com/libsdl-org/SDL/issues/10515
---
 .../01-simple-playback/simple-playback.c      |  6 +-
 .../simple-playback-callback.c                |  6 +-
 examples/audio/03-load-wav/load-wav.c         |  6 +-
 examples/game/01-snake/main.c                 |  6 +-
 examples/pen/01-drawing-lines/drawing-lines.c |  6 +-
 examples/renderer/01-clear/renderer-clear.c   |  6 +-
 .../02-primitives/renderer-primitives.c       |  6 +-
 examples/template.c                           |  6 +-
 include/SDL3/SDL_init.h                       | 19 ++++
 include/SDL3/SDL_main.h                       | 55 +-----------
 include/SDL3/SDL_test_common.h                |  2 +-
 src/main/SDL_main_callbacks.c                 | 24 ++---
 src/main/SDL_main_callbacks.h                 |  4 +-
 src/main/emscripten/SDL_sysmain_callbacks.c   | 12 +--
 src/main/generic/SDL_sysmain_callbacks.c      |  6 +-
 src/main/ios/SDL_sysmain_callbacks.m          | 12 +--
 src/test/SDL_test_common.c                    |  4 +-
 test/loopwave.c                               |  6 +-
 test/testaudio.c                              |  6 +-
 test/testaudiorecording.c                     |  6 +-
 test/testcamera.c                             |  6 +-
 test/testdropfile.c                           | 89 ++++++++++---------
 test/testpen.c                                |  6 +-
 test/testsprite.c                             | 82 ++++++++---------
 24 files changed, 180 insertions(+), 207 deletions(-)

diff --git a/examples/audio/01-simple-playback/simple-playback.c b/examples/audio/01-simple-playback/simple-playback.c
index ecf0c2dba0913..efefd8be79782 100644
--- a/examples/audio/01-simple-playback/simple-playback.c
+++ b/examples/audio/01-simple-playback/simple-playback.c
@@ -17,7 +17,7 @@ static SDL_AudioStream *stream = NULL;
 static int total_samples_generated = 0;
 
 /* This function runs once at startup. */
-int SDL_AppInit(void **appstate, int argc, char *argv[])
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
 {
     SDL_AudioSpec spec;
 
@@ -51,7 +51,7 @@ int SDL_AppInit(void **appstate, int argc, char *argv[])
 }
 
 /* This function runs when a new event (mouse input, keypresses, etc) occurs. */
-int SDL_AppEvent(void *appstate, const SDL_Event *event)
+SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
 {
     if (event->type == SDL_EVENT_QUIT) {
         return SDL_APP_SUCCESS;  /* end the program, reporting success to the OS. */
@@ -60,7 +60,7 @@ int SDL_AppEvent(void *appstate, const SDL_Event *event)
 }
 
 /* This function runs once per frame, and is the heart of the program. */
-int SDL_AppIterate(void *appstate)
+SDL_AppResult SDL_AppIterate(void *appstate)
 {
     /* see if we need to feed the audio stream more data yet.
        We're being lazy here, but if there's less than half a second queued, generate more.
diff --git a/examples/audio/02-simple-playback-callback/simple-playback-callback.c b/examples/audio/02-simple-playback-callback/simple-playback-callback.c
index 1fa1e0b02e6eb..ff71d746a1533 100644
--- a/examples/audio/02-simple-playback-callback/simple-playback-callback.c
+++ b/examples/audio/02-simple-playback-callback/simple-playback-callback.c
@@ -49,7 +49,7 @@ static void SDLCALL FeedTheAudioStreamMore(void *userdata, SDL_AudioStream *astr
 }
 
 /* This function runs once at startup. */
-int SDL_AppInit(void **appstate, int argc, char *argv[])
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
 {
     SDL_AudioSpec spec;
 
@@ -83,7 +83,7 @@ int SDL_AppInit(void **appstate, int argc, char *argv[])
 }
 
 /* This function runs when a new event (mouse input, keypresses, etc) occurs. */
-int SDL_AppEvent(void *appstate, const SDL_Event *event)
+SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
 {
     if (event->type == SDL_EVENT_QUIT) {
         return SDL_APP_SUCCESS;  /* end the program, reporting success to the OS. */
@@ -92,7 +92,7 @@ int SDL_AppEvent(void *appstate, const SDL_Event *event)
 }
 
 /* This function runs once per frame, and is the heart of the program. */
-int SDL_AppIterate(void *appstate)
+SDL_AppResult SDL_AppIterate(void *appstate)
 {
     /* we're not doing anything with the renderer, so just blank it out. */
     SDL_RenderClear(renderer);
diff --git a/examples/audio/03-load-wav/load-wav.c b/examples/audio/03-load-wav/load-wav.c
index 6467ce7e4aa30..44f0c1e14501f 100644
--- a/examples/audio/03-load-wav/load-wav.c
+++ b/examples/audio/03-load-wav/load-wav.c
@@ -26,7 +26,7 @@ static Uint8 *wav_data = NULL;
 static Uint32 wav_data_len = 0;
 
 /* This function runs once at startup. */
-int SDL_AppInit(void **appstate, int argc, char *argv[])
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
 {
     SDL_AudioSpec spec;
     char *wav_path = NULL;
@@ -65,7 +65,7 @@ int SDL_AppInit(void **appstate, int argc, char *argv[])
 }
 
 /* This function runs when a new event (mouse input, keypresses, etc) occurs. */
-int SDL_AppEvent(void *appstate, const SDL_Event *event)
+SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
 {
     if (event->type == SDL_EVENT_QUIT) {
         return SDL_APP_SUCCESS;  /* end the program, reporting success to the OS. */
@@ -74,7 +74,7 @@ int SDL_AppEvent(void *appstate, const SDL_Event *event)
 }
 
 /* This function runs once per frame, and is the heart of the program. */
-int SDL_AppIterate(void *appstate)
+SDL_AppResult SDL_AppIterate(void *appstate)
 {
     /* see if we need to feed the audio stream more data yet.
        We're being lazy here, but if there's less than the entire wav file left to play,
diff --git a/examples/game/01-snake/main.c b/examples/game/01-snake/main.c
index d09f008cb2ec9..8eda24e82963c 100644
--- a/examples/game/01-snake/main.c
+++ b/examples/game/01-snake/main.c
@@ -76,7 +76,7 @@ static void set_rect_xy_(SDL_FRect *r, short x, short y)
     r->y = (float)(y * SNAKE_BLOCK_SIZE_IN_PIXELS);
 }
 
-int SDL_AppIterate(void *appstate)
+SDL_AppResult SDL_AppIterate(void *appstate)
 {
     AppState *as;
     SnakeContext *ctx;
@@ -109,7 +109,7 @@ int SDL_AppIterate(void *appstate)
     return SDL_APP_CONTINUE;
 }
 
-int SDL_AppInit(void **appstate, int argc, char *argv[])
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
 {
     (void)argc;
     (void)argv;
@@ -134,7 +134,7 @@ int SDL_AppInit(void **appstate, int argc, char *argv[])
     return SDL_APP_CONTINUE;
 }
 
-int SDL_AppEvent(void *appstate, const SDL_Event *event)
+SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
 {
     SnakeContext *ctx = &((AppState *)appstate)->snake_ctx;
     switch (event->type) {
diff --git a/examples/pen/01-drawing-lines/drawing-lines.c b/examples/pen/01-drawing-lines/drawing-lines.c
index ef9aa6e6b267d..a8d82ae887013 100644
--- a/examples/pen/01-drawing-lines/drawing-lines.c
+++ b/examples/pen/01-drawing-lines/drawing-lines.c
@@ -21,7 +21,7 @@ static float previous_touch_x = -1.0f;
 static float previous_touch_y = -1.0f;
 
 /* This function runs once at startup. */
-int SDL_AppInit(void **appstate, int argc, char *argv[])
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
 {
     if (SDL_Init(SDL_INIT_VIDEO) == -1) {
         SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL);
@@ -52,7 +52,7 @@ int SDL_AppInit(void **appstate, int argc, char *argv[])
 }
 
 /* This function runs when a new event (mouse input, keypresses, etc) occurs. */
-int SDL_AppEvent(void *appstate, const SDL_Event *event)
+SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
 {
     if (event->type == SDL_EVENT_QUIT) {
         return SDL_APP_SUCCESS;  /* end the program, reporting success to the OS. */
@@ -84,7 +84,7 @@ int SDL_AppEvent(void *appstate, const SDL_Event *event)
 }
 
 /* This function runs once per frame, and is the heart of the program. */
-int SDL_AppIterate(void *appstate)
+SDL_AppResult SDL_AppIterate(void *appstate)
 {
     /* make sure we're drawing to the window and not the render target */
     SDL_SetRenderTarget(renderer, NULL);
diff --git a/examples/renderer/01-clear/renderer-clear.c b/examples/renderer/01-clear/renderer-clear.c
index acbbcd0addc0e..c5da1335d156d 100644
--- a/examples/renderer/01-clear/renderer-clear.c
+++ b/examples/renderer/01-clear/renderer-clear.c
@@ -23,7 +23,7 @@ static int fade_direction = 1;
 
 
 /* This function runs once at startup. */
-int SDL_AppInit(void **appstate, int argc, char *argv[])
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
 {
     if (SDL_Init(SDL_INIT_VIDEO) == -1) {
         SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL);
@@ -39,7 +39,7 @@ int SDL_AppInit(void **appstate, int argc, char *argv[])
 }
 
 /* This function runs when a new event (mouse input, keypresses, etc) occurs. */
-int SDL_AppEvent(void *appstate, const SDL_Event *event)
+SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
 {
     if (event->type == SDL_EVENT_QUIT) {
         return SDL_APP_SUCCESS;  /* end the program, reporting success to the OS. */
@@ -48,7 +48,7 @@ int SDL_AppEvent(void *appstate, const SDL_Event *event)
 }
 
 /* This function runs once per frame, and is the heart of the program. */
-int SDL_AppIterate(void *appstate)
+SDL_AppResult SDL_AppIterate(void *appstate)
 {
     /* since we're always fading red, we leave green and blue at zero.
        alpha doesn't mean much here, so leave it at full (255, no transparency). */
diff --git a/examples/renderer/02-primitives/renderer-primitives.c b/examples/renderer/02-primitives/renderer-primitives.c
index e2021e885492a..76cb8e7bc046b 100644
--- a/examples/renderer/02-primitives/renderer-primitives.c
+++ b/examples/renderer/02-primitives/renderer-primitives.c
@@ -15,7 +15,7 @@ static SDL_Renderer *renderer = NULL;
 static SDL_FPoint points[500];
 
 /* This function runs once at startup. */
-int SDL_AppInit(void **appstate, int argc, char *argv[])
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
 {
     int i;
 
@@ -39,7 +39,7 @@ int SDL_AppInit(void **appstate, int argc, char *argv[])
 }
 
 /* This function runs when a new event (mouse input, keypresses, etc) occurs. */
-int SDL_AppEvent(void *appstate, const SDL_Event *event)
+SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
 {
     if (event->type == SDL_EVENT_QUIT) {
         return SDL_APP_SUCCESS;  /* end the program, reporting success to the OS. */
@@ -48,7 +48,7 @@ int SDL_AppEvent(void *appstate, const SDL_Event *event)
 }
 
 /* This function runs once per frame, and is the heart of the program. */
-int SDL_AppIterate(void *appstate)
+SDL_AppResult SDL_AppIterate(void *appstate)
 {
     SDL_FRect rect;
 
diff --git a/examples/template.c b/examples/template.c
index 8c93bed6b0ce7..48c23b037da97 100644
--- a/examples/template.c
+++ b/examples/template.c
@@ -14,7 +14,7 @@ static SDL_Renderer *renderer = NULL;
 
 
 /* This function runs once at startup. */
-int SDL_AppInit(void **appstate, int argc, char *argv[])
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
 {
     if (SDL_Init(SDL_INIT_VIDEO) == -1) {
         SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't initialize SDL!", SDL_GetError(), NULL);
@@ -29,7 +29,7 @@ int SDL_AppInit(void **appstate, int argc, char *argv[])
 }
 
 /* This function runs when a new event (mouse input, keypresses, etc) occurs. */
-int SDL_AppEvent(void *appstate, const SDL_Event *event)
+SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
 {
     if (event->type == SDL_EVENT_QUIT) {
         return SDL_APP_SUCCESS;  /* end the program, reporting success to the OS. */
@@ -38,7 +38,7 @@ int SDL_AppEvent(void *appstate, const SDL_Event *event)
 }
 
 /* This function runs once per frame, and is the heart of the program. */
-int SDL_AppIterate(void *appstate)
+SDL_AppResult SDL_AppIterate(void *appstate)
 {
     return SDL_APP_CONTINUE;  /* carry on with the program! */
 }
diff --git a/include/SDL3/SDL_init.h b/include/SDL3/SDL_init.h
index 6b5181600bd2b..26f6ad6cccca8 100644
--- a/include/SDL3/SDL_init.h
+++ b/include/SDL3/SDL_init.h
@@ -66,6 +66,25 @@ typedef Uint32 SDL_InitFlags;
 #define SDL_INIT_SENSOR     0x00008000u /**< `SDL_INIT_SENSOR` implies `SDL_INIT_EVENTS` */
 #define SDL_INIT_CAMERA     0x00010000u /**< `SDL_INIT_CAMERA` implies `SDL_INIT_EVENTS` */
 
+/**
+ * Return values for optional main callbacks.
+ *
+ * See https://wiki.libsdl.org/SDL3/README/main-functions#main-callbacks-in-sdl3 for details.
+ *
+ * \since This enum is available since SDL 3.0.0.
+ */
+typedef enum SDL_AppResult
+{
+    SDL_APP_CONTINUE,   /** Value that requests that the app continue from the main callbacks. If SDL_AppInit, SDL_AppEvent, or SDL_AppIterate returns this value, the program will continue to run. */
+    SDL_APP_SUCCESS,    /** Value that requests termination with success from the main callbacks. If SDL_AppInit, SDL_AppEvent, or SDL_AppIterate returns this value, the program will terminate and report success to the operating system. What that success looks like is platform-dependent. On Unix, for example, the process error code will be zero. */
+    SDL_APP_FAILURE     /** Value that requests termination with error from the main callbacks. If SDL_AppInit, SDL_AppEvent, or SDL_AppIterate returns this value, the program will terminate and report failure to the operating system. What that failure looks like is platform-dependent. On Unix, for example, the process error code will be non-zero. */
+} SDL_AppResult;
+
+typedef SDL_AppResult (SDLCALL *SDL_AppInit_func)(void **appstate, int argc, char *argv[]);
+typedef SDL_AppResult (SDLCALL *SDL_AppIterate_func)(void *appstate);
+typedef SDL_AppResult (SDLCALL *SDL_AppEvent_func)(void *appstate, const SDL_Event *event);
+typedef void (SDLCALL *SDL_AppQuit_func)(void *appstate);
+
 /**
  * Initialize the SDL library.
  *
diff --git a/include/SDL3/SDL_main.h b/include/SDL3/SDL_main.h
index 0985629a9faf9..b3cb8e2cd79ec 100644
--- a/include/SDL3/SDL_main.h
+++ b/include/SDL3/SDL_main.h
@@ -188,16 +188,12 @@
 #define main SDL_main
 #endif
 
+#include <SDL3/SDL_init.h>
 #include <SDL3/SDL_begin_code.h>
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-typedef int (SDLCALL *SDL_AppInit_func)(void **appstate, int argc, char *argv[]);
-typedef int (SDLCALL *SDL_AppIterate_func)(void *appstate);
-typedef int (SDLCALL *SDL_AppEvent_func)(void *appstate, const SDL_Event *event);
-typedef void (SDLCALL *SDL_AppQuit_func)(void *appstate);
-
 /*
  * You can (optionally!) define SDL_MAIN_USE_CALLBACKS before including
  * SDL_main.h, and then your application will _not_ have a standard
@@ -224,49 +220,6 @@ typedef void (SDLCALL *SDL_AppQuit_func)(void *appstate);
  */
 #ifdef SDL_MAIN_USE_CALLBACKS
 
-/**
- * Value that requests that the app continue from the main callbacks.
- *
- * If SDL_AppInit, SDL_AppEvent, or SDL_AppIterate returns this value, the
- * program will continue to run. This is the normal return value case.
- *
- * This is always 0; using this macro may be clearer, but is not required.
- *
- * \since This macro is available since SDL 3.0.0.
- */
-#define SDL_APP_CONTINUE 0
-
-/**
- * Value that requests termination with error from the main callbacks.
- *
- * If SDL_AppInit, SDL_AppEvent, or SDL_AppIterate returns this value, the
- * program will terminate and report failure to the operating system.
- *
- * What that failure looks like is platform-dependent. On Unix, for example,
- * the process error code will be non-zero.
- *
- * This is always -1; using this macro may be clearer, but is not required.
- *
- * \since This macro is available since SDL 3.0.0.
- */
-#define SDL_APP_FAILURE -1
-
-/**
- * Value that requests termination with success from the main callbacks.
- *
- * If SDL_AppInit, SDL_AppEvent, or SDL_AppIterate returns this value, the
- * program will terminate and report success to the operating system.
- *
- * What that success looks like is platform-dependent. On Unix, for example,
- * the process error code will be zero.
- *
- * This is always 1; using this macro may be clearer, but is not required.
- *
- * \since This macro is available since SDL 3.0.0.
- */
-#define SDL_APP_SUCCESS 1
-
-
 /**
  * App-implemented initial entry point for SDL_MAIN_USE_CALLBACKS apps.
  *
@@ -311,7 +264,7 @@ typedef void (SDLCALL *SDL_AppQuit_func)(void *appstate);
  * \sa SDL_AppEvent
  * \sa SDL_AppQuit
  */
-extern SDLMAIN_DECLSPEC int SDLCALL SDL_AppInit(void **appstate, int argc, char *argv[]);
+extern SDLMAIN_DECLSPEC SDL_AppResult SDLCALL SDL_AppInit(void **appstate, int argc, char *argv[]);
 
 /**
  * App-implemented iteration entry point for SDL_MAIN_USE_CALLBACKS apps.
@@ -359,7 +312,7 @@ extern SDLMAIN_DECLSPEC int SDLCALL SDL_AppInit(void **appstate, int argc, char
  * \sa SDL_AppInit
  * \sa SDL_AppEvent
  */
-extern SDLMAIN_DECLSPEC int SDLCALL SDL_AppIterate(void *appstate);
+extern SDLMAIN_DECLSPEC SDL_AppResult SDLCALL SDL_AppIterate(void *appstate);
 
 /**
  * App-implemented event entry point for SDL_MAIN_USE_CALLBACKS apps.
@@ -406,7 +359,7 @@ extern SDLMAIN_DECLSPEC int SDLCALL SDL_AppIterate(void *appstate);
  * \sa SDL_AppInit
  * \sa SDL_AppIterate
  */
-extern SDLMAIN_DECLSPEC int SDLCALL SDL_AppEvent(void *appstate, const SDL_Event *event);
+extern SDLMAIN_DECLSPEC SDL_AppResult SDLCALL SDL_AppEvent(void *appstate, const SDL_Event *event);
 
 /**
  * App-implemented deinit entry point for SDL_MAIN_USE_CALLBACKS apps.
diff --git a/include/SDL3/SDL_test_common.h b/include/SDL3/SDL_test_common.h
index a162a3de5573d..dcc0c7bc77438 100644
--- a/include/SDL3/SDL_test_common.h
+++ b/include/SDL3/SDL_test_common.h
@@ -234,7 +234,7 @@ void SDLTest_CommonEvent(SDLTest_CommonState *state, SDL_Event *event, int *done
  * \param event The event to handle.
  * \returns Value suitable for returning from SDL_AppEvent().
  */
-int SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const SDL_Event *event);
+SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const SDL_Event *event);
 
 /**
  * Close test window.
diff --git a/src/main/SDL_main_callbacks.c b/src/main/SDL_main_callbacks.c
index c247632fc5583..a92c70f57cc78 100644
--- a/src/main/SDL_main_callbacks.c
+++ b/src/main/SDL_main_callbacks.c
@@ -46,8 +46,8 @@ static SDL_bool ShouldDispatchImmediately(SDL_Event *event)
 
 static void SDL_DispatchMainCallbackEvent(SDL_Event *event)
 {
-    if (SDL_AtomicGet(&apprc) == 0) { // if already quitting, don't send the event to the app.
-        SDL_AtomicCompareAndSwap(&apprc, 0, SDL_main_event_callback(SDL_main_appstate, event));
+    if (SDL_AtomicGet(&apprc) == SDL_APP_CONTINUE) { // if already quitting, don't send the event to the app.
+        SDL_AtomicCompareAndSwap(&apprc, SDL_APP_CONTINUE, SDL_main_event_callback(SDL_main_appstate, event));
     }
 }
 
@@ -89,23 +89,23 @@ SDL_bool SDL_HasMainCallbacks(void)
     return SDL_FALSE;
 }
 
-int SDL_InitMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)
+SDL_AppResult SDL_InitMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)
 {
     SDL_main_iteration_callback = appiter;
     SDL_main_event_callback = appevent;
     SDL_main_quit_callback = appquit;
-    SDL_AtomicSet(&apprc, 0);
+    SDL_AtomicSet(&apprc, SDL_APP_CONTINUE);
 
-    const int rc = appinit(&SDL_main_appstate, argc, argv);
-    if (SDL_AtomicCompareAndSwap(&apprc, 0, rc) && (rc == 0)) {  // bounce if SDL_AppInit already said abort, otherwise...
+    const SDL_AppResult rc = appinit(&SDL_main_appstate, argc, argv);
+    if (SDL_AtomicCompareAndSwap(&apprc, SDL_APP_CONTINUE, rc) && (rc == SDL_APP_CONTINUE)) { // bounce if SDL_AppInit already said abort, otherwise...
         // make sure we definitely have events initialized, even if the app didn't do it.
         if (SDL_InitSubSystem(SDL_INIT_EVENTS) == -1) {
-            SDL_AtomicSet(&apprc, -1);
+            SDL_AtomicSet(&apprc, SDL_APP_FAILURE);
             return -1;
         }
 
         if (SDL_AddEventWatch(SDL_MainCallbackEventWatcher, NULL) < 0) {
-            SDL_AtomicSet(&apprc, -1);
+            SDL_AtomicSet(&apprc, SDL_APP_FAILURE);
             return -1;
         }
     }
@@ -113,17 +113,17 @@ int SDL_InitMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit, SDL_
     return SDL_AtomicGet(&apprc);
 }
 
-int SDL_IterateMainCallbacks(SDL_bool pump_events)
+SDL_AppResult SDL_IterateMainCallbacks(SDL_bool pump_events)
 {
     if (pump_events) {
         SDL_PumpEvents();
     }
     SDL_DispatchMainCallbackEvents();
 
-    int rc = SDL_AtomicGet(&apprc);
-    if (rc == 0) {
+    SDL_AppResult rc = SDL_AtomicGet(&apprc);
+    if (rc == SDL_APP_CONTINUE) {
         rc = SDL_main_iteration_callback(SDL_main_appstate);
-        if (!SDL_AtomicCompareAndSwap(&apprc, 0, rc)) {
+        if (!SDL_AtomicCompareAndSwap(&apprc, SDL_APP_CONTINUE, rc)) {
             rc = SDL_AtomicGet(&apprc); // something else already set a quit result, keep that.
         }
     }
diff --git a/src/main/SDL_main_callbacks.h b/src/main/SDL_main_callbacks.h
index 54cda2fca275c..c27925b2ea22b 100644
--- a/src/main/SDL_main_callbacks.h
+++ b/src/main/SDL_main_callbacks.h
@@ -23,8 +23,8 @@
 #define SDL_main_callbacks_h_
 
 SDL_bool SDL_HasMainCallbacks(void);
-int SDL_InitMainCallbacks(int argc, char *argv[], SDL_AppInit_func appinit, SDL_AppIterate_func _appiter, SDL_AppEvent_func _appevent, SDL_AppQuit_func _appquit);
-int SDL_IterateMainCallbacks(SDL_bool pump_events);
+SDL_AppResult SDL_InitMainCallbacks(int argc, char *argv[], SDL_AppInit_func appinit, SDL_AppIterate_func _appiter, SDL_AppEvent_func _appevent, SDL_AppQuit_func _appquit);
+SDL_AppResult SDL_IterateMainCallbacks(SDL_bool pump_events);
 void SDL_QuitMainCallbacks(void);
 
 #endif // SDL_main_callbacks_h_
diff --git a/src/main/emscripten/SDL_sysmain_callbacks.c b/src/main/emscripten/SDL_sysmain_callbacks.c
index cb9fbb4cefaff..29901044c5f93 100644
--- a/src/main/emscripten/SDL_sysmain_callbacks.c
+++ b/src/main/emscripten/SDL_sysmain_callbacks.c
@@ -26,22 +26,22 @@
 
 static void EmscriptenInternalMainloop(void)
 {
-    const int rc = SDL_IterateMainCallbacks(SDL_TRUE);
-    if (rc != 0) {
+    const SDL_AppResult rc = SDL_IterateMainCallbacks(SDL_TRUE);
+    if (rc != SDL_APP_CONTINUE) {
         SDL_QuitMainCallbacks();
         emscripten_cancel_main_loop();  // kill" the mainloop, so it stops calling back into it.
-        exit((rc < 0) ? 1 : 0);  // hopefully this takes down everything else, too.
+        exit((rc == SDL_APP_FAILURE) ? 1 : 0);  // hopefully this takes down everything else, too.
     }
 }
 
 int SDL_EnterAppMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)
 {
-    const int rc = SDL_InitMainCallbacks(argc, argv, appinit, appiter, appevent, appquit);
-    if (rc == 0) {
+    const SDL_AppResult rc = SDL_InitMainCallbacks(argc, argv, appinit, appiter, appevent, appquit);
+    if (rc == SDL_APP_CONTINUE) {
         emscripten_set_main_loop(EmscriptenInternalMainloop, 0, 0);  // run at refresh rate, don't throw an exception since we do an orderly return.
     } else {
         SDL_QuitMainCallbacks();
     }
-    return (rc < 0) ? 1 : 0;
+    return (rc == SDL_APP_FAILURE) ? 1 : 0;
 }
 
diff --git a/src/main/generic/SDL_sysmain_callbacks.c b/src/main/generic/SDL_sysmain_callbacks.c
index 59bfbad9b47f8..36f943b6aa258 100644
--- a/src/main/generic/SDL_sysmain_callbacks.c
+++ b/src/main/generic/SDL_sysmain_callbacks.c
@@ -39,13 +39,13 @@ static void SDLCALL MainCallbackRateHintChanged(void *userdata, const char *name
 
 int SDL_EnterAppMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)
 {
-    int rc = SDL_InitMainCallbacks(argc, argv, appinit, appiter, appevent, appquit);
+    SDL_AppResult rc = SDL_InitMainCallbacks(argc, argv, appinit, appiter, appevent, appquit);
     if (rc == 0) {
         SDL_AddHintCallback(SDL_HINT_MAIN_CALLBACK_RATE, MainCallbackRateHintChanged, NULL);
 
         Uint64 next_iteration = callback_rate_increment ? (SDL_GetTicksNS() + callback_rate_increment) : 0;
 
-        while ((rc = SDL_IterateMainCallbacks(SDL_TRUE)) == 0) {
+        while ((rc = SDL_IterateMainCallbacks(SDL_TRUE)) == SDL_APP_CONTINUE) {
             // !!! FIXME: this can be made more complicated if we decide to
             // !!! FIXME: optionally hand off callback responsibility to the
             // !!! FIXME: video subsystem (for example, if Wayland has a
@@ -77,7 +77,7 @@ int SDL_EnterAppMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit,
     }
     SDL_QuitMainCallbacks();
 
-    return (rc < 0) ? 1 : 0;
+    return (rc == SDL_APP_FAILURE) ? 1 : 0;
 }
 
 #endif // !SDL_PLATFORM_IOS
diff --git a/src/main/ios/SDL_sysmain_callbacks.m b/src/main/ios/SDL_sysmain_callbacks.m
index 439db7a2eacdf..6afae4d9081a4 100644
--- a/src/main/ios/SDL_sysmain_callbacks.m
+++ b/src/main/ios/SDL_sysmain_callbacks.m
@@ -50,14 +50,14 @@ - (instancetype)init:(SDL_AppIterate_func)_appiter quitfunc:(SDL_AppQuit_func)_a
 
 - (void)appIteration:(CADisplayLink *)sender
 {
-    const int rc = SDL_IterateMainCallbacks(SDL_TRUE);
-    if (rc != 0) {
+    const SDL_AppResult rc = SDL_IterateMainCallbacks(SDL_TRUE);
+    if (rc != SDL_APP_CONTINUE) {
         [self.displayLink invalidate];
         self.displayLink = nil;
         globalDisplayLink = nil;
         SDL_QuitMainCallbacks();
         SDL_UpdateLifecycleObserver();
-        exit((rc < 0) ? 1 : 0);
+        exit((rc == SDL_APP_FAILURE) ? 1 : 0);
     }
 }
 @end
@@ -66,8 +66,8 @@ - (void)appIteration:(CADisplayLink *)sender
 // When we return from here, we're living in the RunLoop, and a CADisplayLink is firing regularly for us.
 int SDL_EnterAppMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)
 {
-    const int rc = SDL_InitMainCallbacks(argc, argv, appinit, appiter, appevent, appquit);
-    if (rc == 0) {
+    const SDL_AppResult rc = SDL_InitMainCallbacks(argc, argv, appinit, appiter, appevent, appquit);
+    if (rc == SDL_APP_CONTINUE) {
         globalDisplayLink = [[SDLIosMainCallbacksDisplayLink alloc] init:appiter quitfunc:appquit];
         if (globalDisplayLink != nil) {
             return 0;  // this will fall all the way out of SDL_main, where UIApplicationMain will keep running the RunLoop.
@@ -76,7 +76,7 @@ int SDL_EnterAppMainCallbacks(int argc, char* argv[], SDL_AppInit_func appinit,
 
     // appinit requested quit, just bounce out now.
     SDL_QuitMainCallbacks();
-    exit((rc < 0) ? 1 : 0);
+    exit((rc == SDL_APP_FAILURE) ? 1 : 0);
 
     return 1;  // just in case.
 }
diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c
index a2efb9f7a7551..ae282c21431fb 100644
--- a/src/test/SDL_test_common.c
+++ b/src/test/SDL_test_common.c
@@ -2090,7 +2090,7 @@ static void FullscreenTo(SDLTest_CommonState *state, int index, int windowId)
     SDL_free(displays);
 }
 
-int SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const SDL_Event *event)
+SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const SDL_Event *event)
 {
     int i;
 
@@ -2487,7 +2487,7 @@ int SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const SDL_Event
 
 void SDLTest_CommonEvent(SDLTest_CommonState *state, SDL_Event *event, int *done)
 {
-    if (SDLTest_CommonEventMainCallbacks(state, event)) {
+    if (SDLTest_CommonEventMainCallbacks(state, event) != SDL_APP_CONTINUE) {
         *done = 1;
     }
 }
diff --git a/test/loopwave.c b/test/loopwave.c
index 06bb16800b174..f4c8d41ec9321 100644
--- a/test/loopwave.c
+++ b/test/loopwave.c
@@ -42,7 +42,7 @@ static int fillerup(void)
     return SDL_APP_CONTINUE;
 }
 
-int SDL_AppInit(void **appstate, int argc, char *argv[])
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
 {
     int i;
     char *filename = NULL;
@@ -120,12 +120,12 @@ int SDL_AppInit(void **appstate, int argc, char *argv[])
     return SDL_APP_CONTINUE;
 }
 
-int SDL_AppEvent(void *appstate, const SDL_Event *event)
+SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
 {
     return (event->type == SDL_EVENT_QUIT) ? SDL_APP_SUCCESS : SDL_APP_CONTINUE;
 }
 
-int SDL_AppIterate(void *appstate)
+SDL_AppResult SDL_AppIterate(void *appstate)
 {
     return fillerup();
 }
diff --git a/test/testaudio.c b/test/testaudio.c
index a52bc1f16e557..eab00a281bdeb 100644
--- a/test/testaudio.c
+++ b/test/testaudio.c
@@ -1073,7 +1073,7 @@ static void WindowResized(const int newwinw, const int newwinh)
     state->window_h = newwinh;
 }
 
-int SDL_AppInit(void **appstate, int argc, char *argv[])
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
 {
     int i;
 
@@ -1131,7 +1131,7 @@ int SDL_AppInit(void **appstate, int argc, char *argv[])
 
 static SDL_bool saw_event = SDL_FALSE;
 
-int SDL_AppEvent(void *appstate, const SDL_Event *event)
+SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
 {
     Thing *thing = NULL;
 
@@ -1254,7 +1254,7 @@ int SDL_AppEvent(void *appstate, const SDL_Event *event)
     return SDLTest_CommonEventMainCallbacks(state, event);
 }
 
-int SDL_AppIterate(void *appstate)
+SDL_AppResult SDL_AppIterate(void *appstate)
 {
     if (app_ready_ticks == 0) {
         app_ready_ticks = SDL_GetTicks();
diff --git a/test/testaudiorecording.c b/test/testaudiorecording.c
index cd0dbb63aab56..8d1fe43428d94 100644
--- a/test/testaudiorecording.c
+++ b/test/testaudiorecording.c
@@ -21,7 +21,7 @@ static SDL_AudioStream *stream_in = NULL;
 static SDL_AudioStream *stream_out = NULL;
 static SDLTest_CommonState *state = NULL;
 
-int SDL_AppInit(void **appstate, int argc, char **argv)
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv)
 {
     SDL_AudioDeviceID *devices;
     SDL_AudioSpec outspec;
@@ -149,7 +149,7 @@ int SDL_AppInit(void **appstate, int argc, char **argv)
     return SDL_APP_CONTINUE;
 }
 
-int SDL_AppEvent(void *appstate, const SDL_Event *event)
+SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
 {
     if (event->type == SDL_EVENT_QUIT) {
         return SDL_APP_SUCCESS;
@@ -173,7 +173,7 @@ int SDL_AppEvent(void *appstate, const SDL_Event *event)
     return SDL_APP_CONTINUE;
 }
 
-int SDL_AppIterate(void *appstate)
+SDL_AppResult SDL_AppIterate(void *appstate)
 {
     if (!SDL_AudioDevicePaused(SDL_GetAudioStreamDevice(stream_in))) {
         SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
diff --git a/test/testcamera.c b/test/testcamera.c
index d6f0c6314eab2..21641a1f021e3 100644
--- a/test/testcamera.c
+++ b/test/testcamera.c
@@ -46,7 +46,7 @@ static void PrintCameraSpecs(SDL_CameraID camera_id)
     }
 }
 
-int SDL_AppInit(void **appstate, int argc, char *argv[])
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
 {
     char window_title[128];
     int devcount = 0;
@@ -216,7 +216,7 @@ static int FlipCamera(void)
     return SDL_APP_CONTINUE;
 }
 
-int SDL_AppEvent(void *appstate, const SDL_Event *event)
+SDL_AppResult SDL_AppEvent(void *a

(Patch may be truncated, please check the link at the top of this post.)