aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4referenceobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4referenceobject.cpp')
-rw-r--r--src/qml/jsruntime/qv4referenceobject.cpp64
1 files changed, 64 insertions, 0 deletions
diff --git a/src/qml/jsruntime/qv4referenceobject.cpp b/src/qml/jsruntime/qv4referenceobject.cpp
index 7493ed5714..336b715ca0 100644
--- a/src/qml/jsruntime/qv4referenceobject.cpp
+++ b/src/qml/jsruntime/qv4referenceobject.cpp
@@ -488,4 +488,68 @@ void QQmlDirtyReferenceObject_callback(QQmlNotifierEndpoint *e, void **) {
static_cast<QV4::Heap::ReferenceObjectEndpoint*>(e)->reference->setDirty(true);
}
+namespace QV4 {
+
+void Heap::ReferenceObject::connectToNotifySignal(QObject *obj, int property, QQmlEngine *engine)
+{
+ Q_ASSERT(obj);
+ Q_ASSERT(engine);
+
+ Q_ASSERT(!referenceEndpoint);
+ Q_ASSERT(!bindableNotifier);
+
+ referenceEndpoint = new ReferenceObjectEndpoint(this);
+
+ // Connect and signal emission work on "signal indexes". Those are different from "method
+ // indexes".
+ // The public MetaObject interface can, generally, give us the "method index" of the notify
+ // signal.
+ // Quite unintuitively, this is true for "notifySignalIndex". As the "method index" and the
+ // "signal index" can be different, connecting the "method index" of the notify signal can
+ // incur in issues when the signal is being emitted and checking for connected endpoints.
+ // For example, we might be connected to the "method index" of the notify signal for the
+ // property and end up checking for the subscribers of a different signal when the notify
+ // signal is emitted, due to the different meaning of the same index.
+ // Thus we pass by the private interface to ensure that we are connecting based on the "signal
+ // index" instead.
+ const int index = QMetaObjectPrivate::signalIndex(obj->metaObject()->property(property)
+ .notifySignal());
+ referenceEndpoint->connect(obj, index, engine);
+
+ // When the object that is being referenced is destroyed, we
+ // need to ensure that one additional read is performed to
+ // invalidate the data we hold.
+ // As the object might be destroyed in a way that doesn't
+ // trigger the notify signal for the relevant property, we react
+ // directly to the destruction itself.
+ // We use a plain connection instead of a QQmlNotifierEndpoint
+ // based connection as, currently, declarative-side signals are
+ // always discarded during destruction (see
+ // QQmlData::signalEmitted).
+ // In theory it should be possible to relax that condition for
+ // the destroy signal specifically, which should allow a more
+ // optimized way of connecting.
+ // Nonetheless this seems to be the only place where we have
+ // this kind of need, and thus go for the simpler solution,
+ // which can be changed later if the need arises.
+ new (onDelete) QMetaObject::Connection(
+ QObject::connect(obj, &QObject::destroyed, [this](){ setDirty(true); }));
+}
+
+void Heap::ReferenceObject::connectToBindable(QObject *obj, int property, QQmlEngine *engine)
+{
+ Q_ASSERT(obj);
+ Q_ASSERT(engine);
+
+ Q_ASSERT(!referenceEndpoint);
+ Q_ASSERT(!bindableNotifier);
+
+ bindableNotifier = new QPropertyNotifier(obj->metaObject()->property(property).bindable(obj)
+ .addNotifier([this](){ setDirty(true); }));
+ new (onDelete) QMetaObject::Connection(
+ QObject::connect(obj, &QObject::destroyed, [this]() { setDirty(true); }));
+}
+
+} // namespace QV4
+
QT_END_NAMESPACE