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 <laszlo.agocs@qt.io>
This commit is contained in:
Allan Sandfeld Jensen 2022-05-03 11:48:56 +02:00
parent 7ec2153016
commit 0d97723ee2
3 changed files with 53 additions and 8 deletions

View File

@ -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<QChildEvent *>(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<QChildEvent *>(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();
}

View File

@ -40,6 +40,7 @@ public:
protected:
bool event(QEvent *ev) override;
bool eventFilter(QObject *, QEvent *ev) override;
private slots:
void focusWindowChanged(QWindow *focusWindow);

View File

@ -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<QWindow> window(new QWindow());
QScopedPointer<QWidget> 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<QWindow> window1(new QWindow());
QScopedPointer<QWindow> window2(new QWindow());
QScopedPointer<QWidget> 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()