SDL: cocoa: fixed resizing windows with fixed aspect ratio

From 19954719278c612aa41055483a090ece37ad7e79 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 15 Jan 2025 09:36:55 -0800
Subject: [PATCH] cocoa: fixed resizing windows with fixed aspect ratio

The existing algorithm works well for min-max ratios, but didn't allow edge expansion of fixed aspect ratio windows. Use NSWindow setContentAspectRatio instead.
---
 src/video/cocoa/SDL_cocoavideo.m  |  1 +
 src/video/cocoa/SDL_cocoawindow.h |  1 +
 src/video/cocoa/SDL_cocoawindow.m | 21 ++++++++++++++++++---
 3 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m
index b9977c441bc91..aae54ebad8d96 100644
--- a/src/video/cocoa/SDL_cocoavideo.m
+++ b/src/video/cocoa/SDL_cocoavideo.m
@@ -103,6 +103,7 @@ static void Cocoa_DeleteDevice(SDL_VideoDevice *device)
         device->SetWindowSize = Cocoa_SetWindowSize;
         device->SetWindowMinimumSize = Cocoa_SetWindowMinimumSize;
         device->SetWindowMaximumSize = Cocoa_SetWindowMaximumSize;
+        device->SetWindowAspectRatio = Cocoa_SetWindowAspectRatio;
         device->SetWindowOpacity = Cocoa_SetWindowOpacity;
         device->GetWindowSizeInPixels = Cocoa_GetWindowSizeInPixels;
         device->ShowWindow = Cocoa_ShowWindow;
diff --git a/src/video/cocoa/SDL_cocoawindow.h b/src/video/cocoa/SDL_cocoawindow.h
index af567b8af2899..6df69f442a080 100644
--- a/src/video/cocoa/SDL_cocoawindow.h
+++ b/src/video/cocoa/SDL_cocoawindow.h
@@ -168,6 +168,7 @@ extern bool Cocoa_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window);
 extern void Cocoa_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window);
 extern void Cocoa_SetWindowMinimumSize(SDL_VideoDevice *_this, SDL_Window *window);
 extern void Cocoa_SetWindowMaximumSize(SDL_VideoDevice *_this, SDL_Window *window);
+extern void Cocoa_SetWindowAspectRatio(SDL_VideoDevice *_this, SDL_Window *window);
 extern void Cocoa_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h);
 extern bool Cocoa_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opacity);
 extern void Cocoa_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window);
diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m
index 947db1e976c42..daa544f7a43c0 100644
--- a/src/video/cocoa/SDL_cocoawindow.m
+++ b/src/video/cocoa/SDL_cocoawindow.m
@@ -1109,7 +1109,7 @@ - (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize
 {
     SDL_Window *window = _data.window;
 
-    if (window->min_aspect > 0.0f || window->max_aspect > 0.0f) {
+    if (window->min_aspect != window->max_aspect) {
         NSWindow *nswindow = _data.nswindow;
         NSRect newContentRect = [nswindow contentRectForFrameRect:NSMakeRect(0, 0, frameSize.width, frameSize.height)];
         NSSize newSize = newContentRect.size;
@@ -1121,9 +1121,9 @@ - (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize
             aspectRatio = newSize.width / newSize.height;
 
             if (maxAspectRatio > 0.0f && aspectRatio > maxAspectRatio) {
-                newSize.width = (int)SDL_roundf(newSize.height * maxAspectRatio);
+                newSize.width = SDL_roundf(newSize.height * maxAspectRatio);
             } else if (minAspectRatio > 0.0f && aspectRatio < minAspectRatio) {
-                newSize.height = (int)SDL_roundf(newSize.width / minAspectRatio);
+                newSize.height = SDL_roundf(newSize.width / minAspectRatio);
             }
 
             NSRect newFrameRect = [nswindow frameRectForContentRect:NSMakeRect(0, 0, newSize.width, newSize.height)];
@@ -2515,6 +2515,21 @@ void Cocoa_SetWindowMaximumSize(SDL_VideoDevice *_this, SDL_Window *window)
     }
 }
 
+void Cocoa_SetWindowAspectRatio(SDL_VideoDevice *_this, SDL_Window *window)
+{
+    @autoreleasepool {
+        SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)window->internal;
+
+        if (window->min_aspect > 0.0f && window->min_aspect == window->max_aspect) {
+            int numerator = 0, denominator = 1;
+            SDL_CalculateFraction(window->max_aspect, &numerator, &denominator);
+            [windata.nswindow setContentAspectRatio:NSMakeSize(numerator, denominator)];
+        } else {
+            [windata.nswindow setContentAspectRatio:NSMakeSize(0, 0)];
+        }
+    }
+}
+
 void Cocoa_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h)
 {
     @autoreleasepool {