From 3a1cfbc147e3c0e0c9253638e45f399faea15cf1 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Fri, 19 Jun 2026 14:14:13 -0400
Subject: [PATCH] main: If SDL_MAIN_CALLBACK_RATE="waitevent", have at least
one iteration run.
This way apps can at least draw an initial image to their windows before going
into a deep, blocking wait for user interaction.
Fixes #15027.
---
include/SDL3/SDL_hints.h | 6 +++++-
src/main/emscripten/SDL_sysmain_callbacks.c | 8 ++++++--
src/main/generic/SDL_sysmain_callbacks.c | 18 ++++++++++++++++--
3 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h
index a8751ede4716b..bc23b58add113 100644
--- a/include/SDL3/SDL_hints.h
+++ b/include/SDL3/SDL_hints.h
@@ -2835,7 +2835,11 @@ extern "C" {
* There are other strings that have special meaning. If set to "waitevent",
* SDL_AppIterate will not be called until new event(s) have arrived (and been
* processed by SDL_AppEvent). This can be useful for apps that are completely
- * idle except in response to input.
+ * idle except in response to input. As of SDL 3.6.0, SDL will allow a single
+ * call to SDL_AppIterate to proceed without an event immediately after this
+ * hint is set to "waitevent", so apps can have a minimum of activity, perhaps
+ * to render an initial image to a window before the user has otherwise
+ * interacted with the app.
*
* On some platforms, or if you are using SDL_main instead of SDL_AppIterate,
* this hint is ignored. When the hint can be used, it is allowed to be
diff --git a/src/main/emscripten/SDL_sysmain_callbacks.c b/src/main/emscripten/SDL_sysmain_callbacks.c
index fca3488640c63..138c6ed6d1f84 100644
--- a/src/main/emscripten/SDL_sysmain_callbacks.c
+++ b/src/main/emscripten/SDL_sysmain_callbacks.c
@@ -58,6 +58,8 @@ static bool SDLCALL EmscriptenMainCallbackEventWatcher(void *userdata, SDL_Event
static void EmscriptenInternalMainloop(void)
{
+ const bool force_iterate = callback_rate_changed && iterate_after_waitevent;
+
// callback rate changed? Update emscripten's mainloop iteration speed.
if (callback_rate_changed) {
callback_rate_changed = false;
@@ -70,7 +72,7 @@ static void EmscriptenInternalMainloop(void)
if (iterate_after_waitevent) {
SDL_PumpEvents();
- if (!saw_new_event) {
+ if (!saw_new_event && !force_iterate) {
// do nothing yet. Note that we're still going to iterate here because we can't block,
// but we can stop the app's iteration from progressing until there's an event.
return;
@@ -94,7 +96,9 @@ int SDL_EnterAppMainCallbacks(int argc, char *argv[], SDL_AppInit_func appinit,
rc = SDL_APP_FAILURE;
} else {
SDL_AddHintCallback(SDL_HINT_MAIN_CALLBACK_RATE, MainCallbackRateHintChanged, NULL);
- callback_rate_changed = false;
+ if (!iterate_after_waitevent) { // if we're doing waitevent, we need callback_rate_changed to stay true for the next iteration.
+ callback_rate_changed = false;
+ }
emscripten_set_main_loop(EmscriptenInternalMainloop, 0, 0); // don't throw an exception since we do an orderly return.
if (callback_rate_increment > 0.0) {
emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, callback_rate_increment);
diff --git a/src/main/generic/SDL_sysmain_callbacks.c b/src/main/generic/SDL_sysmain_callbacks.c
index 77aa2f54de9ce..425e79077caef 100644
--- a/src/main/generic/SDL_sysmain_callbacks.c
+++ b/src/main/generic/SDL_sysmain_callbacks.c
@@ -27,9 +27,11 @@
static Uint64 callback_rate_increment = 0;
static bool iterate_after_waitevent = false;
+static bool callback_rate_changed = false;
static void SDLCALL MainCallbackRateHintChanged(void *userdata, const char *name, const char *oldValue, const char *newValue)
{
+ callback_rate_changed = true;
iterate_after_waitevent = newValue && (SDL_strcmp(newValue, "waitevent") == 0);
if (iterate_after_waitevent) {
callback_rate_increment = 0;
@@ -45,10 +47,22 @@ static void SDLCALL MainCallbackRateHintChanged(void *userdata, const char *name
static SDL_AppResult GenericIterateMainCallbacks(void)
{
- if (iterate_after_waitevent) {
+ bool should_wait = iterate_after_waitevent;
+
+ if (callback_rate_changed) {
+ callback_rate_changed = false;
+ if (iterate_after_waitevent) {
+ // just go immediately for one iteration (it will do a PumpEvents),
+ // and do a full blocking wait for more events next time.
+ should_wait = false;
+ }
+ }
+
+ if (should_wait) {
SDL_WaitEvent(NULL);
}
- return SDL_IterateMainCallbacks(!iterate_after_waitevent);
+
+ return SDL_IterateMainCallbacks(!should_wait);
}
int SDL_EnterAppMainCallbacks(int argc, char *argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit)