From db33628452c5ccbf07b901405fba74525f7192c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 13 Nov 2023 11:12:50 +0100 Subject: [PATCH] Ensure foreign window can be reparented out of contained window again A foreign window embedded into a Qt hierarchy must also support being removed from that window hierarchy. Pick-to: 6.6 Change-Id: Id4d08079ff19d67a8989937bc72602e8bd14b31b Reviewed-by: Richard Moe Gustavsen --- src/plugins/platforms/cocoa/qcocoawindow.mm | 10 ++++++---- src/plugins/platforms/ios/qioswindow.mm | 12 +++++++++--- tests/auto/gui/kernel/qwindow/tst_foreignwindow.cpp | 9 ++++++++- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 3fbc06a089..748b8ef1c6 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1499,6 +1499,10 @@ void QCocoaWindow::recreateWindowIfNeeded() QPlatformWindow *parentWindow = QPlatformWindow::parent(); auto *parentCocoaWindow = static_cast(parentWindow); + QCocoaWindow *oldParentCocoaWindow = nullptr; + if (QNSView *qnsView = qnsview_cast(m_view.superview)) + oldParentCocoaWindow = qnsView.platformWindow; + if (isForeignWindow()) { // A foreign window is created as such, and can never move between being // foreign and not, so we don't need to get rid of any existing NSWindows, @@ -1508,6 +1512,8 @@ void QCocoaWindow::recreateWindowIfNeeded() // We do however need to manage the parent relationship if (parentCocoaWindow) [parentCocoaWindow->m_view addSubview:m_view]; + else if (oldParentCocoaWindow) + [m_view removeFromSuperview]; return; } @@ -1515,10 +1521,6 @@ void QCocoaWindow::recreateWindowIfNeeded() const bool isEmbeddedView = isEmbedded(); RecreationReasons recreateReason = RecreationNotNeeded; - QCocoaWindow *oldParentCocoaWindow = nullptr; - if (QNSView *qnsView = qnsview_cast(m_view.superview)) - oldParentCocoaWindow = qnsView.platformWindow; - if (parentWindow != oldParentCocoaWindow) recreateReason |= ParentChanged; diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index ddbc63bb57..84a3f55f55 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -266,10 +266,16 @@ void QIOSWindow::setWindowState(Qt::WindowStates state) void QIOSWindow::setParent(const QPlatformWindow *parentWindow) { - UIView *parentView = parentWindow ? reinterpret_cast(parentWindow->winId()) - : isQtApplication() ? static_cast(screen())->uiWindow().rootViewController.view : 0; + UIView *parentView = parentWindow ? + reinterpret_cast(parentWindow->winId()) + : isQtApplication() && !isForeignWindow() ? + static_cast(screen())->uiWindow().rootViewController.view + : nullptr; - [parentView addSubview:m_view]; + if (parentView) + [parentView addSubview:m_view]; + else if (quiview_cast(m_view.superview)) + [m_view removeFromSuperview]; } void QIOSWindow::requestActivateWindow() diff --git a/tests/auto/gui/kernel/qwindow/tst_foreignwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_foreignwindow.cpp index c42bb9d974..a43939a21b 100644 --- a/tests/auto/gui/kernel/qwindow/tst_foreignwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_foreignwindow.cpp @@ -81,10 +81,17 @@ void tst_ForeignWindow::embedForeignWindow() NativeWindow nativeWindow; QVERIFY(nativeWindow); + // Top level windows may not have 0 as their winId, e.g. on + // XCB the root window of the screen is used. + const auto originalParentWinId = nativeWindow.parentWinId(); + // As a prerequisite to that, we must be able to reparent the foreign window std::unique_ptr foreignWindow(QWindow::fromWinId(nativeWindow)); - foreignWindow.release()->setParent(&parentWindow); + foreignWindow->setParent(&parentWindow); QTRY_COMPARE(nativeWindow.parentWinId(), parentWindow.winId()); + + foreignWindow->setParent(nullptr); + QTRY_COMPARE(nativeWindow.parentWinId(), originalParentWinId); } #include