SDL: event: Cap maximum wait time if sensor or joystick subsystems are active

From 1bc6dc3ea03c9df7c5b5b56523be23d64fe16ff8 Mon Sep 17 00:00:00 2001
From: Cameron Gutman <[EMAIL REDACTED]>
Date: Tue, 26 Oct 2021 20:02:04 -0500
Subject: [PATCH] event: Cap maximum wait time if sensor or joystick subsystems
 are active

Joystick and sensor subsystems require periodic polling to detect new devices.
---
 src/events/SDL_events.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c
index 074da1aa27..2e79852b38 100644
--- a/src/events/SDL_events.c
+++ b/src/events/SDL_events.c
@@ -44,6 +44,9 @@
 /* An arbitrary limit so we don't have unbounded growth */
 #define SDL_MAX_QUEUED_EVENTS   65535
 
+/* Determines how often we wake to call SDL_PumpEvents() in SDL_WaitEventTimeout_Device() */
+#define PERIODIC_POLL_INTERVAL_MS 3000
+
 typedef struct SDL_EventWatcher {
     SDL_EventFilter callback;
     void *userdata;
@@ -795,10 +798,29 @@ SDL_PollEvent(SDL_Event * event)
     return SDL_WaitEventTimeout(event, 0);
 }
 
+static SDL_bool
+SDL_events_need_periodic_poll() {
+    SDL_bool need_periodic_poll = SDL_FALSE;
+
+#if !SDL_JOYSTICK_DISABLED
+    need_periodic_poll =
+        SDL_WasInit(SDL_INIT_JOYSTICK) &&
+        (!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY));
+#endif
+
+#if !SDL_SENSOR_DISABLED
+    need_periodic_poll = need_periodic_poll ||
+        (SDL_WasInit(SDL_INIT_SENSOR) && !SDL_disabled_events[SDL_SENSORUPDATE >> 8]);
+#endif
+
+    return need_periodic_poll;
+}
+
 static int
 SDL_WaitEventTimeout_Device(_THIS, SDL_Window *wakeup_window, SDL_Event * event, Uint32 start, int timeout)
 {
     int loop_timeout = timeout;
+    SDL_bool need_periodic_poll = SDL_events_need_periodic_poll();
 
     for (;;) {
         /* Pump events on entry and each time we wake to ensure:
@@ -838,6 +860,13 @@ SDL_WaitEventTimeout_Device(_THIS, SDL_Window *wakeup_window, SDL_Event * event,
                 }
                 loop_timeout = (int)((Uint32)timeout - elapsed);
             }
+            if (need_periodic_poll) {
+                if (loop_timeout >= 0) {
+                    loop_timeout = SDL_min(loop_timeout, PERIODIC_POLL_INTERVAL_MS);
+                } else {
+                    loop_timeout = PERIODIC_POLL_INTERVAL_MS;
+                }
+            }
             status = _this->WaitEventTimeout(_this, loop_timeout);
             /* Set wakeup_window to NULL without holding the lock. */
             _this->wakeup_window = NULL;