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 <richard.gustavsen@qt.io>
bb10
Tor Arne Vestbø 2023-11-13 11:12:50 +01:00
parent 93077dd1f2
commit db33628452
3 changed files with 23 additions and 8 deletions

View File

@ -1499,6 +1499,10 @@ void QCocoaWindow::recreateWindowIfNeeded()
QPlatformWindow *parentWindow = QPlatformWindow::parent();
auto *parentCocoaWindow = static_cast<QCocoaWindow *>(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;

View File

@ -266,10 +266,16 @@ void QIOSWindow::setWindowState(Qt::WindowStates state)
void QIOSWindow::setParent(const QPlatformWindow *parentWindow)
{
UIView *parentView = parentWindow ? reinterpret_cast<UIView *>(parentWindow->winId())
: isQtApplication() ? static_cast<QIOSScreen *>(screen())->uiWindow().rootViewController.view : 0;
UIView *parentView = parentWindow ?
reinterpret_cast<UIView *>(parentWindow->winId())
: isQtApplication() && !isForeignWindow() ?
static_cast<QIOSScreen *>(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()

View File

@ -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<QWindow> 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 <tst_foreignwindow.moc>