This may have gotten fixed by the fix for QTBUG-107850[1] (commit
7487332)[2].  QTBUG-84858 gets a tacit mention there, but is not among
the list of duplicates that got closed through this (even though it
probably should be).

I hastily backported this to 5.15.8 (see attachment), but have not yet
checked if it actually compiles (the test might use functions/macros
missing from 5.15) or works.  I can't look into this more currently
since I'm somewhat busy.  Hopefully I can try it out this weekend.

Regards.

1: https://bugreports.qt.io/browse/QTBUG-107850
2: 
https://invent.kde.org/qt/qt/qtdeclarative/-/commit/74873324bdf3399753f9fcaf7461c0e00df628b1
Description: backport commit 7487332 to hopefully fix #983597
 Edited from the original for 6.5.0 FF: https://invent.kde.org/qt/qt/qtdeclarative/-/commit/74873324bdf3399753f9fcaf7461c0e00df628b1
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -2326,6 +2326,7 @@
 QQuickItem::~QQuickItem()
 {
     Q_D(QQuickItem);
+    d->inDestructor = true;
 
     if (d->windowRefCount > 1)
         d->windowRefCount = 1; // Make sure window is set to null in next call to derefWindow().
@@ -2689,9 +2690,8 @@
 
         const bool wasVisible = isVisible();
         op->removeChild(this);
-        if (wasVisible) {
+        if (wasVisible && !op->inDestructor)
             emit oldParentItem->visibleChildrenChanged();
-        }
     } else if (d->window) {
         QQuickWindowPrivate::get(d->window)->parentlessItems.remove(this);
     }
@@ -2768,8 +2768,9 @@
 
     d->itemChange(ItemParentHasChanged, d->parentItem);
 
-    emit parentChanged(d->parentItem);
-    if (isVisible() && d->parentItem)
+    if (!d->inDestructor)
+        emit parentChanged(d->parentItem);
+    if (isVisible() && d->parentItem && !QQuickItemPrivate::get(d->parentItem)->inDestructor)
         emit d->parentItem->visibleChildrenChanged();
 }
 
@@ -2965,7 +2966,8 @@
 
     itemChange(QQuickItem::ItemChildRemovedChange, child);
 
-    emit q->childrenChanged();
+    if (!inDestructor)
+        emit q->childrenChanged();
 }
 
 void QQuickItemPrivate::refWindow(QQuickWindow *c)
@@ -3194,6 +3196,7 @@
     , touchEnabled(false)
 #endif
     , hasCursorHandler(false)
+    , inDestructor(false)
     , dirtyAttributes(0)
     , nextDirtyItem(nullptr)
     , prevDirtyItem(nullptr)
@@ -6106,9 +6109,11 @@
         QAccessible::updateAccessibility(&ev);
     }
 #endif
-    emit q->visibleChanged();
-    if (childVisibilityChanged)
-        emit q->visibleChildrenChanged();
+    if (!inDestructor) {
+        emit q->visibleChanged();
+        if (childVisibilityChanged)
+            emit q->visibleChildrenChanged();
+    }
 
     return true;    // effective visibility DID change
 }
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -472,6 +472,7 @@
     bool replayingPressEvent:1;
     bool touchEnabled:1;
     bool hasCursorHandler:1;
+    quint32 inDestructor:1; // has entered ~QQuickItem
 
     enum DirtyType {
         TransformOrigin         = 0x00000001,
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -130,6 +130,7 @@
     void isAncestorOf();
 
     void grab();
+    void signalsOnDestruction();
 
 private:
     QQmlEngine engine;
@@ -3520,6 +3521,52 @@
     QVERIFY(!sub2.isAncestorOf(&sub2));
 }
 
+/*
+    Items that are getting destroyed should not emit property change notifications.
+*/
+void tst_QQuickItem::signalsOnDestruction()
+{
+    QQuickWindow window;
+    window.show();
+
+    // visual children, but not QObject children
+    std::unique_ptr<QQuickItem> parent(new QQuickItem(window.contentItem()));
+    std::unique_ptr<QQuickItem> child(new QQuickItem);
+    std::unique_ptr<QQuickItem> grandChild(new QQuickItem);
+
+    QSignalSpy childrenSpy(parent.get(), &QQuickItem::childrenChanged);
+    QSignalSpy visibleChildrenSpy(parent.get(), &QQuickItem::visibleChildrenChanged);
+    QSignalSpy childParentSpy(child.get(), &QQuickItem::parentChanged);
+    QSignalSpy childChildrenSpy(child.get(), &QQuickItem::childrenChanged);
+    QSignalSpy childVisibleChildrenSpy(child.get(), &QQuickItem::visibleChanged);
+    QSignalSpy grandChildParentSpy(grandChild.get(), &QQuickItem::parentChanged);
+
+    child->setParentItem(parent.get());
+    QCOMPARE(childrenSpy.count(), 1);
+    QCOMPARE(visibleChildrenSpy.count(), 1);
+    QCOMPARE(childParentSpy.count(), 1);
+    QCOMPARE(childChildrenSpy.count(), 0);
+    QCOMPARE(childVisibleChildrenSpy.count(), 0);
+
+    grandChild->setParentItem(child.get());
+    QCOMPARE(childrenSpy.count(), 1);
+    QCOMPARE(visibleChildrenSpy.count(), 1);
+    QCOMPARE(childParentSpy.count(), 1);
+    QCOMPARE(childChildrenSpy.count(), 1);
+    QCOMPARE(childVisibleChildrenSpy.count(), 0);
+    QCOMPARE(grandChildParentSpy.count(), 1);
+
+    parent.reset();
+
+    QVERIFY(!child->parentItem());
+    QVERIFY(grandChild->parentItem());
+    QCOMPARE(childrenSpy.count(), 1);
+    QCOMPARE(visibleChildrenSpy.count(), 1);
+    QCOMPARE(childParentSpy.count(), 2);
+    QCOMPARE(grandChildParentSpy.count(), 1);
+}
+
+
 QTEST_MAIN(tst_QQuickItem)
 
 #include "tst_qquickitem.moc"

Reply via email to