From f439ccfc1a834eefe68ce33a3dad31dda0b617a5 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 3 Nov 2023 22:31:42 -0700 Subject: [PATCH] Updated return values for SDL event functions SDL_PollEvent(), SDL_WaitEvent(), and SDL_WaitEventTimeout() all return SDL_bool. SDL_AddEventWatch() returns an int result code. Also improved timeout accuracy in SDL_WaitEventTimeout() --- include/SDL3/SDL_events.h | 38 ++++----- src/SDL_internal.h | 2 +- src/dynapi/SDL_dynapi_procs.h | 8 +- src/events/SDL_events.c | 141 ++++++++++++++++++---------------- 4 files changed, 96 insertions(+), 93 deletions(-) diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h index 4e93b0fb1..8a7665ea6 100644 --- a/include/SDL3/SDL_events.h +++ b/include/SDL3/SDL_events.h @@ -731,9 +731,7 @@ typedef enum * \sa SDL_PumpEvents * \sa SDL_PushEvent */ -extern DECLSPEC int SDLCALL SDL_PeepEvents(SDL_Event * events, int numevents, - SDL_eventaction action, - Uint32 minType, Uint32 maxType); +extern DECLSPEC int SDLCALL SDL_PeepEvents(SDL_Event *events, int numevents, SDL_eventaction action, Uint32 minType, Uint32 maxType); /* @} */ /** @@ -852,7 +850,7 @@ extern DECLSPEC void SDLCALL SDL_FlushEvents(Uint32 minType, Uint32 maxType); * * \param event the SDL_Event structure to be filled with the next event from * the queue, or NULL - * \returns 1 if there is a pending event or 0 if there are none available. + * \returns SDL_TRUE if this got an event or SDL_FALSE if there are none available. * * \since This function is available since SDL 3.0.0. * @@ -863,7 +861,7 @@ extern DECLSPEC void SDLCALL SDL_FlushEvents(Uint32 minType, Uint32 maxType); * \sa SDL_WaitEvent * \sa SDL_WaitEventTimeout */ -extern DECLSPEC int SDLCALL SDL_PollEvent(SDL_Event * event); +extern DECLSPEC SDL_bool SDLCALL SDL_PollEvent(SDL_Event *event); /** * Wait indefinitely for the next available event. @@ -876,7 +874,7 @@ extern DECLSPEC int SDLCALL SDL_PollEvent(SDL_Event * event); * * \param event the SDL_Event structure to be filled in with the next event * from the queue, or NULL - * \returns 1 on success or 0 if there was an error while waiting for events; + * \returns SDL_TRUE on success or SDL_FALSE if there was an error while waiting for events; * call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. @@ -885,7 +883,7 @@ extern DECLSPEC int SDLCALL SDL_PollEvent(SDL_Event * event); * \sa SDL_PumpEvents * \sa SDL_WaitEventTimeout */ -extern DECLSPEC int SDLCALL SDL_WaitEvent(SDL_Event *event); +extern DECLSPEC SDL_bool SDLCALL SDL_WaitEvent(SDL_Event *event); /** * Wait until the specified timeout (in milliseconds) for the next available @@ -904,9 +902,7 @@ extern DECLSPEC int SDLCALL SDL_WaitEvent(SDL_Event *event); * from the queue, or NULL * \param timeoutMS the maximum number of milliseconds to wait for the next * available event - * \returns 1 on success or 0 if there was an error while waiting for events; - * call SDL_GetError() for more information. This also returns 0 if - * the timeout elapsed without an event arriving. + * \returns SDL_TRUE if this got an event or SDL_FALSE if the timeout elapsed without any events available. * * \since This function is available since SDL 3.0.0. * @@ -914,7 +910,7 @@ extern DECLSPEC int SDLCALL SDL_WaitEvent(SDL_Event *event); * \sa SDL_PumpEvents * \sa SDL_WaitEvent */ -extern DECLSPEC int SDLCALL SDL_WaitEventTimeout(SDL_Event *event, Sint32 timeoutMS); +extern DECLSPEC SDL_bool SDLCALL SDL_WaitEventTimeout(SDL_Event *event, Sint32 timeoutMS); /** * Add an event to the event queue. @@ -948,7 +944,7 @@ extern DECLSPEC int SDLCALL SDL_WaitEventTimeout(SDL_Event *event, Sint32 timeou * \sa SDL_PollEvent * \sa SDL_RegisterEvents */ -extern DECLSPEC int SDLCALL SDL_PushEvent(SDL_Event * event); +extern DECLSPEC int SDLCALL SDL_PushEvent(SDL_Event *event); /** * A function pointer used for callbacks that watch the event queue. @@ -962,7 +958,7 @@ extern DECLSPEC int SDLCALL SDL_PushEvent(SDL_Event * event); * \sa SDL_SetEventFilter * \sa SDL_AddEventWatch */ -typedef int (SDLCALL * SDL_EventFilter) (void *userdata, SDL_Event * event); +typedef int (SDLCALL *SDL_EventFilter)(void *userdata, SDL_Event *event); /** * Set up a filter to process all events before they change internal state and @@ -1006,8 +1002,7 @@ typedef int (SDLCALL * SDL_EventFilter) (void *userdata, SDL_Event * event); * \sa SDL_PeepEvents * \sa SDL_PushEvent */ -extern DECLSPEC void SDLCALL SDL_SetEventFilter(SDL_EventFilter filter, - void *userdata); +extern DECLSPEC void SDLCALL SDL_SetEventFilter(SDL_EventFilter filter, void *userdata); /** * Query the current event filter. @@ -1024,8 +1019,7 @@ extern DECLSPEC void SDLCALL SDL_SetEventFilter(SDL_EventFilter filter, * * \sa SDL_SetEventFilter */ -extern DECLSPEC SDL_bool SDLCALL SDL_GetEventFilter(SDL_EventFilter * filter, - void **userdata); +extern DECLSPEC SDL_bool SDLCALL SDL_GetEventFilter(SDL_EventFilter *filter, void **userdata); /** * Add a callback to be triggered when an event is added to the event queue. @@ -1047,14 +1041,14 @@ extern DECLSPEC SDL_bool SDLCALL SDL_GetEventFilter(SDL_EventFilter * filter, * * \param filter an SDL_EventFilter function to call when an event happens. * \param userdata a pointer that is passed to `filter` + * \returns 0 on success, or a negative error code on failure; call SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * * \sa SDL_DelEventWatch * \sa SDL_SetEventFilter */ -extern DECLSPEC void SDLCALL SDL_AddEventWatch(SDL_EventFilter filter, - void *userdata); +extern DECLSPEC int SDLCALL SDL_AddEventWatch(SDL_EventFilter filter, void *userdata); /** * Remove an event watch callback added with SDL_AddEventWatch(). @@ -1069,8 +1063,7 @@ extern DECLSPEC void SDLCALL SDL_AddEventWatch(SDL_EventFilter filter, * * \sa SDL_AddEventWatch */ -extern DECLSPEC void SDLCALL SDL_DelEventWatch(SDL_EventFilter filter, - void *userdata); +extern DECLSPEC void SDLCALL SDL_DelEventWatch(SDL_EventFilter filter, void *userdata); /** * Run a specific filter function on the current event queue, removing any @@ -1088,8 +1081,7 @@ extern DECLSPEC void SDLCALL SDL_DelEventWatch(SDL_EventFilter filter, * \sa SDL_GetEventFilter * \sa SDL_SetEventFilter */ -extern DECLSPEC void SDLCALL SDL_FilterEvents(SDL_EventFilter filter, - void *userdata); +extern DECLSPEC void SDLCALL SDL_FilterEvents(SDL_EventFilter filter, void *userdata); /** * Set the state of processing events by type. diff --git a/src/SDL_internal.h b/src/SDL_internal.h index aa2d6c627..b0f2c296f 100644 --- a/src/SDL_internal.h +++ b/src/SDL_internal.h @@ -200,7 +200,7 @@ extern "C" { extern DECLSPEC Uint32 SDLCALL SDL_GetNextObjectID(void); extern DECLSPEC int SDLCALL SDL_WaitSemaphoreTimeoutNS(SDL_Semaphore *sem, Sint64 timeoutNS); extern DECLSPEC int SDLCALL SDL_WaitConditionTimeoutNS(SDL_Condition *cond, SDL_Mutex *mutex, Sint64 timeoutNS); -extern DECLSPEC int SDLCALL SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS); +extern DECLSPEC SDL_bool SDLCALL SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS); /* Ends C function definitions when using C++ */ #ifdef __cplusplus diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 25ee29776..d2f40604b 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -103,7 +103,7 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_IsAndroidTV,(void),(),return) SDL_DYNAPI_PROC(SDL_bool,SDL_IsChromebook,(void),(),return) SDL_DYNAPI_PROC(SDL_bool,SDL_IsDeXMode,(void),(),return) -SDL_DYNAPI_PROC(void,SDL_AddEventWatch,(SDL_EventFilter a, void *b),(a,b),) +SDL_DYNAPI_PROC(int,SDL_AddEventWatch,(SDL_EventFilter a, void *b),(a,b),) SDL_DYNAPI_PROC(int,SDL_AddGamepadMapping,(const char *a),(a),return) SDL_DYNAPI_PROC(int,SDL_AddGamepadMappingsFromRW,(SDL_RWops *a, SDL_bool b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_AddHintCallback,(const char *a, SDL_HintCallback b, void *c),(a,b,c),return) @@ -554,7 +554,7 @@ SDL_DYNAPI_PROC(SDL_Joystick*,SDL_OpenJoystick,(SDL_JoystickID a),(a),return) SDL_DYNAPI_PROC(SDL_Sensor*,SDL_OpenSensor,(SDL_SensorID a),(a),return) SDL_DYNAPI_PROC(int,SDL_OpenURL,(const char *a),(a),return) SDL_DYNAPI_PROC(int,SDL_PeepEvents,(SDL_Event *a, int b, SDL_eventaction c, Uint32 d, Uint32 e),(a,b,c,d,e),return) -SDL_DYNAPI_PROC(int,SDL_PollEvent,(SDL_Event *a),(a),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_PollEvent,(SDL_Event *a),(a),return) SDL_DYNAPI_PROC(int,SDL_PostSemaphore,(SDL_Semaphore *a),(a),return) SDL_DYNAPI_PROC(int,SDL_PremultiplyAlpha,(int a, int b, Uint32 c, const void *d, int e, Uint32 f, void *g, int h),(a,b,c,d,e,f,g,h),return) SDL_DYNAPI_PROC(void,SDL_PumpEvents,(void),(),) @@ -725,8 +725,8 @@ SDL_DYNAPI_PROC(int,SDL_Vulkan_LoadLibrary,(const char *a),(a),return) SDL_DYNAPI_PROC(void,SDL_Vulkan_UnloadLibrary,(void),(),) SDL_DYNAPI_PROC(int,SDL_WaitCondition,(SDL_Condition *a, SDL_Mutex *b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_WaitConditionTimeout,(SDL_Condition *a, SDL_Mutex *b, Sint32 c),(a,b,c),return) -SDL_DYNAPI_PROC(int,SDL_WaitEvent,(SDL_Event *a),(a),return) -SDL_DYNAPI_PROC(int,SDL_WaitEventTimeout,(SDL_Event *a, Sint32 b),(a,b),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_WaitEvent,(SDL_Event *a),(a),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_WaitEventTimeout,(SDL_Event *a, Sint32 b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_WaitSemaphore,(SDL_Semaphore *a),(a),return) SDL_DYNAPI_PROC(int,SDL_WaitSemaphoreTimeout,(SDL_Semaphore *a, Sint32 b),(a,b),return) SDL_DYNAPI_PROC(void,SDL_WaitThread,(SDL_Thread *a, int *b),(a,b),) diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c index bd926f3d7..031e660ac 100644 --- a/src/events/SDL_events.c +++ b/src/events/SDL_events.c @@ -903,7 +903,7 @@ void SDL_PumpEvents(void) /* Public functions */ -int SDL_PollEvent(SDL_Event *event) +SDL_bool SDL_PollEvent(SDL_Event *event) { return SDL_WaitEventTimeoutNS(event, 0); } @@ -1014,14 +1014,14 @@ static SDL_Window *SDL_find_active_window(SDL_VideoDevice *_this) return NULL; } -int SDL_WaitEvent(SDL_Event *event) +SDL_bool SDL_WaitEvent(SDL_Event *event) { return SDL_WaitEventTimeoutNS(event, -1); } -int SDL_WaitEventTimeout(SDL_Event *event, Sint32 timeoutMS) +SDL_bool SDL_WaitEventTimeout(SDL_Event *event, Sint32 timeoutMS) { - Uint64 timeoutNS; + Sint64 timeoutNS; if (timeoutMS > 0) { timeoutNS = SDL_MS_TO_NS(timeoutMS); @@ -1031,7 +1031,7 @@ int SDL_WaitEventTimeout(SDL_Event *event, Sint32 timeoutMS) return SDL_WaitEventTimeoutNS(event, timeoutNS); } -int SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS) +SDL_bool SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS) { SDL_VideoDevice *_this = SDL_GetVideoDevice(); SDL_Window *wakeup_window; @@ -1039,46 +1039,6 @@ int SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS) SDL_bool include_sentinel = (timeoutNS == 0); int result; - /* If there isn't a poll sentinel event pending, pump events and add one */ - if (SDL_AtomicGet(&SDL_sentinel_pending) == 0) { - SDL_PumpEventsInternal(SDL_TRUE); - } - - /* First check for existing events */ - result = SDL_PeepEventsInternal(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST, include_sentinel); - if (result < 0) { - return 0; - } - if (include_sentinel) { - if (event) { - if (event->type == SDL_EVENT_POLL_SENTINEL) { - /* Reached the end of a poll cycle, and not willing to wait */ - return 0; - } - } else { - /* Need to peek the next event to check for sentinel */ - SDL_Event dummy; - - if (SDL_PeepEventsInternal(&dummy, 1, SDL_PEEKEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST, SDL_TRUE) && - dummy.type == SDL_EVENT_POLL_SENTINEL) { - SDL_PeepEventsInternal(&dummy, 1, SDL_GETEVENT, SDL_EVENT_POLL_SENTINEL, SDL_EVENT_POLL_SENTINEL, SDL_TRUE); - /* Reached the end of a poll cycle, and not willing to wait */ - return 0; - } - } - } - if (result == 0) { - if (timeoutNS == 0) { - /* No events available, and not willing to wait */ - return 0; - } - } else { - /* Has existing events */ - return 1; - } - /* We should have completely handled timeoutNS == 0 above */ - SDL_assert(timeoutNS != 0); - if (timeoutNS > 0) { start = SDL_GetTicksNS(); expiration = start + timeoutNS; @@ -1087,36 +1047,80 @@ int SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS) expiration = 0; } + /* If there isn't a poll sentinel event pending, pump events and add one */ + if (SDL_AtomicGet(&SDL_sentinel_pending) == 0) { + SDL_PumpEventsInternal(SDL_TRUE); + } + + /* First check for existing events */ + result = SDL_PeepEventsInternal(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST, include_sentinel); + if (result < 0) { + return SDL_FALSE; + } + if (include_sentinel) { + if (event) { + if (event->type == SDL_EVENT_POLL_SENTINEL) { + /* Reached the end of a poll cycle, and not willing to wait */ + return SDL_FALSE; + } + } else { + /* Need to peek the next event to check for sentinel */ + SDL_Event dummy; + + if (SDL_PeepEventsInternal(&dummy, 1, SDL_PEEKEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST, SDL_TRUE) && + dummy.type == SDL_EVENT_POLL_SENTINEL) { + SDL_PeepEventsInternal(&dummy, 1, SDL_GETEVENT, SDL_EVENT_POLL_SENTINEL, SDL_EVENT_POLL_SENTINEL, SDL_TRUE); + /* Reached the end of a poll cycle, and not willing to wait */ + return SDL_FALSE; + } + } + } + if (result == 0) { + if (timeoutNS == 0) { + /* No events available, and not willing to wait */ + return SDL_FALSE; + } + } else { + /* Has existing events */ + return SDL_TRUE; + } + /* We should have completely handled timeoutNS == 0 above */ + SDL_assert(timeoutNS != 0); + if (_this && _this->WaitEventTimeout && _this->SendWakeupEvent && !SDL_events_need_polling()) { /* Look if a shown window is available to send the wakeup event. */ wakeup_window = SDL_find_active_window(_this); if (wakeup_window) { - int status = SDL_WaitEventTimeout_Device(_this, wakeup_window, event, start, timeoutNS); - - /* There may be implementation-defined conditions where the backend cannot - reliably wait for the next event. If that happens, fall back to polling. */ - if (status >= 0) { - return status; + result = SDL_WaitEventTimeout_Device(_this, wakeup_window, event, start, timeoutNS); + if (result > 0) { + return SDL_TRUE; + } else if (result == 0) { + return SDL_FALSE; + } else { + /* There may be implementation-defined conditions where the backend cannot + * reliably wait for the next event. If that happens, fall back to polling. + */ } } } for (;;) { SDL_PumpEventsInternal(SDL_TRUE); - switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST)) { - case -1: - return 0; - case 0: - if (timeoutNS > 0 && SDL_GetTicksNS() >= expiration) { - /* Timeout expired and no events */ - return 0; - } - SDL_Delay(1); - break; - default: - /* Has events */ - return 1; + + if (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST) > 0) { + return SDL_TRUE; } + + Uint64 delay = SDL_MS_TO_NS(1); + if (timeoutNS > 0) { + Uint64 now = SDL_GetTicksNS(); + if (now >= expiration) { + /* Timeout expired and no events */ + return SDL_FALSE; + } + delay = SDL_min((expiration - now), delay); + } + SDL_DelayNS(delay); } } @@ -1200,8 +1204,10 @@ SDL_bool SDL_GetEventFilter(SDL_EventFilter *filter, void **userdata) return event_ok.callback ? SDL_TRUE : SDL_FALSE; } -void SDL_AddEventWatch(SDL_EventFilter filter, void *userdata) +int SDL_AddEventWatch(SDL_EventFilter filter, void *userdata) { + int result = 0; + SDL_LockMutex(SDL_event_watchers_lock); { SDL_EventWatcher *event_watchers; @@ -1216,9 +1222,14 @@ void SDL_AddEventWatch(SDL_EventFilter filter, void *userdata) watcher->userdata = userdata; watcher->removed = SDL_FALSE; ++SDL_event_watchers_count; + } else { + SDL_OutOfMemory(); + result = -1; } } SDL_UnlockMutex(SDL_event_watchers_lock); + + return result; } void SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)