diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp index 838c90fce7..d042064579 100644 --- a/src/corelib/kernel/qcoreevent.cpp +++ b/src/corelib/kernel/qcoreevent.cpp @@ -159,8 +159,10 @@ Q_TRACE_POINT(qtcore, QEvent_dtor, QEvent *event, QEvent::Type type); \value OrientationChange The screens orientation has changes (QScreenOrientationChangeEvent). \value Paint Screen update necessary (QPaintEvent). \value PaletteChange Palette of the widget changed. - \value ParentAboutToChange The widget parent is about to change. - \value ParentChange The widget parent has changed. + \value ParentAboutToChange The object parent is about to change. + Only sent to some object types, such as QWidget. + \value ParentChange The object parent has changed. + Only sent to some object types, such as QWidget. \value PlatformPanel A platform specific panel has been requested. \value PlatformSurface A native platform surface has been created or is about to be destroyed (QPlatformSurfaceEvent). \omitvalue Pointer diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h index 93ab1c1871..e8e4b4bba6 100644 --- a/src/corelib/kernel/qcoreevent.h +++ b/src/corelib/kernel/qcoreevent.h @@ -77,7 +77,7 @@ public: Hide = 18, // widget is hidden Close = 19, // request to close widget Quit = 20, // request to quit application - ParentChange = 21, // widget has been reparented + ParentChange = 21, // object has been reparented ParentAboutToChange = 131, // sent just before the parent change is done ThreadChange = 22, // object has changed threads WindowActivate = 24, // window was activated diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 90d1f6745c..7c109238b2 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -179,6 +179,7 @@ QObjectPrivate::QObjectPrivate(int version) isQuickItem = false; willBeWidget = false; wasWidget = false; + receiveParentEvents = false; // If object wants ParentAboutToChange and ParentChange } QObjectPrivate::~QObjectPrivate() @@ -2249,7 +2250,15 @@ void QObjectPrivate::setParent_helper(QObject *o) } } } + + if (receiveParentEvents) { + Q_ASSERT(!isWidget); // Handled in QWidget + QEvent e(QEvent::ParentAboutToChange); + QCoreApplication::sendEvent(q, &e); + } + parent = o; + if (parent) { // object hierarchies are constrained to a single thread if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) { @@ -2265,6 +2274,12 @@ void QObjectPrivate::setParent_helper(QObject *o) } } } + + if (receiveParentEvents) { + Q_ASSERT(!isWidget); // Handled in QWidget + QEvent e(QEvent::ParentChange); + QCoreApplication::sendEvent(q, &e); + } } /*! diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index eb99504647..7c3d74dcda 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -72,7 +72,8 @@ public: uint isQuickItem : 1; uint willBeWidget : 1; // for handling widget-specific bits in QObject's ctor uint wasWidget : 1; // for properly cleaning up in QObject's dtor - uint unused : 21; + uint receiveParentEvents: 1; + uint unused : 20; QAtomicInt postedEvents; QDynamicMetaObjectData *metaObject; QBindingStorage bindingStorage; diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index a4f761d6b9..5692615f29 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -80,6 +80,7 @@ private slots: void signalBlocking(); void blockingQueuedConnection(); void childEvents(); + void parentEvents(); void installEventFilter(); void deleteSelfInSlot(); void disconnectSelfInSlotAndDeleteAfterEmit(); @@ -3200,6 +3201,78 @@ void tst_QObject::childEvents() } } +void tst_QObject::parentEvents() +{ +#ifdef QT_BUILD_INTERNAL + EventSpy::EventList expected; + + { + // Parent events not enabled + QObject parent; + QObject child; + + EventSpy spy; + child.installEventFilter(&spy); + + QCoreApplication::postEvent(&child, new QEvent(QEvent::Type(QEvent::User + 1))); + + child.setParent(&parent); + + QCoreApplication::postEvent(&child, new QEvent(QEvent::Type(QEvent::User + 2))); + + expected = + EventSpy::EventList(); + QCOMPARE(spy.eventList(), expected); + spy.clear(); + + QCoreApplication::processEvents(); + + expected = + EventSpy::EventList() + << qMakePair(&child, QEvent::Type(QEvent::User + 1)) + << qMakePair(&child, QEvent::Type(QEvent::User + 2)); + QCOMPARE(spy.eventList(), expected); + } + + { + // Parent events enabled + QObject parent; + QObject child; + auto *childPrivate = QObjectPrivate::get(&child); + childPrivate->receiveParentEvents = true; + + EventSpy spy; + child.installEventFilter(&spy); + + QCoreApplication::postEvent(&child, new QEvent(QEvent::Type(QEvent::User + 1))); + + child.setParent(&parent); + child.setParent(nullptr); + + QCoreApplication::postEvent(&child, new QEvent(QEvent::Type(QEvent::User + 2))); + + expected = + EventSpy::EventList() + << qMakePair(&child, QEvent::ParentAboutToChange) + << qMakePair(&child, QEvent::ParentChange) + << qMakePair(&child, QEvent::ParentAboutToChange) + << qMakePair(&child, QEvent::ParentChange); + QCOMPARE(spy.eventList(), expected); + spy.clear(); + + QCoreApplication::processEvents(); + + expected = + EventSpy::EventList() + << qMakePair(&child, QEvent::Type(QEvent::User + 1)) + << qMakePair(&child, QEvent::Type(QEvent::User + 2)); + QCOMPARE(spy.eventList(), expected); + } +#else + QSKIP("Needs QT_BUILD_INTERNAL"); +#endif +} + void tst_QObject::installEventFilter() { QEvent event(QEvent::User);