Added the timerID to the SDL timer callback

Fixes https://github.com/libsdl-org/SDL/issues/2593
This commit is contained in:
Sam Lantinga 2024-05-26 17:56:29 -07:00
parent a5b0041b4a
commit b6360516e4
7 changed files with 53 additions and 42 deletions

View File

@ -1677,6 +1677,13 @@ If you were using this macro for other things besides SDL ticks values, you can
#define SDL_TICKS_PASSED(A, B) ((Sint32)((B) - (A)) <= 0) #define SDL_TICKS_PASSED(A, B) ((Sint32)((B) - (A)) <= 0)
``` ```
The callback passed to SDL_AddTimer() has changed parameters to:
```c
Uint32 SDLCALL TimerCallback(void *userdata, SDL_TimerID timerID, Uint32 interval);
````
The return value of SDL_RemoveTimer() has changed to the standard int error code.
## SDL_touch.h ## SDL_touch.h
SDL_GetTouchName is replaced with SDL_GetTouchDeviceName(), which takes an SDL_TouchID instead of an index. SDL_GetTouchName is replaced with SDL_GetTouchDeviceName(), which takes an SDL_TouchID instead of an index.

View File

@ -124,6 +124,13 @@ extern SDL_DECLSPEC void SDLCALL SDL_Delay(Uint32 ms);
*/ */
extern SDL_DECLSPEC void SDLCALL SDL_DelayNS(Uint64 ns); extern SDL_DECLSPEC void SDLCALL SDL_DelayNS(Uint64 ns);
/**
* Definition of the timer ID type.
*
* \since This datatype is available since SDL 3.0.0.
*/
typedef Uint32 SDL_TimerID;
/** /**
* Function prototype for the timer callback function. * Function prototype for the timer callback function.
* *
@ -132,9 +139,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_DelayNS(Uint64 ns);
* the one passed in, the periodic alarm continues, otherwise a new alarm is * the one passed in, the periodic alarm continues, otherwise a new alarm is
* scheduled. If the callback returns 0, the periodic alarm is cancelled. * scheduled. If the callback returns 0, the periodic alarm is cancelled.
* *
* \param userdata an arbitrary pointer provided by the app through SDL_AddTimer, for its own use.
* \param timerID the current timer being processed
* \param interval the current callback time interval. * \param interval the current callback time interval.
* \param param an arbitrary pointer provided by the app through SDL_AddTimer,
* for its own use.
* \returns the new callback time interval, or 0 to disable further runs of * \returns the new callback time interval, or 0 to disable further runs of
* the callback. * the callback.
* *
@ -146,14 +153,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_DelayNS(Uint64 ns);
* *
* \sa SDL_AddTimer * \sa SDL_AddTimer
*/ */
typedef Uint32 (SDLCALL *SDL_TimerCallback)(Uint32 interval, void *param); typedef Uint32 (SDLCALL *SDL_TimerCallback)(void *userdata, SDL_TimerID timerID, Uint32 interval);
/**
* Definition of the timer ID type.
*
* \since This datatype is available since SDL 3.0.0.
*/
typedef Uint32 SDL_TimerID;
/** /**
* Call a callback function at a future time. * Call a callback function at a future time.
@ -179,7 +179,7 @@ typedef Uint32 SDL_TimerID;
* \param interval the timer delay, in milliseconds, passed to `callback` * \param interval the timer delay, in milliseconds, passed to `callback`
* \param callback the SDL_TimerCallback function to call when the specified * \param callback the SDL_TimerCallback function to call when the specified
* `interval` elapses * `interval` elapses
* \param param a pointer that is passed to `callback` * \param userdata a pointer that is passed to `callback`
* \returns a timer ID or 0 if an error occurs; call SDL_GetError() for more * \returns a timer ID or 0 if an error occurs; call SDL_GetError() for more
* information. * information.
* *
@ -189,22 +189,20 @@ typedef Uint32 SDL_TimerID;
* *
* \sa SDL_RemoveTimer * \sa SDL_RemoveTimer
*/ */
extern SDL_DECLSPEC SDL_TimerID SDLCALL SDL_AddTimer(Uint32 interval, extern SDL_DECLSPEC SDL_TimerID SDLCALL SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *userdata);
SDL_TimerCallback callback,
void *param);
/** /**
* Remove a timer created with SDL_AddTimer(). * Remove a timer created with SDL_AddTimer().
* *
* \param id the ID of the timer to remove * \param id the ID of the timer to remove
* \returns SDL_TRUE if the timer is removed or SDL_FALSE if the timer wasn't * \returns 0 on success or a negative error code on failure; call
* found. * SDL_GetError() for more information.
* *
* \since This function is available since SDL 3.0.0. * \since This function is available since SDL 3.0.0.
* *
* \sa SDL_AddTimer * \sa SDL_AddTimer
*/ */
extern SDL_DECLSPEC SDL_bool SDLCALL SDL_RemoveTimer(SDL_TimerID id); extern SDL_DECLSPEC int SDLCALL SDL_RemoveTimer(SDL_TimerID id);
/* Ends C function definitions when using C++ */ /* Ends C function definitions when using C++ */

View File

@ -662,7 +662,7 @@ SDL_DYNAPI_PROC(int,SDL_ReleaseCameraFrame,(SDL_Camera *a, SDL_Surface *b),(a,b)
SDL_DYNAPI_PROC(int,SDL_ReloadGamepadMappings,(void),(),return) SDL_DYNAPI_PROC(int,SDL_ReloadGamepadMappings,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_RemovePath,(const char *a),(a),return) SDL_DYNAPI_PROC(int,SDL_RemovePath,(const char *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_RemoveStoragePath,(SDL_Storage *a, const char *b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_RemoveStoragePath,(SDL_Storage *a, const char *b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_RemoveTimer,(SDL_TimerID a),(a),return) SDL_DYNAPI_PROC(int,SDL_RemoveTimer,(SDL_TimerID a),(a),return)
SDL_DYNAPI_PROC(int,SDL_RenamePath,(const char *a, const char *b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_RenamePath,(const char *a, const char *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_RenameStoragePath,(SDL_Storage *a, const char *b, const char *c),(a,b,c),return) SDL_DYNAPI_PROC(int,SDL_RenameStoragePath,(SDL_Storage *a, const char *b, const char *c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_RenderClear,(SDL_Renderer *a),(a),return) SDL_DYNAPI_PROC(int,SDL_RenderClear,(SDL_Renderer *a),(a),return)

View File

@ -31,7 +31,7 @@ typedef struct SDL_Timer
{ {
SDL_TimerID timerID; SDL_TimerID timerID;
SDL_TimerCallback callback; SDL_TimerCallback callback;
void *param; void *userdata;
Uint64 interval; Uint64 interval;
Uint64 scheduled; Uint64 scheduled;
SDL_AtomicInt canceled; SDL_AtomicInt canceled;
@ -161,7 +161,7 @@ static int SDLCALL SDL_TimerThread(void *_data)
interval = 0; interval = 0;
} else { } else {
/* FIXME: We could potentially support sub-millisecond timers now */ /* FIXME: We could potentially support sub-millisecond timers now */
interval = SDL_MS_TO_NS(current->callback((Uint32)SDL_NS_TO_MS(current->interval), current->param)); interval = SDL_MS_TO_NS(current->callback(current->userdata, current->timerID, (Uint32)SDL_NS_TO_MS(current->interval)));
} }
if (interval > 0) { if (interval > 0) {
@ -269,7 +269,7 @@ void SDL_QuitTimers(void)
} }
} }
SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param) SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *userdata)
{ {
SDL_TimerData *data = &SDL_timer_data; SDL_TimerData *data = &SDL_timer_data;
SDL_Timer *timer; SDL_Timer *timer;
@ -299,7 +299,7 @@ SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *para
} }
timer->timerID = SDL_GetNextObjectID(); timer->timerID = SDL_GetNextObjectID();
timer->callback = callback; timer->callback = callback;
timer->param = param; timer->userdata = userdata;
timer->interval = SDL_MS_TO_NS(interval); timer->interval = SDL_MS_TO_NS(interval);
timer->scheduled = SDL_GetTicksNS() + timer->interval; timer->scheduled = SDL_GetTicksNS() + timer->interval;
SDL_AtomicSet(&timer->canceled, 0); SDL_AtomicSet(&timer->canceled, 0);
@ -329,7 +329,7 @@ SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *para
return entry->timerID; return entry->timerID;
} }
SDL_bool SDL_RemoveTimer(SDL_TimerID id) int SDL_RemoveTimer(SDL_TimerID id)
{ {
SDL_TimerData *data = &SDL_timer_data; SDL_TimerData *data = &SDL_timer_data;
SDL_TimerMap *prev, *entry; SDL_TimerMap *prev, *entry;
@ -357,7 +357,11 @@ SDL_bool SDL_RemoveTimer(SDL_TimerID id)
} }
SDL_free(entry); SDL_free(entry);
} }
return canceled; if (canceled) {
return 0;
} else {
return SDL_SetError("Timer not found");
}
} }
#else #else
@ -371,7 +375,7 @@ typedef struct SDL_TimerMap
int timeoutID; int timeoutID;
Uint32 interval; Uint32 interval;
SDL_TimerCallback callback; SDL_TimerCallback callback;
void *param; void *userdata;
struct SDL_TimerMap *next; struct SDL_TimerMap *next;
} SDL_TimerMap; } SDL_TimerMap;
@ -385,7 +389,7 @@ static SDL_TimerData SDL_timer_data;
static void SDL_Emscripten_TimerHelper(void *userdata) static void SDL_Emscripten_TimerHelper(void *userdata)
{ {
SDL_TimerMap *entry = (SDL_TimerMap *)userdata; SDL_TimerMap *entry = (SDL_TimerMap *)userdata;
entry->interval = entry->callback(entry->interval, entry->param); entry->interval = entry->callback(entry->userdata, entry->timerID, entry->interval);
if (entry->interval > 0) { if (entry->interval > 0) {
entry->timeoutID = emscripten_set_timeout(&SDL_Emscripten_TimerHelper, entry->timeoutID = emscripten_set_timeout(&SDL_Emscripten_TimerHelper,
entry->interval, entry->interval,
@ -410,7 +414,7 @@ void SDL_QuitTimers(void)
} }
} }
SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param) SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *userdata)
{ {
SDL_TimerData *data = &SDL_timer_data; SDL_TimerData *data = &SDL_timer_data;
SDL_TimerMap *entry; SDL_TimerMap *entry;
@ -421,7 +425,7 @@ SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *para
} }
entry->timerID = SDL_GetNextObjectID(); entry->timerID = SDL_GetNextObjectID();
entry->callback = callback; entry->callback = callback;
entry->param = param; entry->userdata = userdata;
entry->interval = interval; entry->interval = interval;
entry->timeoutID = emscripten_set_timeout(&SDL_Emscripten_TimerHelper, entry->timeoutID = emscripten_set_timeout(&SDL_Emscripten_TimerHelper,
@ -434,7 +438,7 @@ SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *para
return entry->timerID; return entry->timerID;
} }
SDL_bool SDL_RemoveTimer(SDL_TimerID id) int SDL_RemoveTimer(SDL_TimerID id)
{ {
SDL_TimerData *data = &SDL_timer_data; SDL_TimerData *data = &SDL_timer_data;
SDL_TimerMap *prev, *entry; SDL_TimerMap *prev, *entry;
@ -455,10 +459,10 @@ SDL_bool SDL_RemoveTimer(SDL_TimerID id)
if (entry) { if (entry) {
emscripten_clear_timeout(entry->timeoutID); emscripten_clear_timeout(entry->timeoutID);
SDL_free(entry); SDL_free(entry);
return 0;
return SDL_TRUE; } else {
return SDL_SetError("Timer not found");
} }
return SDL_FALSE;
} }
#endif /* !defined(SDL_PLATFORM_EMSCRIPTEN) || !SDL_THREADS_DISABLED */ #endif /* !defined(SDL_PLATFORM_EMSCRIPTEN) || !SDL_THREADS_DISABLED */

View File

@ -101,7 +101,7 @@ static int timer_delayAndGetTicks(void *arg)
} }
/* Test callback */ /* Test callback */
static Uint32 SDLCALL timerTestCallback(Uint32 interval, void *param) static Uint32 SDLCALL timerTestCallback(void *param, SDL_TimerID timerID, Uint32 interval)
{ {
g_timerCallbackCalled = 1; g_timerCallbackCalled = 1;
@ -121,7 +121,7 @@ static Uint32 SDLCALL timerTestCallback(Uint32 interval, void *param)
static int timer_addRemoveTimer(void *arg) static int timer_addRemoveTimer(void *arg)
{ {
SDL_TimerID id; SDL_TimerID id;
SDL_bool result; int result;
int param; int param;
/* Reset state */ /* Reset state */
@ -136,13 +136,13 @@ static int timer_addRemoveTimer(void *arg)
/* Remove timer again and check that callback was not called */ /* Remove timer again and check that callback was not called */
result = SDL_RemoveTimer(id); result = SDL_RemoveTimer(id);
SDLTest_AssertPass("Call to SDL_RemoveTimer()"); SDLTest_AssertPass("Call to SDL_RemoveTimer()");
SDLTest_AssertCheck(result == SDL_TRUE, "Check result value, expected: %i, got: %i", SDL_TRUE, result); SDLTest_AssertCheck(result == 0, "Check result value, expected: 0, got: %i", result);
SDLTest_AssertCheck(g_timerCallbackCalled == 0, "Check callback WAS NOT called, expected: 0, got: %i", g_timerCallbackCalled); SDLTest_AssertCheck(g_timerCallbackCalled == 0, "Check callback WAS NOT called, expected: 0, got: %i", g_timerCallbackCalled);
/* Try to remove timer again (should be a NOOP) */ /* Try to remove timer again (should be a NOOP) */
result = SDL_RemoveTimer(id); result = SDL_RemoveTimer(id);
SDLTest_AssertPass("Call to SDL_RemoveTimer()"); SDLTest_AssertPass("Call to SDL_RemoveTimer()");
SDLTest_AssertCheck(result == SDL_FALSE, "Check result value, expected: %i, got: %i", SDL_FALSE, result); SDLTest_AssertCheck(result < 0, "Check result value, expected: <0, got: %i", result);
/* Reset state */ /* Reset state */
param = SDLTest_RandomIntegerInRange(-1024, 1024); param = SDLTest_RandomIntegerInRange(-1024, 1024);
@ -162,7 +162,7 @@ static int timer_addRemoveTimer(void *arg)
/* Remove timer again and check that callback was called */ /* Remove timer again and check that callback was called */
result = SDL_RemoveTimer(id); result = SDL_RemoveTimer(id);
SDLTest_AssertPass("Call to SDL_RemoveTimer()"); SDLTest_AssertPass("Call to SDL_RemoveTimer()");
SDLTest_AssertCheck(result == SDL_FALSE, "Check result value, expected: %i, got: %i", SDL_FALSE, result); SDLTest_AssertCheck(result < 0, "Check result value, expected: <0, got: %i", result);
SDLTest_AssertCheck(g_timerCallbackCalled == 1, "Check callback WAS called, expected: 1, got: %i", g_timerCallbackCalled); SDLTest_AssertCheck(g_timerCallbackCalled == 1, "Check callback WAS called, expected: 1, got: %i", g_timerCallbackCalled);
return TEST_COMPLETED; return TEST_COMPLETED;

View File

@ -100,7 +100,7 @@ Run(void *data)
} }
#ifndef _WIN32 #ifndef _WIN32
static Uint32 hit_timeout(Uint32 interval, void *param) { static Uint32 hit_timeout(void *param, SDL_TimerID timerID, Uint32 interval) {
SDL_Log("Hit timeout! Sending SIGINT!"); SDL_Log("Hit timeout! Sending SIGINT!");
(void)raise(SIGINT); (void)raise(SIGINT);
return 0; return 0;

View File

@ -50,16 +50,18 @@ static int test_sdl_delay_within_bounds(void) {
static int ticks = 0; static int ticks = 0;
static Uint32 SDLCALL static Uint32 SDLCALL
ticktock(Uint32 interval, void *param) ticktock(void *param, SDL_TimerID timerID, Uint32 interval)
{ {
++ticks; ++ticks;
return interval; return interval;
} }
static Uint32 SDLCALL static Uint32 SDLCALL
callback(Uint32 interval, void *param) callback(void *param, SDL_TimerID timerID, Uint32 interval)
{ {
SDL_Log("Timer %" SDL_PRIu32 " : param = %d\n", interval, (int)(uintptr_t)param); int value = (int)(uintptr_t)param;
SDL_assert( value == 1 || value == 2 || value == 3 );
SDL_Log("Timer %" SDL_PRIu32 " : param = %d\n", interval, value);
return interval; return interval;
} }
@ -182,7 +184,7 @@ int main(int argc, char *argv[])
start_perf = SDL_GetPerformanceCounter(); start_perf = SDL_GetPerformanceCounter();
for (i = 0; i < 1000000; ++i) { for (i = 0; i < 1000000; ++i) {
ticktock(0, NULL); ticktock(NULL, 0, 0);
} }
now_perf = SDL_GetPerformanceCounter(); now_perf = SDL_GetPerformanceCounter();
SDL_Log("1 million iterations of ticktock took %f ms\n", (double)((now_perf - start_perf) * 1000) / SDL_GetPerformanceFrequency()); SDL_Log("1 million iterations of ticktock took %f ms\n", (double)((now_perf - start_perf) * 1000) / SDL_GetPerformanceFrequency());