XCB/Windows: Decouple foreign window from QWindow parent on destroy

Qt's foreign windows do not take (full) ownership of the native handle,
so our platform window implementations take care to not fully destroy
the native handle in their destructors.

But if the foreign window had a QWindow parent at the time of
destruction, and we fail to decouple the native handle from its
native handle parent, the destruction of the QWindow parent may
bring down the foreign window native handle as well, as part of
deleting the parent QWindow's native handle.

We take care to selectively do this decoupling on macOS, iOS, and
Android, but were failing to do so on XCB and Windows. This has now
been corrected, which allows us to remove the workaround in QWindow,
which was also in the wrong place (before setVisible(false) on the
foreign window child).

Note that we do not unconditionally reparent the foreign window, as
it might be a foreign window used for containing other QWindows, in
which case we don't want to mess with the native view hierarchy.

Change-Id: Ic526ca63fbf72dae5013ae9e44cb5cddf61c944b
Reviewed-by: Liang Qi <liang.qi@qt.io>
(cherry picked from commit 8f8ce8d7a7e029e62a4f9b5b209dcc37f61410cb)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Tor Arne Vestbø 2024-08-28 15:06:22 +02:00 committed by Qt Cherry-pick Bot
parent fb6cfadc38
commit 046cc59aee
4 changed files with 10 additions and 10 deletions

View File

@ -2083,16 +2083,6 @@ void QWindowPrivate::destroy()
QObject *object = childrenWindows.at(i);
if (object->isWindowType()) {
QWindow *w = static_cast<QWindow*>(object);
auto *childPlatformWindow = w->handle();
if (!childPlatformWindow)
continue;
// Decouple the foreign window from this window,
// so that destroying our native handle doesn't
// bring down the foreign window as well.
if (childPlatformWindow->isForeignWindow())
childPlatformWindow->setParent(nullptr);
qt_window_private(w)->destroy();
}
}

View File

@ -1364,6 +1364,12 @@ QWindowsForeignWindow::QWindowsForeignWindow(QWindow *window, HWND hwnd)
setParent(QPlatformWindow::parent());
}
QWindowsForeignWindow::~QWindowsForeignWindow()
{
if (QPlatformWindow::parent())
setParent(nullptr);
}
void QWindowsForeignWindow::setParent(const QPlatformWindow *newParentWindow)
{
const bool wasTopLevel = isTopLevel_sys();

View File

@ -160,6 +160,7 @@ class QWindowsForeignWindow : public QWindowsBaseWindow
{
public:
explicit QWindowsForeignWindow(QWindow *window, HWND hwnd);
~QWindowsForeignWindow();
void setParent(const QPlatformWindow *window) override;
void setGeometry(const QRect &rect) override { setGeometry_sys(rect); }

View File

@ -530,6 +530,9 @@ QXcbForeignWindow::QXcbForeignWindow(QWindow *window, WId nativeHandle)
QXcbForeignWindow::~QXcbForeignWindow()
{
if (QPlatformWindow::parent())
setParent(nullptr);
// Clear window so that destroy() does not affect it
m_window = 0;