From 0d97723ee2778203af0cfd13599572110fb69dd5 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 3 May 2022 11:48:56 +0200 Subject: [PATCH] Fix separate delete of window and windowcontainer The documentation says we can change window parent to avoid the widget deleting the window. That didn't work as the widget didn't get the child-removed event as it wasn't the parent. This patch instead uses an event filter on the set parent. Pick-to: 6.3 6.2 Change-Id: I1f61d1832fcf3257722f305beeefd8f1abf1f656 Reviewed-by: Laszlo Agocs --- src/widgets/kernel/qwindowcontainer.cpp | 35 +++++++++++++++---- src/widgets/kernel/qwindowcontainer_p.h | 1 + .../qwindowcontainer/tst_qwindowcontainer.cpp | 25 +++++++++++-- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/widgets/kernel/qwindowcontainer.cpp b/src/widgets/kernel/qwindowcontainer.cpp index 847058e5b21..072a0bc5fa2 100644 --- a/src/widgets/kernel/qwindowcontainer.cpp +++ b/src/widgets/kernel/qwindowcontainer.cpp @@ -191,6 +191,7 @@ QWindowContainer::QWindowContainer(QWindow *embeddedWindow, QWidget *parent, Qt: d->fakeParent.setObjectName(windowName + "ContainerFakeParent"_L1); d->window->setParent(&d->fakeParent); + d->window->parent()->installEventFilter(this); d->window->setFlag(Qt::SubWindow); setAcceptDrops(true); @@ -239,6 +240,26 @@ void QWindowContainer::focusWindowChanged(QWindow *focusWindow) } } +/*! + \internal + */ + +bool QWindowContainer::eventFilter(QObject *o, QEvent *e) +{ + Q_D(QWindowContainer); + if (!d->window) + return false; + + if (e->type() == QEvent::ChildRemoved) { + QChildEvent *ce = static_cast(e); + if (ce->child() == d->window) { + o->removeEventFilter(this); + d->window = nullptr; + } + } + return false; +} + /*! \internal */ @@ -251,12 +272,6 @@ bool QWindowContainer::event(QEvent *e) QEvent::Type type = e->type(); switch (type) { - case QEvent::ChildRemoved: { - QChildEvent *ce = static_cast(e); - if (ce->child() == d->window) - d->window = nullptr; - break; - } // The only thing we are interested in is making sure our sizes stay // in sync, so do a catch-all case. case QEvent::Resize: @@ -271,10 +286,13 @@ bool QWindowContainer::event(QEvent *e) case QEvent::Show: d->updateUsesNativeWidgets(); if (d->isStillAnOrphan()) { + d->window->parent()->removeEventFilter(this); d->window->setParent(d->usesNativeWidgets ? windowHandle() : window()->windowHandle()); d->fakeParent.destroy(); + if (d->window->parent()) + d->window->parent()->installEventFilter(this); } if (d->window->parent()) { d->markParentChain(); @@ -345,7 +363,10 @@ static void qwindowcontainer_traverse(QWidget *parent, qwindowcontainer_traverse void QWindowContainer::toplevelAboutToBeDestroyed(QWidget *parent) { if (QWindowContainerPrivate *d = QWindowContainerPrivate::get(parent)) { + if (d->window->parent()) + d->window->parent()->removeEventFilter(parent); d->window->setParent(&d->fakeParent); + d->window->parent()->installEventFilter(parent); } qwindowcontainer_traverse(parent, toplevelAboutToBeDestroyed); } @@ -363,7 +384,9 @@ void QWindowContainer::parentWasChanged(QWidget *parent) tld->createTLSysExtra(); Q_ASSERT(toplevel->windowHandle()); } + d->window->parent()->removeEventFilter(parent); d->window->setParent(toplevel->windowHandle()); + toplevel->windowHandle()->installEventFilter(parent); d->fakeParent.destroy(); d->updateGeometry(); } diff --git a/src/widgets/kernel/qwindowcontainer_p.h b/src/widgets/kernel/qwindowcontainer_p.h index e8944191e6a..8dc5c64af4f 100644 --- a/src/widgets/kernel/qwindowcontainer_p.h +++ b/src/widgets/kernel/qwindowcontainer_p.h @@ -40,6 +40,7 @@ public: protected: bool event(QEvent *ev) override; + bool eventFilter(QObject *, QEvent *ev) override; private slots: void focusWindowChanged(QWindow *focusWindow); diff --git a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp index 8d0f84ca60e..19c9606d79d 100644 --- a/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp +++ b/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp @@ -50,6 +50,7 @@ private slots: void testOwnership(); void testBehindTheScenesDeletion(); void testUnparenting(); + void testReparenting(); void testUnparentReparent(); void testActivation(); void testAncestorChange(); @@ -206,12 +207,12 @@ void tst_QWindowContainer::testActivation() void tst_QWindowContainer::testUnparenting() { - QWindow *window = new QWindow(); + QPointer window(new QWindow()); QScopedPointer container(QWidget::createWindowContainer(window)); container->setWindowTitle(QTest::currentTestFunction()); container->setGeometry(m_availableGeometry.x() + 100, m_availableGeometry.y() + 100, 200, 100); - window->setParent(0); + window->setParent(nullptr); container->show(); @@ -219,6 +220,26 @@ void tst_QWindowContainer::testUnparenting() // Window should not be made visible by container.. QVERIFY(!window->isVisible()); + + container.reset(); + QVERIFY(window); + delete window; +} + +void tst_QWindowContainer::testReparenting() +{ + QPointer window1(new QWindow()); + QScopedPointer window2(new QWindow()); + QScopedPointer container(QWidget::createWindowContainer(window1)); + + window1->setParent(window2.data()); + + // Not deleted with container + container.reset(); + QVERIFY(window1); + // but deleted with new parent + window2.reset(); + QVERIFY(!window1); } void tst_QWindowContainer::testUnparentReparent()