From d950b9e2d9c756c7fc5641d75d9f7dd1a19ceac8 Mon Sep 17 00:00:00 2001
From: Charlie Birks <[EMAIL REDACTED]>
Date: Sun, 7 Nov 2021 20:40:54 +0000
Subject: [PATCH] emscripten: Make timers work (if used with
emscripten_set_main_loop)
Co-authored-by: aidanhs <aidanhs@cantab.net>
---
src/timer/SDL_timer.c | 112 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 112 insertions(+)
diff --git a/src/timer/SDL_timer.c b/src/timer/SDL_timer.c
index 559fdf5b2d..7ed1720455 100644
--- a/src/timer/SDL_timer.c
+++ b/src/timer/SDL_timer.c
@@ -28,6 +28,8 @@
/* #define DEBUG_TIMERS */
+#if !defined(__EMSCRIPTEN__) || !SDL_THREADS_DISABLED
+
typedef struct _SDL_Timer
{
int timerID;
@@ -370,6 +372,116 @@ SDL_RemoveTimer(SDL_TimerID id)
return canceled;
}
+#else
+
+#include <emscripten/emscripten.h>
+
+typedef struct _SDL_TimerMap
+{
+ int timerID;
+ int timeoutID;
+ struct _SDL_TimerMap *next;
+} SDL_TimerMap;
+
+typedef struct {
+ int nextID;
+ SDL_TimerMap *timermap;
+} SDL_TimerData;
+
+static SDL_TimerData SDL_timer_data;
+
+static void
+SDL_Emscripten_TimerHelper(SDL_TimerMap *entry, Uint32 interval, SDL_TimerCallback callback, void *param)
+{
+ Uint32 new_timeout;
+
+ new_timeout = callback(interval, param);
+
+ if (new_timeout != 0) {
+ entry->timeoutID = EM_ASM_INT({
+ return Browser.safeSetTimeout(function() {
+ dynCall('viiii', $0, [$1, $2, $3, $4]);
+ }, $2);
+ }, &SDL_Emscripten_TimerHelper, entry, interval, callback, param);
+ }
+}
+
+int
+SDL_TimerInit(void)
+{
+ return 0;
+}
+
+void
+SDL_TimerQuit(void)
+{
+ SDL_TimerData *data = &SDL_timer_data;
+ SDL_TimerMap *entry;
+
+ while (data->timermap) {
+ entry = data->timermap;
+ data->timermap = entry->next;
+ SDL_free(entry);
+ }
+}
+
+SDL_TimerID
+SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param)
+{
+ SDL_TimerData *data = &SDL_timer_data;
+ SDL_TimerMap *entry;
+
+ entry = (SDL_TimerMap *)SDL_malloc(sizeof(*entry));
+ if (!entry) {
+ SDL_OutOfMemory();
+ return 0;
+ }
+ entry->timerID = ++data->nextID;
+
+ entry->timeoutID = EM_ASM_INT({
+ return Browser.safeSetTimeout(function() {
+ dynCall('viiii', $0, [$1, $2, $3, $4]);
+ }, $2);
+ }, &SDL_Emscripten_TimerHelper, entry, interval, callback, param);
+
+ entry->next = data->timermap;
+ data->timermap = entry;
+
+ return entry->timerID;
+}
+
+SDL_bool
+SDL_RemoveTimer(SDL_TimerID id)
+{
+ SDL_TimerData *data = &SDL_timer_data;
+ SDL_TimerMap *prev, *entry;
+
+ /* Find the timer */
+ prev = NULL;
+ for (entry = data->timermap; entry; prev = entry, entry = entry->next) {
+ if (entry->timerID == id) {
+ if (prev) {
+ prev->next = entry->next;
+ } else {
+ data->timermap = entry->next;
+ }
+ break;
+ }
+ }
+
+ if (entry) {
+ EM_ASM_({
+ window.clearTimeout($0);
+ }, entry->timeoutID);
+ SDL_free(entry);
+
+ return SDL_TRUE;
+ }
+ return SDL_FALSE;
+}
+
+#endif
+
/* This is a legacy support function; SDL_GetTicks() returns a Uint32,
which wraps back to zero every ~49 days. The newer SDL_GetTicks64()
doesn't have this problem, so we just wrap that function and clamp to