SDL: fixed issue where video events could be posted while system was quitting (#14572)

From 70c2f576c83fffb4176b728f58783ec58c530c76 Mon Sep 17 00:00:00 2001
From: milkmull <[EMAIL REDACTED]>
Date: Wed, 3 Dec 2025 17:17:11 -0500
Subject: [PATCH] fixed issue where video events could be posted while system
 was quitting (#14572)

---
 src/events/SDL_displayevents.c | 11 ++++++++++-
 src/events/SDL_windowevents.c  | 12 ++++++++++--
 src/video/SDL_sysvideo.h       |  1 +
 src/video/SDL_video.c          |  2 ++
 4 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/src/events/SDL_displayevents.c b/src/events/SDL_displayevents.c
index e41f75cca761d..0bcd4ccfd886d 100644
--- a/src/events/SDL_displayevents.c
+++ b/src/events/SDL_displayevents.c
@@ -26,6 +26,9 @@
 
 void SDL_SendDisplayEvent(SDL_VideoDisplay *display, SDL_EventType displayevent, int data1, int data2)
 {
+    SDL_VideoDevice *_this;
+    bool post_event = true;
+
     if (!display || display->id == 0) {
         return;
     }
@@ -40,8 +43,14 @@ void SDL_SendDisplayEvent(SDL_VideoDisplay *display, SDL_EventType displayevent,
         break;
     }
 
+    // Only post if we are not currently quitting
+    _this = SDL_GetVideoDevice();
+    if (_this == NULL || _this->is_quitting) {
+        post_event = false;
+    }
+
     // Post the event, if desired
-    if (SDL_EventEnabled(displayevent)) {
+    if (post_event && SDL_EventEnabled(displayevent)) {
         SDL_Event event;
         event.type = displayevent;
         event.common.timestamp = 0;
diff --git a/src/events/SDL_windowevents.c b/src/events/SDL_windowevents.c
index 7d4bd150901b4..f31faf09aff22 100644
--- a/src/events/SDL_windowevents.c
+++ b/src/events/SDL_windowevents.c
@@ -70,6 +70,8 @@ static bool SDLCALL RemoveSupersededWindowEvents(void *userdata, SDL_Event *even
 
 bool SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent, int data1, int data2)
 {
+    SDL_VideoDevice *_this;
+    bool post_event = true;
     bool posted = false;
 
     if (!window) {
@@ -220,6 +222,12 @@ bool SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent, int data
         return false;
     }
 
+    // Only post if we are not currently quitting
+    _this = SDL_GetVideoDevice();
+    if (_this == NULL || _this->is_quitting) {
+        post_event = false;
+    }
+
     // Post the event, if desired
     SDL_Event event;
     event.type = windowevent;
@@ -231,7 +239,7 @@ bool SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent, int data
     SDL_DispatchEventWatchList(&SDL_window_event_watchers[SDL_WINDOW_EVENT_WATCH_EARLY], &event);
     SDL_DispatchEventWatchList(&SDL_window_event_watchers[SDL_WINDOW_EVENT_WATCH_NORMAL], &event);
 
-    if (SDL_EventEnabled(windowevent)) {
+    if (post_event && SDL_EventEnabled(windowevent)) {
         // Fixes queue overflow with move/resize events that aren't processed
         if (windowevent == SDL_EVENT_WINDOW_MOVED ||
             windowevent == SDL_EVENT_WINDOW_RESIZED ||
@@ -291,7 +299,7 @@ bool SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent, int data
     if (windowevent == SDL_EVENT_WINDOW_CLOSE_REQUESTED && !window->parent && !SDL_HasActiveTrays()) {
         int toplevel_count = 0;
         SDL_Window *n;
-        for (n = SDL_GetVideoDevice()->windows; n; n = n->next) {
+        for (n = _this->windows; n; n = n->next) {
             if (!n->parent && !(n->flags & SDL_WINDOW_HIDDEN)) {
                 ++toplevel_count;
             }
diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index 27819d4e7c038..06b88b3642ffe 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -422,6 +422,7 @@ struct SDL_VideoDevice
     Uint32 device_caps;
     SDL_SystemTheme system_theme;
     bool screen_keyboard_shown;
+    bool is_quitting;
 
     /* * * */
     // Data used by the GL drivers
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 4f9bb6a437c86..2bae47e1a1aee 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -4627,6 +4627,8 @@ void SDL_VideoQuit(void)
         return;
     }
 
+    _this->is_quitting = true;
+
     // Halt event processing before doing anything else
 #if 0 // This was moved to the end to fix a memory leak
     SDL_QuitPen();