From c717a20ec87a17ef79b00519e187d6985040a1ea Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 17 Mar 2026 12:25:13 -0700
Subject: [PATCH] Fixed initial window size and placement on visionOS
---
src/video/uikit/SDL_uikitmetalview.m | 5 +++++
src/video/uikit/SDL_uikitvideo.m | 4 +++-
src/video/uikit/SDL_uikitwindow.m | 21 +++++++++++++++++----
3 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/src/video/uikit/SDL_uikitmetalview.m b/src/video/uikit/SDL_uikitmetalview.m
index da0a8edd4ff7b..596b311165d81 100644
--- a/src/video/uikit/SDL_uikitmetalview.m
+++ b/src/video/uikit/SDL_uikitmetalview.m
@@ -69,6 +69,11 @@ - (void)updateDrawableSize
size.width *= self.layer.contentsScale;
size.height *= self.layer.contentsScale;
+ // Skip invalid sizes (can happen on visionOS before scene geometry is applied)
+ if (size.width <= 0 || size.height <= 0) {
+ return;
+ }
+
CAMetalLayer *metallayer = ((CAMetalLayer *)self.layer);
if (metallayer.drawableSize.width != size.width ||
metallayer.drawableSize.height != size.height) {
diff --git a/src/video/uikit/SDL_uikitvideo.m b/src/video/uikit/SDL_uikitvideo.m
index 43fab3afcdbd1..d31f70a13d572 100644
--- a/src/video/uikit/SDL_uikitvideo.m
+++ b/src/video/uikit/SDL_uikitvideo.m
@@ -213,7 +213,9 @@ SDL_SystemTheme UIKit_GetSystemTheme(void)
#ifdef SDL_PLATFORM_VISIONOS
CGRect UIKit_ComputeViewFrame(SDL_Window *window)
{
- return CGRectMake(window->x, window->y, window->w, window->h);
+ // View origin is always (0,0) relative to the UIWindow.
+ // window->x/y are screen-level positions (often SDL_WINDOWPOS_UNDEFINED).
+ return CGRectMake(0, 0, window->w, window->h);
}
#else
CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen)
diff --git a/src/video/uikit/SDL_uikitwindow.m b/src/video/uikit/SDL_uikitwindow.m
index dd6dc27bd7d1f..3f1f1b464d246 100644
--- a/src/video/uikit/SDL_uikitwindow.m
+++ b/src/video/uikit/SDL_uikitwindow.m
@@ -186,6 +186,23 @@ bool UIKit_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properti
}
if (scene) {
uiwindow = [[UIWindow alloc] initWithWindowScene:scene];
+
+#ifdef SDL_PLATFORM_VISIONOS
+ /* On visionOS, the window scene may not have its final geometry yet
+ * when the UIWindow is first created. Request the desired size now
+ * and set the UIWindow frame to match so views have valid initial
+ * dimensions before the async geometry update completes. */
+ CGSize desiredSize = CGSizeMake(window->w, window->h);
+ uiwindow.frame = CGRectMake(0, 0, desiredSize.width, desiredSize.height);
+
+ UIWindowSceneGeometryPreferences *preferences =
+ [[UIWindowSceneGeometryPreferencesVision alloc] initWithSize:desiredSize];
+ [scene requestGeometryUpdateWithPreferences:preferences errorHandler:^(NSError * _Nonnull error) {
+ SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO,
+ "Initial geometry request failed: %s",
+ [[error localizedDescription] UTF8String]);
+ }];
+#endif
}
}
if (!uiwindow) {
@@ -214,10 +231,6 @@ bool UIKit_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properti
if (!SetupWindowData(_this, window, uiwindow, true)) {
return false;
}
-
-#ifdef SDL_PLATFORM_VISIONOS
- SDL_SetWindowSize(window, window->w, window->h);
-#endif
}
return true;