Add new special QObjectPrivate::{connect, disconnect} for QML
Original QML-specific connection mechanism ignores the receiver argument and uses sender as receiver. This causes uncontrollable memory growth in certain cases as connections on receiver persist even after receiver is destroyed New connect() with receiver parameter uses underlying API correctly, disconnect is provided for the symmetry (not sure it's really needed) Task-number: QTBUG-86368 Pick-to: 5.15 6.0 Change-Id: I4580d75b617cb2c4dfb971a4dfb8e943e325572b Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
5a0e5521e4
commit
6f520abdab
@ -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);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -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()
|
||||
|
@ -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<QObject> 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 { };
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user