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.8 6.7 6.5
Change-Id: I5b14e156956ae76a8f53cac31904eaadee9e791f
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Tor Arne Vestbø 2024-06-17 19:34:28 +02:00
parent 6887986bc5
commit 006cbf658e
2 changed files with 35 additions and 0 deletions

View File

@ -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;
}

View File

@ -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<QWindow> 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"