diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 9bcf29830b2..a729962d4f5 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -5061,11 +5061,32 @@ bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject /*! \internal - Used by QML to connect a signal by index to a slot implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass). + Used by QML to connect a signal by index to a slot implemented in JavaScript + (wrapped in a custom QSlotObjectBase subclass). + + This version of connect assumes that sender and receiver are the same object. The signal_index is an index relative to the number of methods. */ QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type) +{ + return QObjectPrivate::connect(sender, signal_index, sender, slotObj, type); +} + +/*! + \internal + Used by QML to connect a signal by index to a slot implemented in JavaScript + (wrapped in a custom QSlotObjectBase subclass). + + This is an overload that should be used when \a sender and \a receiver are + different objects. + + The signal_index is an index relative to the number of methods. + */ +QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index, + const QObject *receiver, + QtPrivate::QSlotObjectBase *slotObj, + Qt::ConnectionType type) { if (!sender) { qCWarning(lcConnect, "QObject::connect: invalid nullptr parameter"); @@ -5076,7 +5097,8 @@ QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signa const QMetaObject *senderMetaObject = sender->metaObject(); signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index); - return QObjectPrivate::connectImpl(sender, signal_index, sender, /*slot*/nullptr, slotObj, type, /*types*/nullptr, senderMetaObject); + return QObjectPrivate::connectImpl(sender, signal_index, receiver, /*slot*/ nullptr, slotObj, + type, /*types*/ nullptr, senderMetaObject); } /*! @@ -5084,13 +5106,34 @@ QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signa Used by QML to disconnect a signal by index that's connected to a slot implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass) In the QML case the slot is not a pointer to a pointer to the function to disconnect, but instead it is a pointer to an array of internal values required for the disconnect. + + This version of disconnect assumes that sender and receiver are the same object. */ bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, void **slot) +{ + return QObjectPrivate::disconnect(sender, signal_index, sender, slot); +} + +/*! + \internal + + Used by QML to disconnect a signal by index that's connected to a slot + implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass) In the + QML case the slot is not a pointer to a pointer to the function to disconnect, + but instead it is a pointer to an array of internal values required for the + disconnect. + + This is an overload that should be used when \a sender and \a receiver are + different objects. + */ +bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, const QObject *receiver, + void **slot) { const QMetaObject *senderMetaObject = sender->metaObject(); signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index); - return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, sender, -1, slot); + return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1, + slot); } /*! diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index a9626a8ab0f..4483e2b6ce7 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -353,7 +353,13 @@ public: QtPrivate::QSlotObjectBase *slotObj, int type, const int *types, const QMetaObject *senderMetaObject); static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type); + static QMetaObject::Connection connect(const QObject *sender, int signal_index, + const QObject *receiver, + QtPrivate::QSlotObjectBase *slotObj, + Qt::ConnectionType type); static bool disconnect(const QObject *sender, int signal_index, void **slot); + static bool disconnect(const QObject *sender, int signal_index, const QObject *receiver, + void **slot); static bool disconnect(Connection *c); void ensureConnectionData() diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 8513375a20c..a7b47438e06 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -152,6 +152,7 @@ private slots: void connectBase(); void connectWarnings(); void qmlConnect(); + void qmlConnectToQObjectReceiver(); void exceptions(); void noDeclarativeParentChangedOnDestruction(); void deleteLaterInAboutToBlockHandler(); @@ -6790,6 +6791,33 @@ void tst_QObject::qmlConnect() #endif } +void tst_QObject::qmlConnectToQObjectReceiver() +{ +#ifdef QT_BUILD_INTERNAL + SenderObject sender; + QScopedPointer receiver(new QObject); + QmlReceiver *slotObject = new QmlReceiver; + slotObject->magic = slotObject; + slotObject->ref(); // extra ref so that slot object is not implicitly deleted + + QVERIFY(QObjectPrivate::connect(&sender, sender.metaObject()->indexOfSignal("signal1()"), + receiver.get(), slotObject, Qt::AutoConnection)); + + QCOMPARE(slotObject->callCount, 0); + sender.emitSignal1(); + QCOMPARE(slotObject->callCount, 1); + + receiver.reset(); // this should disconnect the slotObject + + sender.emitSignal1(); + QCOMPARE(slotObject->callCount, 1); + + slotObject->destroyIfLastRef(); +#else + QSKIP("Needs QT_BUILD_INTERNAL"); +#endif +} + #ifndef QT_NO_EXCEPTIONS class ObjectException : public std::exception { };