diff options
Diffstat (limited to 'src/plugins/platforms/ios/qioswindow.mm')
-rw-r--r-- | src/plugins/platforms/ios/qioswindow.mm | 110 |
1 files changed, 61 insertions, 49 deletions
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 3631d6be70..7cd3d5f0b0 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -21,7 +21,7 @@ #import <QuartzCore/CAEAGLLayer.h> #endif -#ifdef Q_OS_IOS +#if QT_CONFIG(metal) #import <QuartzCore/CAMetalLayer.h> #endif @@ -36,13 +36,12 @@ enum { QIOSWindow::QIOSWindow(QWindow *window, WId nativeHandle) : QPlatformWindow(window) - , m_windowLevel(0) { if (nativeHandle) { m_view = reinterpret_cast<UIView *>(nativeHandle); [m_view retain]; } else { -#ifdef Q_OS_IOS +#if QT_CONFIG(metal) if (window->surfaceType() == QSurface::RasterSurface) window->setSurfaceType(QSurface::MetalSurface); @@ -55,6 +54,9 @@ QIOSWindow::QIOSWindow(QWindow *window, WId nativeHandle) connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &QIOSWindow::applicationStateChanged); + // Always set parent, even if we don't have a parent window, + // as we use setParent to reparent top levels into our desktop + // manager view. setParent(QPlatformWindow::parent()); if (!isForeignWindow()) { @@ -124,11 +126,6 @@ void QIOSWindow::setVisible(bool visible) if (!isQtApplication() || !window()->isTopLevel()) return; - // Since iOS doesn't do window management the way a Qt application - // expects, we need to raise and activate windows ourselves: - if (visible) - updateWindowLevel(); - if (blockedByModal()) { if (visible) raise(); @@ -261,21 +258,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); @@ -284,14 +294,14 @@ void QIOSWindow::setWindowState(Qt::WindowStates state) void QIOSWindow::setParent(const QPlatformWindow *parentWindow) { - UIView *parentView = parentWindow ? - reinterpret_cast<UIView *>(parentWindow->winId()) - : isQtApplication() && !isForeignWindow() ? - static_cast<QIOSScreen *>(screen())->uiWindow().rootViewController.view - : nullptr; - - if (parentView) - [parentView addSubview:m_view]; + UIView *superview = nullptr; + if (parentWindow) + superview = reinterpret_cast<UIView *>(parentWindow->winId()); + else if (isQtApplication() && !isForeignWindow()) + superview = rootViewForScreen(window()->screen()); + + if (superview) + [superview addSubview:m_view]; else if (quiview_cast(m_view.superview)) [m_view removeFromSuperview]; } @@ -304,7 +314,6 @@ void QIOSWindow::requestActivateWindow() if (blockedByModal()) return; - Q_ASSERT(m_view.window); [m_view.window makeKeyWindow]; [m_view becomeFirstResponder]; @@ -328,8 +337,8 @@ void QIOSWindow::raiseOrLower(bool raise) UIView *view = static_cast<UIView *>([subviews objectAtIndex:i]); if (view.hidden || view == m_view || !view.qwindow) continue; - int level = static_cast<QIOSWindow *>(view.qwindow->handle())->m_windowLevel; - if (m_windowLevel > level || (raise && m_windowLevel == level)) { + int level = static_cast<QIOSWindow *>(view.qwindow->handle())->windowLevel(); + if (windowLevel() > level || (raise && windowLevel() == level)) { [m_view.superview insertSubview:m_view aboveSubview:view]; return; } @@ -344,40 +353,34 @@ void QIOSWindow::raiseOrLower(bool raise) } } -void QIOSWindow::updateWindowLevel() +int QIOSWindow::windowLevel() const { Qt::WindowType type = window()->type(); + int level = 0; + if (type == Qt::ToolTip) - m_windowLevel = 120; + level = 120; else if (window()->flags() & Qt::WindowStaysOnTopHint) - m_windowLevel = 100; + level = 100; else if (window()->isModal()) - m_windowLevel = 40; + level = 40; else if (type == Qt::Popup) - m_windowLevel = 30; + level = 30; else if (type == Qt::SplashScreen) - m_windowLevel = 20; + level = 20; else if (type == Qt::Tool) - m_windowLevel = 10; + level = 10; else - m_windowLevel = 0; + level = 0; - // A window should be in at least the same m_windowLevel as its parent: + // A window should be in at least the same window level as its parent QWindow *transientParent = window()->transientParent(); QIOSWindow *transientParentWindow = transientParent ? static_cast<QIOSWindow *>(transientParent->handle()) : 0; if (transientParentWindow) - m_windowLevel = qMax(transientParentWindow->m_windowLevel, m_windowLevel); -} + level = qMax(transientParentWindow->windowLevel(), level); -void QIOSWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation) -{ - // Update the QWindow representation straight away, so that - // we can update the statusbar orientation based on the new - // content orientation. - qt_window_private(window())->contentOrientation = orientation; - - [m_view.qtViewController updateProperties]; + return level; } void QIOSWindow::applicationStateChanged(Qt::ApplicationState) @@ -391,6 +394,15 @@ void QIOSWindow::applicationStateChanged(Qt::ApplicationState) qreal QIOSWindow::devicePixelRatio() const { +#if !defined(Q_OS_VISIONOS) + // If the view has not yet been added to a screen, it will not + // pick up its device pixel ratio, so we need to do so manually + // based on the screen we think the window will be added to. + if (!m_view.window.windowScene.screen) + return screen()->devicePixelRatio(); +#endif + + // Otherwise we can rely on the content scale factor return m_view.contentScaleFactor; } |