From 9a43c08146a765fca166586e9739eb26c5309346 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 23 Dec 2024 11:09:46 -0800 Subject: [PATCH] Allow rendering during the modal resize loop on macOS Fixes https://github.com/libsdl-org/SDL/issues/11508 --- src/video/SDL_sysvideo.h | 1 + src/video/SDL_video.c | 11 ++++++++++ src/video/cocoa/SDL_cocoawindow.h | 4 ++++ src/video/cocoa/SDL_cocoawindow.m | 29 +++++++++++++++++++++++++-- src/video/windows/SDL_windowsevents.c | 7 +------ 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 51d991f1df..2633f5e067 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -568,6 +568,7 @@ extern void SDL_OnWindowMoved(SDL_Window *window); extern void SDL_OnWindowResized(SDL_Window *window); extern void SDL_CheckWindowPixelSizeChanged(SDL_Window *window); extern void SDL_OnWindowPixelSizeChanged(SDL_Window *window); +extern void SDL_OnWindowLiveResizeUpdate(SDL_Window *window); extern void SDL_OnWindowMinimized(SDL_Window *window); extern void SDL_OnWindowMaximized(SDL_Window *window); extern void SDL_OnWindowRestored(SDL_Window *window); diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 75b2a8df9e..3d539d3e42 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -35,6 +35,7 @@ #include "../timer/SDL_timer_c.h" #include "../camera/SDL_camera_c.h" #include "../render/SDL_sysrender.h" +#include "../main/SDL_main_callbacks.h" #ifdef SDL_VIDEO_OPENGL #include @@ -3920,6 +3921,16 @@ void SDL_OnWindowPixelSizeChanged(SDL_Window *window) window->surface_valid = false; } +void SDL_OnWindowLiveResizeUpdate(SDL_Window *window) +{ + if (SDL_HasMainCallbacks()) { + SDL_IterateMainCallbacks(false); + } else { + // Send an expose event so the application can redraw + SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_EXPOSED, 0, 0); + } +} + static void SDL_CheckWindowSafeAreaChanged(SDL_Window *window) { SDL_Rect rect; diff --git a/src/video/cocoa/SDL_cocoawindow.h b/src/video/cocoa/SDL_cocoawindow.h index 9add0c0e58..83d6fe8564 100644 --- a/src/video/cocoa/SDL_cocoawindow.h +++ b/src/video/cocoa/SDL_cocoawindow.h @@ -59,6 +59,7 @@ typedef enum NSInteger focusClickPending; float pendingWindowWarpX, pendingWindowWarpY; BOOL isDragAreaRunning; + NSTimer *liveResizeTimer; } - (BOOL)isTouchFromTrackpad:(NSEvent *)theEvent; @@ -83,6 +84,9 @@ typedef enum // Window delegate functionality - (BOOL)windowShouldClose:(id)sender; - (void)windowDidExpose:(NSNotification *)aNotification; +- (void)windowDidChangeOcclusionState:(NSNotification *)aNotification; +- (void)windowWillStartLiveResize:(NSNotification *)aNotification; +- (void)windowDidEndLiveResize:(NSNotification *)aNotification; - (void)windowDidMove:(NSNotification *)aNotification; - (void)windowDidResize:(NSNotification *)aNotification; - (void)windowDidMiniaturize:(NSNotification *)aNotification; diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 55dfe2cb1b..c4512033fd 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -696,11 +696,15 @@ static NSCursor *Cocoa_GetDesiredCursor(void) isMiniaturizing = NO; isDragAreaRunning = NO; pendingWindowWarpX = pendingWindowWarpY = FLT_MAX; + liveResizeTimer = nil; center = [NSNotificationCenter defaultCenter]; if ([window delegate] != nil) { [center addObserver:self selector:@selector(windowDidExpose:) name:NSWindowDidExposeNotification object:window]; + [center addObserver:self selector:@selector(windowDidChangeOcclusionState:) name:NSWindowDidChangeOcclusionStateNotification object:window]; + [center addObserver:self selector:@selector(windowWillStartLiveResize:) name:NSWindowWillStartLiveResizeNotification object:window]; + [center addObserver:self selector:@selector(windowDidEndLiveResize:) name:NSWindowDidEndLiveResizeNotification object:window]; [center addObserver:self selector:@selector(windowWillMove:) name:NSWindowWillMoveNotification object:window]; [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:window]; [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:window]; @@ -718,7 +722,6 @@ static NSCursor *Cocoa_GetDesiredCursor(void) [center addObserver:self selector:@selector(windowDidExitFullScreen:) name:NSWindowDidExitFullScreenNotification object:window]; [center addObserver:self selector:@selector(windowDidFailToEnterFullScreen:) name:@"NSWindowDidFailToEnterFullScreenNotification" object:window]; [center addObserver:self selector:@selector(windowDidFailToExitFullScreen:) name:@"NSWindowDidFailToExitFullScreenNotification" object:window]; - [center addObserver:self selector:@selector(windowDidChangeOcclusionState:) name:NSWindowDidChangeOcclusionStateNotification object:window]; } else { [window setDelegate:self]; } @@ -853,6 +856,9 @@ static NSCursor *Cocoa_GetDesiredCursor(void) if ([window delegate] != self) { [center removeObserver:self name:NSWindowDidExposeNotification object:window]; + [center removeObserver:self name:NSWindowDidChangeOcclusionStateNotification object:window]; + [center removeObserver:self name:NSWindowWillStartLiveResizeNotification object:window]; + [center removeObserver:self name:NSWindowDidEndLiveResizeNotification object:window]; [center removeObserver:self name:NSWindowWillMoveNotification object:window]; [center removeObserver:self name:NSWindowDidMoveNotification object:window]; [center removeObserver:self name:NSWindowDidResizeNotification object:window]; @@ -870,7 +876,6 @@ static NSCursor *Cocoa_GetDesiredCursor(void) [center removeObserver:self name:NSWindowDidExitFullScreenNotification object:window]; [center removeObserver:self name:@"NSWindowDidFailToEnterFullScreenNotification" object:window]; [center removeObserver:self name:@"NSWindowDidFailToExitFullScreenNotification" object:window]; - [center removeObserver:self name:NSWindowDidChangeOcclusionStateNotification object:window]; } else { [window setDelegate:nil]; } @@ -997,6 +1002,26 @@ static NSCursor *Cocoa_GetDesiredCursor(void) } } +- (void)windowWillStartLiveResize:(NSNotification *)aNotification +{ + // We'll try to maintain 60 FPS during live resizing + const NSTimeInterval interval = 1.0 / 60.0; + liveResizeTimer = [NSTimer scheduledTimerWithTimeInterval:interval + repeats:TRUE + block:^(NSTimer *unusedTimer) + { + SDL_OnWindowLiveResizeUpdate(_data.window); + }]; + + [[NSRunLoop currentRunLoop] addTimer:liveResizeTimer forMode:NSRunLoopCommonModes]; +} + +- (void)windowDidEndLiveResize:(NSNotification *)aNotification +{ + [liveResizeTimer invalidate]; + liveResizeTimer = nil; +} + - (void)windowWillMove:(NSNotification *)aNotification { if ([_data.nswindow isKindOfClass:[SDL3Window class]]) { diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index fef4ac4a71..4802303cca 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -1541,12 +1541,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara case WM_TIMER: { if (wParam == (UINT_PTR)SDL_IterateMainCallbacks) { - if (SDL_HasMainCallbacks()) { - SDL_IterateMainCallbacks(false); - } else { - // Send an expose event so the application can redraw - SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_EXPOSED, 0, 0); - } + SDL_OnWindowLiveResizeUpdate(data->window); return 0; } } break;