SDL: events: Only add sentinels for pumping done inside SDL_WaitEventTimeout()

From e9134b045a6eea1d9bea2046ddcefb669ab6e016 Mon Sep 17 00:00:00 2001
From: Cameron Gutman <[EMAIL REDACTED]>
Date: Thu, 6 Jan 2022 19:38:10 -0600
Subject: [PATCH] events: Only add sentinels for pumping done inside
 SDL_WaitEventTimeout()

We don't want to catch explicit SDL_PumpEvents() calls by the application with
our polling check to avoid stale data. If the call to SDL_PumpEvents() produced
no events, there will be a sentinel sitting in the queue that will cause
SDL_PollEvent() to immediately return 0 next time it is called.

Our SDL_WaitEventTimeout() implementation avoids this issue by always popping
an event after calling SDL_PumpEvents(). This will remove the new sentinel if
we didn't get any new events.
---
 src/events/SDL_events.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c
index 4459896e550..ff079c50ea9 100644
--- a/src/events/SDL_events.c
+++ b/src/events/SDL_events.c
@@ -809,7 +809,7 @@ SDL_FlushEvents(Uint32 minType, Uint32 maxType)
 
 /* Run the system dependent event loops */
 void
-SDL_PumpEvents(void)
+SDL_PumpEventsInternal(SDL_bool push_sentinel)
 {
     SDL_VideoDevice *_this = SDL_GetVideoDevice();
 
@@ -837,7 +837,7 @@ SDL_PumpEvents(void)
 
     SDL_SendPendingSignalEvents();  /* in case we had a signal handler fire, etc. */
 
-    if (SDL_GetEventState(SDL_POLLSENTINEL) == SDL_ENABLE) {
+    if (push_sentinel && SDL_GetEventState(SDL_POLLSENTINEL) == SDL_ENABLE) {
         SDL_Event sentinel;
 
         SDL_zero(sentinel);
@@ -846,6 +846,12 @@ SDL_PumpEvents(void)
     }
 }
 
+void
+SDL_PumpEvents()
+{
+    SDL_PumpEventsInternal(SDL_FALSE);
+}
+
 /* Public functions */
 
 int
@@ -885,7 +891,7 @@ SDL_WaitEventTimeout_Device(_THIS, SDL_Window *wakeup_window, SDL_Event * event,
            c) Periodic processing that takes place in some platform PumpEvents() functions happens
            d) Signals received in WaitEventTimeout() are turned into SDL events
         */
-        SDL_PumpEvents();
+        SDL_PumpEventsInternal(SDL_TRUE);
 
         if (!_this->wakeup_lock || SDL_LockMutex(_this->wakeup_lock) == 0) {
             int status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
@@ -984,7 +990,7 @@ SDL_WaitEventTimeout(SDL_Event * event, int timeout)
 
     /* If there isn't a poll sentinel event pending, pump events and add one */
     if (SDL_AtomicGet(&SDL_sentinel_pending) == 0) {
-        SDL_PumpEvents();
+        SDL_PumpEventsInternal(SDL_TRUE);
     }
 
     /* First check for existing events */
@@ -1031,7 +1037,7 @@ SDL_WaitEventTimeout(SDL_Event * event, int timeout)
     }
 
     for (;;) {
-        SDL_PumpEvents();
+        SDL_PumpEventsInternal(SDL_TRUE);
         switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
         case -1:
             return 0;