diff --git a/src/plugins/platforms/ios/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h index e7ca2d1fecc..0fafbe19360 100644 --- a/src/plugins/platforms/ios/qiosglobal.h +++ b/src/plugins/platforms/ios/qiosglobal.h @@ -26,6 +26,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow); class QPlatformScreen; bool isQtApplication(); +bool isRunningOnVisionOS(); #ifndef Q_OS_TVOS Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation); diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm index 8d0df38dbe6..eb9e713b0dc 100644 --- a/src/plugins/platforms/ios/qiosglobal.mm +++ b/src/plugins/platforms/ios/qiosglobal.mm @@ -29,6 +29,15 @@ bool isQtApplication() return isQt; } +bool isRunningOnVisionOS() +{ + static bool result = []{ + // This class is documented to only be available on visionOS + return NSClassFromString(@"UIWindowSceneGeometryPreferencesVision"); + }(); + return result; +} + #ifndef Q_OS_TVOS Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation) { diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm index e6f533c4664..d96f7686f5c 100644 --- a/src/plugins/platforms/ios/qiosscreen.mm +++ b/src/plugins/platforms/ios/qiosscreen.mm @@ -310,15 +310,6 @@ QString QIOSScreen::name() const #endif } -[[maybe_unused]] static bool isRunningOnVisionOS() -{ - static bool result = []{ - // This class is documented to only be available on visionOS - return NSClassFromString(@"UIWindowSceneGeometryPreferencesVision"); - }(); - return result; -} - void QIOSScreen::updateProperties() { QRect previousGeometry = m_geometry; @@ -327,26 +318,9 @@ void QIOSScreen::updateProperties() #if defined(Q_OS_VISIONOS) // Based on what iPad app reports m_geometry = QRect(0, 0, 1194, 834); - m_availableGeometry = m_geometry; m_depth = 24; #else m_geometry = QRectF::fromCGRect(m_uiScreen.bounds).toRect(); - m_availableGeometry = m_geometry; - - // For convenience, we reflect the safe area margins of the screen's UIWindow - // by reducing the available geometry of the screen. But we only do this if - // the UIWindow bounds is representative of the UIScreen. - if (isRunningOnVisionOS()) { - // On visionOS there is no concept of a screen, and hence no concept of - // screen-relative system UI that we should keep top level windows away - // from, so don't apply the UIWindow safe area insets to the screen. - } else { - UIEdgeInsets safeAreaInsets = m_uiWindow.safeAreaInsets; - if (m_uiWindow.bounds.size.width == m_uiScreen.bounds.size.width) - m_availableGeometry.adjust(safeAreaInsets.left, 0, -safeAreaInsets.right, 0); - if (m_uiWindow.bounds.size.height == m_uiScreen.bounds.size.height) - m_availableGeometry.adjust(0, safeAreaInsets.top, 0, -safeAreaInsets.bottom); - } #ifndef Q_OS_TVOS if (m_uiScreen == [UIScreen mainScreen]) { @@ -390,6 +364,12 @@ void QIOSScreen::updateProperties() #endif // defined(Q_OS_VISIONOS) + // UIScreen does not provide a consistent accessor for the safe area margins + // of the screen, and on visionOS we won't even have a UIScreen, so we report + // the available geometry of the screen to be the same as the full geometry. + // Safe area margins and maximized state is handled in QIOSWindow::setWindowState. + m_availableGeometry = m_geometry; + // At construction time, we don't yet have an associated QScreen, but we still want // to compute the properties above so they are ready for when the QScreen attaches. // Also, at destruction time the QScreen has already been torn down, so notifying diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 398f8c4a6f9..0f4a6803b3e 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -261,21 +261,34 @@ void QIOSWindow::setWindowState(Qt::WindowStates state) // it to clamp the window geometry. Instead just use the UIWindow // directly, which represents our "screen". applyGeometry(uiWindowBounds); + } else if (isRunningOnVisionOS()) { + // On visionOS there is no concept of a screen, and hence no concept of + // screen-relative system UI that we should keep top level windows away + // from, so don't apply the UIWindow safe area insets to the screen. + applyGeometry(uiWindowBounds); } else { - // When an application is in split-view mode, the UIScreen still has the - // same geometry, but the UIWindow is resized to the area reserved for the - // application. We use this to constrain the geometry used when applying the - // fullscreen or maximized window states. Note that we do not do this - // in applyGeometry(), as we don't want to artificially limit window - // placement "outside" of the screen bounds if that's what the user wants. - QRect fullscreenGeometry = screen()->geometry().intersected(uiWindowBounds); - QRect maximizedGeometry = window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint ? - fullscreenGeometry : screen()->availableGeometry().intersected(uiWindowBounds); + QRect fullscreenGeometry = screen()->geometry(); + QRect maximizedGeometry = fullscreenGeometry; + +#if !defined(Q_OS_VISIONOS) + if (!(window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint)) { + // If the safe area margins reflect the screen's outer edges, + // then reduce the maximized geometry accordingly. Otherwise + // leave it as is, and assume the client will take the safe + // are margins into account explicitly. + UIScreen *uiScreen = m_view.window.windowScene.screen; + UIEdgeInsets safeAreaInsets = m_view.window.safeAreaInsets; + if (m_view.window.bounds.size.width == uiScreen.bounds.size.width) + maximizedGeometry.adjust(safeAreaInsets.left, 0, -safeAreaInsets.right, 0); + if (m_view.window.bounds.size.height == uiScreen.bounds.size.height) + maximizedGeometry.adjust(0, safeAreaInsets.top, 0, -safeAreaInsets.bottom); + } +#endif if (state & Qt::WindowFullScreen) - applyGeometry(fullscreenGeometry); + applyGeometry(fullscreenGeometry.intersected(uiWindowBounds)); else - applyGeometry(maximizedGeometry); + applyGeometry(maximizedGeometry.intersected(uiWindowBounds)); } } else { applyGeometry(m_normalGeometry);