From f0f9cc602f065e167a0ac608203d7a5fc3a3c297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 17 Jun 2024 19:34:28 +0200 Subject: [PATCH] Let QWindowContainer know when its top level is about to be destroyed When the top level window that a QWindowContainer is in is about to be destroyed the QWindowContainer must reparent the contained window into a dummy window, as otherwise the destruction of the top level will bring down the contained window as well. We were notifying the window container about this situation when the window container was moved from being a top level itself, to being a child widget, but did not have any logic for other ways the window container could lose its parent QWindow. An example of this was when RHI-needs would result in recreating the top revel with a different RHI backend. We now have a last minute call to toplevelAboutToBeDestroyed in QWidgetPrivate::deleteTLSysExtra(). Fixes: QTBUG-126303 Pick-to: 6.7 6.5 Change-Id: I5b14e156956ae76a8f53cac31904eaadee9e791f Reviewed-by: Volker Hilsheimer (cherry picked from commit 006cbf658ea1f5986bbe1baafa7c146780320661) Reviewed-by: Qt Cherry-pick Bot --- src/widgets/kernel/qwidget.cpp | 4 +++ .../qwindowcontainer/tst_qwindowcontainer.cpp | 31 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 0af28e3cfd5..a8bc8e2185a 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -1700,7 +1700,11 @@ void QWidgetPrivate::deleteSysExtra() void QWidgetPrivate::deleteTLSysExtra() { + Q_Q(QWidget); if (extra && extra->topextra) { + if (extra->hasWindowContainer) + QWindowContainer::toplevelAboutToBeDestroyed(q); + delete extra->topextra->window; extra->topextra->window = nullptr; } diff --git a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp index 52aaf094b47..e7d65db550c 100644 --- a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp +++ b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp @@ -62,6 +62,7 @@ private slots: void testPlatformSurfaceEvent(); void embedWidgetWindow(); void testFocus(); + void parentDestroyed(); void cleanup(); private: @@ -530,6 +531,36 @@ void tst_QWindowContainer::testFocus() QVERIFY(!lineEdit->hasFocus()); } +class CreateDestroyWidget : public QWidget +{ +public: + void create() { QWidget::create(); } + void destroy() { QWidget::destroy(); } +}; + +void tst_QWindowContainer::parentDestroyed() +{ + CreateDestroyWidget topLevel; + topLevel.setAttribute(Qt::WA_NativeWindow); + QVERIFY(topLevel.windowHandle()); + + QPointer window = new QWindow; + QWidget *container = QWidget::createWindowContainer(window.get()); + container->setParent(&topLevel); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + QCOMPARE(window->parent(), topLevel.windowHandle()); + + // Destroying the widget should not wipe out the contained QWindow + topLevel.destroy(); + QVERIFY(window); + + // Recreating the top level should once again reparent the contained window + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + QCOMPARE(window->parent(), topLevel.windowHandle()); +} + QTEST_MAIN(tst_QWindowContainer) #include "tst_qwindowcontainer.moc"