From db4e6c1931d0d63d0ffed34d1d409699f921c3bb Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 24 Feb 2025 15:01:53 -0800 Subject: [PATCH] Cocoa metal layers need their size updated before renderer updates Also refactored event watch code so it can be shared between internal window event dispatch and public event watchers. Fixes https://github.com/libsdl-org/SDL/issues/12376 --- VisualC-GDK/SDL/SDL.vcxproj | 2 + VisualC-GDK/SDL/SDL.vcxproj.filters | 2 + VisualC/SDL/SDL.vcxproj | 2 + VisualC/SDL/SDL.vcxproj.filters | 6 + Xcode/SDL/SDL.xcodeproj/project.pbxproj | 30 +++-- src/events/SDL_events.c | 140 +++++------------------ src/events/SDL_eventwatch.c | 143 ++++++++++++++++++++++++ src/events/SDL_eventwatch_c.h | 45 ++++++++ src/events/SDL_windowevents.c | 37 +++++- src/events/SDL_windowevents_c.h | 11 ++ src/render/SDL_render.c | 11 +- src/render/SDL_sysrender.h | 3 - src/video/cocoa/SDL_cocoametalview.m | 6 +- 13 files changed, 301 insertions(+), 137 deletions(-) create mode 100644 src/events/SDL_eventwatch.c create mode 100644 src/events/SDL_eventwatch_c.h diff --git a/VisualC-GDK/SDL/SDL.vcxproj b/VisualC-GDK/SDL/SDL.vcxproj index 09563a63d3..5bf000436f 100644 --- a/VisualC-GDK/SDL/SDL.vcxproj +++ b/VisualC-GDK/SDL/SDL.vcxproj @@ -442,6 +442,7 @@ + @@ -676,6 +677,7 @@ + diff --git a/VisualC-GDK/SDL/SDL.vcxproj.filters b/VisualC-GDK/SDL/SDL.vcxproj.filters index dd2c4639cf..f760877e21 100644 --- a/VisualC-GDK/SDL/SDL.vcxproj.filters +++ b/VisualC-GDK/SDL/SDL.vcxproj.filters @@ -39,6 +39,7 @@ + @@ -333,6 +334,7 @@ + diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj index 07a16f7079..a15978a29c 100644 --- a/VisualC/SDL/SDL.vcxproj +++ b/VisualC/SDL/SDL.vcxproj @@ -354,6 +354,7 @@ + @@ -558,6 +559,7 @@ + diff --git a/VisualC/SDL/SDL.vcxproj.filters b/VisualC/SDL/SDL.vcxproj.filters index c0a23b4318..d653ee05f1 100644 --- a/VisualC/SDL/SDL.vcxproj.filters +++ b/VisualC/SDL/SDL.vcxproj.filters @@ -534,6 +534,9 @@ events + + events + events @@ -1076,6 +1079,9 @@ events + + events + events diff --git a/Xcode/SDL/SDL.xcodeproj/project.pbxproj b/Xcode/SDL/SDL.xcodeproj/project.pbxproj index 8e4f9fa033..2a63a2eead 100644 --- a/Xcode/SDL/SDL.xcodeproj/project.pbxproj +++ b/Xcode/SDL/SDL.xcodeproj/project.pbxproj @@ -512,6 +512,8 @@ F3D46B122D20625800D9CBDF /* SDL_egl.h in Headers */ = {isa = PBXBuildFile; fileRef = F3D46A8E2D20625800D9CBDF /* SDL_egl.h */; settings = {ATTRIBUTES = (Public, ); }; }; F3D46B132D20625800D9CBDF /* SDL_filesystem.h in Headers */ = {isa = PBXBuildFile; fileRef = F3D46A922D20625800D9CBDF /* SDL_filesystem.h */; settings = {ATTRIBUTES = (Public, ); }; }; F3D60A8328C16A1900788A3A /* SDL_hidapi_wii.c in Sources */ = {isa = PBXBuildFile; fileRef = F3D60A8228C16A1800788A3A /* SDL_hidapi_wii.c */; }; + F3D8BDFC2D6D2C7000B22FA1 /* SDL_eventwatch_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3D8BDFB2D6D2C7000B22FA1 /* SDL_eventwatch_c.h */; }; + F3D8BDFD2D6D2C7000B22FA1 /* SDL_eventwatch.c in Sources */ = {isa = PBXBuildFile; fileRef = F3D8BDFA2D6D2C7000B22FA1 /* SDL_eventwatch.c */; }; F3DDCC562AFD42B600B0842B /* SDL_clipboard_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3DDCC4D2AFD42B500B0842B /* SDL_clipboard_c.h */; }; F3DDCC5B2AFD42B600B0842B /* SDL_video_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3DDCC522AFD42B600B0842B /* SDL_video_c.h */; }; F3DDCC5D2AFD42B600B0842B /* SDL_rect_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = F3DDCC542AFD42B600B0842B /* SDL_rect_impl.h */; }; @@ -1079,6 +1081,8 @@ F3D46AC82D20625800D9CBDF /* SDL_video.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_video.h; sourceTree = ""; }; F3D46AC92D20625800D9CBDF /* SDL_vulkan.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_vulkan.h; sourceTree = ""; }; F3D60A8228C16A1800788A3A /* SDL_hidapi_wii.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_wii.c; sourceTree = ""; }; + F3D8BDFA2D6D2C7000B22FA1 /* SDL_eventwatch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_eventwatch.c; sourceTree = ""; }; + F3D8BDFB2D6D2C7000B22FA1 /* SDL_eventwatch_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_eventwatch_c.h; sourceTree = ""; }; F3DDCC4D2AFD42B500B0842B /* SDL_clipboard_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_clipboard_c.h; sourceTree = ""; }; F3DDCC522AFD42B600B0842B /* SDL_video_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_video_c.h; sourceTree = ""; }; F3DDCC542AFD42B600B0842B /* SDL_rect_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_rect_impl.h; sourceTree = ""; }; @@ -2209,29 +2213,31 @@ A7D8A93623E2514000DCD162 /* scancodes_linux.h */, A7D8A92C23E2514000DCD162 /* scancodes_windows.h */, A7D8A94123E2514000DCD162 /* scancodes_xfree86.h */, - F3C2CB202C5DDDB2004D7998 /* SDL_categories_c.h */, F3C2CB212C5DDDB2004D7998 /* SDL_categories.c */, - A7D8A93923E2514000DCD162 /* SDL_clipboardevents_c.h */, + F3C2CB202C5DDDB2004D7998 /* SDL_categories_c.h */, A7D8A93A23E2514000DCD162 /* SDL_clipboardevents.c */, - A7D8A93123E2514000DCD162 /* SDL_displayevents_c.h */, + A7D8A93923E2514000DCD162 /* SDL_clipboardevents_c.h */, A7D8A92D23E2514000DCD162 /* SDL_displayevents.c */, - A7D8A92E23E2514000DCD162 /* SDL_dropevents_c.h */, + A7D8A93123E2514000DCD162 /* SDL_displayevents_c.h */, A7D8A93B23E2514000DCD162 /* SDL_dropevents.c */, - A7D8A94223E2514000DCD162 /* SDL_events_c.h */, + A7D8A92E23E2514000DCD162 /* SDL_dropevents_c.h */, A7D8A93523E2514000DCD162 /* SDL_events.c */, - A7D8A93D23E2514000DCD162 /* SDL_keyboard_c.h */, + A7D8A94223E2514000DCD162 /* SDL_events_c.h */, + F3D8BDFA2D6D2C7000B22FA1 /* SDL_eventwatch.c */, + F3D8BDFB2D6D2C7000B22FA1 /* SDL_eventwatch_c.h */, A7D8A93823E2514000DCD162 /* SDL_keyboard.c */, - F31013C62C24E98200FBE946 /* SDL_keymap_c.h */, + A7D8A93D23E2514000DCD162 /* SDL_keyboard_c.h */, F31013C52C24E98200FBE946 /* SDL_keymap.c */, - A7D8A92B23E2514000DCD162 /* SDL_mouse_c.h */, + F31013C62C24E98200FBE946 /* SDL_keymap_c.h */, A7D8A92A23E2514000DCD162 /* SDL_mouse.c */, - 63134A232A7902FD0021E9A6 /* SDL_pen_c.h */, + A7D8A92B23E2514000DCD162 /* SDL_mouse_c.h */, 63134A242A7902FD0021E9A6 /* SDL_pen.c */, + 63134A232A7902FD0021E9A6 /* SDL_pen_c.h */, A7D8A93C23E2514000DCD162 /* SDL_quit.c */, - A7D8A93723E2514000DCD162 /* SDL_touch_c.h */, A7D8A93E23E2514000DCD162 /* SDL_touch.c */, - A7D8A94323E2514000DCD162 /* SDL_windowevents_c.h */, + A7D8A93723E2514000DCD162 /* SDL_touch_c.h */, A7D8A92F23E2514000DCD162 /* SDL_windowevents.c */, + A7D8A94323E2514000DCD162 /* SDL_windowevents_c.h */, ); path = events; sourceTree = ""; @@ -2707,6 +2713,7 @@ A7D8B3D423E2514300DCD162 /* yuv_rgb.h in Headers */, F3FA5A252B59ACE000FEAD97 /* yuv_rgb_common.h in Headers */, F3FA5A1D2B59ACE000FEAD97 /* yuv_rgb_internal.h in Headers */, + F3D8BDFC2D6D2C7000B22FA1 /* SDL_eventwatch_c.h in Headers */, F3FA5A242B59ACE000FEAD97 /* yuv_rgb_lsx.h in Headers */, F3FA5A1E2B59ACE000FEAD97 /* yuv_rgb_lsx_func.h in Headers */, F3FA5A1F2B59ACE000FEAD97 /* yuv_rgb_sse.h in Headers */, @@ -2965,6 +2972,7 @@ 566E26CF246274CC00718109 /* SDL_syslocale.m in Sources */, A7D8AFC023E2514200DCD162 /* SDL_egl.c in Sources */, A7D8AC3323E2514100DCD162 /* SDL_RLEaccel.c in Sources */, + F3D8BDFD2D6D2C7000B22FA1 /* SDL_eventwatch.c in Sources */, F3EFA5F02D5AB97300BCF22F /* SDL_stb.c in Sources */, A7D8BBB123E2514500DCD162 /* SDL_assert.c in Sources */, A7D8B3DA23E2514300DCD162 /* SDL_bmp.c in Sources */, diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c index ebce863bb5..e7216ee408 100644 --- a/src/events/SDL_events.c +++ b/src/events/SDL_events.c @@ -23,6 +23,8 @@ // General event handling code for SDL #include "SDL_events_c.h" +#include "SDL_eventwatch_c.h" +#include "SDL_windowevents_c.h" #include "../SDL_hints_c.h" #include "../audio/SDL_audio_c.h" #include "../camera/SDL_camera_c.h" @@ -98,19 +100,7 @@ typedef struct SDL2_SysWMmsg } msg; } SDL2_SysWMmsg; -typedef struct SDL_EventWatcher -{ - SDL_EventFilter callback; - void *userdata; - bool removed; -} SDL_EventWatcher; - -static SDL_Mutex *SDL_event_watchers_lock; -static SDL_EventWatcher SDL_EventOK; -static SDL_EventWatcher *SDL_event_watchers = NULL; -static int SDL_event_watchers_count = 0; -static bool SDL_event_watchers_dispatching = false; -static bool SDL_event_watchers_removed = false; +static SDL_EventWatchList SDL_event_watchers; static SDL_AtomicInt SDL_sentinel_pending; static Uint32 SDL_last_event_id = 0; @@ -938,16 +928,8 @@ void SDL_StopEventLoop(void) SDL_disabled_events[i] = NULL; } - if (SDL_event_watchers_lock) { - SDL_DestroyMutex(SDL_event_watchers_lock); - SDL_event_watchers_lock = NULL; - } - if (SDL_event_watchers) { - SDL_free(SDL_event_watchers); - SDL_event_watchers = NULL; - SDL_event_watchers_count = 0; - } - SDL_zero(SDL_EventOK); + SDL_QuitEventWatchList(&SDL_event_watchers); + SDL_QuitWindowEventWatch(); SDL_Mutex *lock = NULL; if (SDL_EventQ.lock) { @@ -981,17 +963,19 @@ bool SDL_StartEventLoop(void) } SDL_LockMutex(SDL_EventQ.lock); - if (SDL_event_watchers_lock == NULL) { - SDL_event_watchers_lock = SDL_CreateMutex(); - if (SDL_event_watchers_lock == NULL) { - SDL_UnlockMutex(SDL_EventQ.lock); - return false; - } + if (!SDL_InitEventWatchList(&SDL_event_watchers)) { + SDL_UnlockMutex(SDL_EventQ.lock); + return false; } #endif // !SDL_THREADS_DISABLED + SDL_InitWindowEventWatch(); + SDL_EventQ.active = true; + +#ifndef SDL_THREADS_DISABLED SDL_UnlockMutex(SDL_EventQ.lock); +#endif return true; } @@ -1735,44 +1719,11 @@ bool SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS) static bool SDL_CallEventWatchers(SDL_Event *event) { - if ((SDL_EventOK.callback || SDL_event_watchers_count > 0) && - (event->common.type != SDL_EVENT_POLL_SENTINEL)) { - SDL_LockMutex(SDL_event_watchers_lock); - { - if (SDL_EventOK.callback && !SDL_EventOK.callback(SDL_EventOK.userdata, event)) { - SDL_UnlockMutex(SDL_event_watchers_lock); - return false; - } - - if (SDL_event_watchers_count > 0) { - // Make sure we only dispatch the current watcher list - int i, event_watchers_count = SDL_event_watchers_count; - - SDL_event_watchers_dispatching = true; - for (i = 0; i < event_watchers_count; ++i) { - if (!SDL_event_watchers[i].removed) { - SDL_event_watchers[i].callback(SDL_event_watchers[i].userdata, event); - } - } - SDL_event_watchers_dispatching = false; - - if (SDL_event_watchers_removed) { - for (i = SDL_event_watchers_count; i--;) { - if (SDL_event_watchers[i].removed) { - --SDL_event_watchers_count; - if (i < SDL_event_watchers_count) { - SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i + 1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i])); - } - } - } - SDL_event_watchers_removed = false; - } - } - } - SDL_UnlockMutex(SDL_event_watchers_lock); + if (event->common.type == SDL_EVENT_POLL_SENTINEL) { + return true; } - return true; + return SDL_DispatchEventWatchList(&SDL_event_watchers, event); } bool SDL_PushEvent(SDL_Event *event) @@ -1796,11 +1747,11 @@ bool SDL_PushEvent(SDL_Event *event) void SDL_SetEventFilter(SDL_EventFilter filter, void *userdata) { SDL_EventEntry *event, *next; - SDL_LockMutex(SDL_event_watchers_lock); + SDL_LockMutex(SDL_event_watchers.lock); { // Set filter and discard pending events - SDL_EventOK.callback = filter; - SDL_EventOK.userdata = userdata; + SDL_event_watchers.filter.callback = filter; + SDL_event_watchers.filter.userdata = userdata; if (filter) { // Cut all events not accepted by the filter SDL_LockMutex(SDL_EventQ.lock); @@ -1815,18 +1766,18 @@ void SDL_SetEventFilter(SDL_EventFilter filter, void *userdata) SDL_UnlockMutex(SDL_EventQ.lock); } } - SDL_UnlockMutex(SDL_event_watchers_lock); + SDL_UnlockMutex(SDL_event_watchers.lock); } bool SDL_GetEventFilter(SDL_EventFilter *filter, void **userdata) { SDL_EventWatcher event_ok; - SDL_LockMutex(SDL_event_watchers_lock); + SDL_LockMutex(SDL_event_watchers.lock); { - event_ok = SDL_EventOK; + event_ok = SDL_event_watchers.filter; } - SDL_UnlockMutex(SDL_event_watchers_lock); + SDL_UnlockMutex(SDL_event_watchers.lock); if (filter) { *filter = event_ok.callback; @@ -1839,53 +1790,12 @@ bool SDL_GetEventFilter(SDL_EventFilter *filter, void **userdata) bool SDL_AddEventWatch(SDL_EventFilter filter, void *userdata) { - bool result = true; - - SDL_LockMutex(SDL_event_watchers_lock); - { - SDL_EventWatcher *event_watchers; - - event_watchers = (SDL_EventWatcher *)SDL_realloc(SDL_event_watchers, (SDL_event_watchers_count + 1) * sizeof(*event_watchers)); - if (event_watchers) { - SDL_EventWatcher *watcher; - - SDL_event_watchers = event_watchers; - watcher = &SDL_event_watchers[SDL_event_watchers_count]; - watcher->callback = filter; - watcher->userdata = userdata; - watcher->removed = false; - ++SDL_event_watchers_count; - } else { - result = false; - } - } - SDL_UnlockMutex(SDL_event_watchers_lock); - - return result; + return SDL_AddEventWatchList(&SDL_event_watchers, filter, userdata); } void SDL_RemoveEventWatch(SDL_EventFilter filter, void *userdata) { - SDL_LockMutex(SDL_event_watchers_lock); - { - int i; - - for (i = 0; i < SDL_event_watchers_count; ++i) { - if (SDL_event_watchers[i].callback == filter && SDL_event_watchers[i].userdata == userdata) { - if (SDL_event_watchers_dispatching) { - SDL_event_watchers[i].removed = true; - SDL_event_watchers_removed = true; - } else { - --SDL_event_watchers_count; - if (i < SDL_event_watchers_count) { - SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i + 1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i])); - } - } - break; - } - } - } - SDL_UnlockMutex(SDL_event_watchers_lock); + SDL_RemoveEventWatchList(&SDL_event_watchers, filter, userdata); } void SDL_FilterEvents(SDL_EventFilter filter, void *userdata) diff --git a/src/events/SDL_eventwatch.c b/src/events/SDL_eventwatch.c new file mode 100644 index 0000000000..08e7248c6a --- /dev/null +++ b/src/events/SDL_eventwatch.c @@ -0,0 +1,143 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#include "SDL_eventwatch_c.h" + + +bool SDL_InitEventWatchList(SDL_EventWatchList *list) +{ + if (list->lock == NULL) { + list->lock = SDL_CreateMutex(); + if (list->lock == NULL) { + return false; + } + } + return true; +} + +void SDL_QuitEventWatchList(SDL_EventWatchList *list) +{ + if (list->lock) { + SDL_DestroyMutex(list->lock); + list->lock = NULL; + } + if (list->watchers) { + SDL_free(list->watchers); + list->watchers = NULL; + list->count = 0; + } + SDL_zero(list->filter); +} + +bool SDL_DispatchEventWatchList(SDL_EventWatchList *list, SDL_Event *event) +{ + SDL_EventWatcher *filter = &list->filter; + + if (!filter->callback && list->count == 0) { + return true; + } + + SDL_LockMutex(list->lock); + { + // Make sure we only dispatch the current watcher list + int i, count = list->count; + + if (filter->callback && !filter->callback(filter->userdata, event)) { + SDL_UnlockMutex(list->lock); + return false; + } + + list->dispatching = true; + for (i = 0; i < count; ++i) { + if (!list->watchers[i].removed) { + list->watchers[i].callback(list->watchers[i].userdata, event); + } + } + list->dispatching = false; + + if (list->removed) { + for (i = list->count; i--;) { + if (list->watchers[i].removed) { + --list->count; + if (i < list->count) { + SDL_memmove(&list->watchers[i], &list->watchers[i + 1], (list->count - i) * sizeof(list->watchers[i])); + } + } + } + list->removed = false; + } + } + SDL_UnlockMutex(list->lock); + + return true; +} + +bool SDL_AddEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata) +{ + bool result = true; + + SDL_LockMutex(list->lock); + { + SDL_EventWatcher *watchers; + + watchers = (SDL_EventWatcher *)SDL_realloc(list->watchers, (list->count + 1) * sizeof(*watchers)); + if (watchers) { + SDL_EventWatcher *watcher; + + list->watchers = watchers; + watcher = &list->watchers[list->count]; + watcher->callback = filter; + watcher->userdata = userdata; + watcher->removed = false; + ++list->count; + } else { + result = false; + } + } + SDL_UnlockMutex(list->lock); + + return result; +} + +void SDL_RemoveEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata) +{ + SDL_LockMutex(list->lock); + { + int i; + + for (i = 0; i < list->count; ++i) { + if (list->watchers[i].callback == filter && list->watchers[i].userdata == userdata) { + if (list->dispatching) { + list->watchers[i].removed = true; + list->removed = true; + } else { + --list->count; + if (i < list->count) { + SDL_memmove(&list->watchers[i], &list->watchers[i + 1], (list->count - i) * sizeof(list->watchers[i])); + } + } + break; + } + } + } + SDL_UnlockMutex(list->lock); +} diff --git a/src/events/SDL_eventwatch_c.h b/src/events/SDL_eventwatch_c.h new file mode 100644 index 0000000000..c9aea38c0d --- /dev/null +++ b/src/events/SDL_eventwatch_c.h @@ -0,0 +1,45 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +typedef struct SDL_EventWatcher +{ + SDL_EventFilter callback; + void *userdata; + bool removed; +} SDL_EventWatcher; + +typedef struct SDL_EventWatchList +{ + SDL_Mutex *lock; + SDL_EventWatcher filter; + SDL_EventWatcher *watchers; + int count; + bool dispatching; + bool removed; +} SDL_EventWatchList; + + +extern bool SDL_InitEventWatchList(SDL_EventWatchList *list); +extern void SDL_QuitEventWatchList(SDL_EventWatchList *list); +extern bool SDL_DispatchEventWatchList(SDL_EventWatchList *list, SDL_Event *event); +extern bool SDL_AddEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata); +extern void SDL_RemoveEventWatchList(SDL_EventWatchList *list, SDL_EventFilter filter, void *userdata); diff --git a/src/events/SDL_windowevents.c b/src/events/SDL_windowevents.c index e0364f8ee0..e20cd3ab0d 100644 --- a/src/events/SDL_windowevents.c +++ b/src/events/SDL_windowevents.c @@ -23,10 +23,39 @@ // Window event handling code for SDL #include "SDL_events_c.h" +#include "SDL_eventwatch_c.h" #include "SDL_mouse_c.h" -#include "../render/SDL_sysrender.h" #include "../tray/SDL_tray_utils.h" + +#define NUM_WINDOW_EVENT_WATCH_PRIORITIES (SDL_WINDOW_EVENT_WATCH_NORMAL + 1) + +static SDL_EventWatchList SDL_window_event_watchers[NUM_WINDOW_EVENT_WATCH_PRIORITIES]; + +void SDL_InitWindowEventWatch(void) +{ + for (int i = 0; i < SDL_arraysize(SDL_window_event_watchers); ++i) { + SDL_InitEventWatchList(&SDL_window_event_watchers[i]); + } +} + +void SDL_QuitWindowEventWatch(void) +{ + for (int i = 0; i < SDL_arraysize(SDL_window_event_watchers); ++i) { + SDL_QuitEventWatchList(&SDL_window_event_watchers[i]); + } +} + +void SDL_AddWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata) +{ + SDL_AddEventWatchList(&SDL_window_event_watchers[priority], filter, userdata); +} + +void SDL_RemoveWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata) +{ + SDL_RemoveEventWatchList(&SDL_window_event_watchers[priority], filter, userdata); +} + static bool SDLCALL RemoveSupercededWindowEvents(void *userdata, SDL_Event *event) { SDL_Event *new_event = (SDL_Event *)userdata; @@ -191,10 +220,8 @@ bool SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent, int data event.window.data2 = data2; event.window.windowID = window->id; - for (int i = 0; i < window->num_renderers; ++i) { - SDL_Renderer *renderer = window->renderers[i]; - SDL_RendererEventWatch(renderer, &event); - } + 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)) { // Fixes queue overflow with move/resize events that aren't processed diff --git a/src/events/SDL_windowevents_c.h b/src/events/SDL_windowevents_c.h index b7f0681e6d..720430546a 100644 --- a/src/events/SDL_windowevents_c.h +++ b/src/events/SDL_windowevents_c.h @@ -23,6 +23,17 @@ #ifndef SDL_windowevents_c_h_ #define SDL_windowevents_c_h_ +typedef enum +{ + SDL_WINDOW_EVENT_WATCH_EARLY, + SDL_WINDOW_EVENT_WATCH_NORMAL +} SDL_WindowEventWatchPriority; + +extern void SDL_InitWindowEventWatch(void); +extern void SDL_QuitWindowEventWatch(void); +extern void SDL_AddWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata); +extern void SDL_RemoveWindowEventWatch(SDL_WindowEventWatchPriority priority, SDL_EventFilter filter, void *userdata); + extern bool SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent, int data1, int data2); #endif // SDL_windowevents_c_h_ diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 4c438debc3..52f0b38257 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -25,6 +25,7 @@ #include "SDL_sysrender.h" #include "SDL_render_debug_font.h" #include "software/SDL_render_sw_c.h" +#include "../events/SDL_windowevents_c.h" #include "../video/SDL_pixels_c.h" #include "../video/SDL_video_c.h" @@ -820,8 +821,9 @@ const char *SDL_GetRenderDriver(int index) #endif } -void SDL_RendererEventWatch(SDL_Renderer *renderer, SDL_Event *event) +static bool SDL_RendererEventWatch(void *userdata, SDL_Event *event) { + SDL_Renderer *renderer = (SDL_Renderer *)userdata; SDL_Window *window = renderer->window; if (renderer->WindowEvent) { @@ -849,6 +851,7 @@ void SDL_RendererEventWatch(SDL_Renderer *renderer, SDL_Event *event) event->type == SDL_EVENT_WINDOW_HDR_STATE_CHANGED) { UpdateHDRProperties(renderer); } + return true; } bool SDL_CreateWindowAndRenderer(const char *title, int width, int height, SDL_WindowFlags window_flags, SDL_Window **window, SDL_Renderer **renderer) @@ -1107,6 +1110,10 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props) SDL_SetRenderViewport(renderer, NULL); + if (window) { + SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, SDL_RendererEventWatch, renderer); + } + int vsync = (int)SDL_GetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0); if (!SDL_SetRenderVSync(renderer, vsync)) { if (vsync == 0) { @@ -5224,6 +5231,8 @@ void SDL_DestroyRendererWithoutFreeing(SDL_Renderer *renderer) renderer->destroyed = true; + SDL_RemoveWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, SDL_RendererEventWatch, renderer); + if (renderer->window) { SDL_PropertiesID props = SDL_GetWindowProperties(renderer->window); if (SDL_GetPointerProperty(props, SDL_PROP_WINDOW_RENDERER_POINTER, NULL) == renderer) { diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index 375419a06a..9c39bb1de7 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -339,9 +339,6 @@ extern SDL_RenderDriver GPU_RenderDriver; // Clean up any renderers at shutdown extern void SDL_QuitRender(void); -// Handle window events for a renderer -extern void SDL_RendererEventWatch(SDL_Renderer *renderer, SDL_Event *event); - // Add a supported texture format to a renderer extern bool SDL_AddSupportedTextureFormat(SDL_Renderer *renderer, SDL_PixelFormat format); diff --git a/src/video/cocoa/SDL_cocoametalview.m b/src/video/cocoa/SDL_cocoametalview.m index d856645115..af84e93586 100644 --- a/src/video/cocoa/SDL_cocoametalview.m +++ b/src/video/cocoa/SDL_cocoametalview.m @@ -26,6 +26,8 @@ */ #include "SDL_internal.h" +#include "../../events/SDL_windowevents_c.h" + #import "SDL_cocoametalview.h" #if defined(SDL_VIDEO_DRIVER_COCOA) && (defined(SDL_VIDEO_VULKAN) || defined(SDL_VIDEO_METAL)) @@ -88,7 +90,7 @@ static bool SDLCALL SDL_MetalViewEventWatch(void *userdata, SDL_Event *event) self.layer.opaque = opaque; - SDL_AddEventWatch(SDL_MetalViewEventWatch, (__bridge void *)(self)); + SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_EARLY, SDL_MetalViewEventWatch, (__bridge void *)(self)); [self updateDrawableSize]; } @@ -98,7 +100,7 @@ static bool SDLCALL SDL_MetalViewEventWatch(void *userdata, SDL_Event *event) - (void)dealloc { - SDL_RemoveEventWatch(SDL_MetalViewEventWatch, (__bridge void *)(self)); + SDL_RemoveWindowEventWatch(SDL_WINDOW_EVENT_WATCH_EARLY, SDL_MetalViewEventWatch, (__bridge void *)(self)); } - (NSInteger)tag