summaryrefslogtreecommitdiff
path: root/src/declarative
diff options
context:
space:
mode:
authorThomas McGuire <thomas.mcguire.qnx@kdab.com>2012-08-06 09:36:05 +0200
committerQt by Nokia <qt-info@nokia.com>2012-08-31 15:08:29 +0200
commit3c4c970962d75a902ff14a1c8b3adb36895c4ffa (patch)
tree6f6a4060c3e6b9179ac731398f7832427aa28fb1 /src/declarative
parent43669c58027b9e6ba76b6b2ca6059ab3d9e8c0ea (diff)
downloadqt4-tools-3c4c970962d75a902ff14a1c8b3adb36895c4ffa.tar.gz
Make connectNotify() work with QML
Call connectNotify() and disconnectNotify() in QML signal handlers and in QML bindings. This is a backport of Qt5's QtDeclarative commit 26ea8e01e9ee2a8c8c09266147b94c9ac92d09f9. Task-number: QTBUG-11284 Change-Id: If5c3701426208875f3b775040c4e7bcbaac2b0a9 Reviewed-by: Kent Hansen <kent.hansen@nokia.com> Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
Diffstat (limited to 'src/declarative')
-rw-r--r--src/declarative/qml/qdeclarativebinding.cpp17
-rw-r--r--src/declarative/qml/qdeclarativebinding_p.h33
-rw-r--r--src/declarative/qml/qdeclarativeboundsignal.cpp41
-rw-r--r--src/declarative/qml/qdeclarativeboundsignal_p.h28
-rw-r--r--src/declarative/qml/qdeclarativecompiledbindings.cpp72
-rw-r--r--src/declarative/qml/qdeclarativedata_p.h6
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp35
-rw-r--r--src/declarative/qml/qdeclarativenotifier.cpp5
-rw-r--r--src/declarative/qml/qdeclarativenotifier_p.h28
-rw-r--r--src/declarative/qml/qdeclarativeproperty.cpp6
-rw-r--r--src/declarative/qml/qdeclarativeproperty_p.h2
11 files changed, 239 insertions, 34 deletions
diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp
index 5acbec9c08..779fdd1cf4 100644
--- a/src/declarative/qml/qdeclarativebinding.cpp
+++ b/src/declarative/qml/qdeclarativebinding.cpp
@@ -75,8 +75,11 @@ Bindings are free to implement their own memory management, so the delete operat
necessarily safe. The default implementation clears the binding, removes it from the object
and calls delete.
*/
-void QDeclarativeAbstractBinding::destroy()
+void QDeclarativeAbstractBinding::destroy(DestroyMode mode)
{
+ if (mode == DisconnectBinding)
+ disconnect(QDeclarativeAbstractBinding::DisconnectOne);
+
removeFromObject();
clear();
@@ -488,6 +491,12 @@ QString QDeclarativeBinding::expression() const
return QDeclarativeExpression::expression();
}
+void QDeclarativeBinding::disconnect(DisconnectMode disconnectMode)
+{
+ Q_UNUSED(disconnectMode);
+ setNotifyOnValueChanged(false);
+}
+
QDeclarativeValueTypeProxyBinding::QDeclarativeValueTypeProxyBinding(QObject *o, int index)
: m_object(o), m_index(index), m_bindings(0)
{
@@ -539,6 +548,12 @@ void QDeclarativeValueTypeProxyBinding::update(QDeclarativePropertyPrivate::Writ
{
}
+void QDeclarativeValueTypeProxyBinding::disconnect(DisconnectMode disconnectMode)
+{
+ Q_UNUSED(disconnectMode);
+ // Nothing to do
+}
+
QDeclarativeAbstractBinding *QDeclarativeValueTypeProxyBinding::binding(int propertyIndex)
{
QDeclarativeAbstractBinding *binding = m_bindings;
diff --git a/src/declarative/qml/qdeclarativebinding_p.h b/src/declarative/qml/qdeclarativebinding_p.h
index 01d5070a27..a6bde99714 100644
--- a/src/declarative/qml/qdeclarativebinding_p.h
+++ b/src/declarative/qml/qdeclarativebinding_p.h
@@ -71,10 +71,39 @@ public:
QDeclarativeAbstractBinding();
- virtual void destroy();
+ enum DestroyMode {
+ // The binding should disconnect itself upon destroy
+ DisconnectBinding,
+
+ // The binding doesn't need to disconnect itself, but it can if it wants to.
+ //
+ // This is used in QDeclarativeData::destroyed() - at the point at which the bindings are
+ // destroyed, the notifiers are already disconnected, so no need to disconnect each
+ // binding again.
+ //
+ // Bindings can use this flag to speed up destruction, especially for compiled bindings
+ // disconnecting a single binding might be slow.
+ KeepBindingConnected
+ };
+
+ virtual void destroy(DestroyMode mode = DisconnectBinding);
virtual QString expression() const;
+ enum DisconnectMode {
+
+ // Just this single binding is getting disconnected, other bindings remain connected and
+ // should not be changed.
+ DisconnectOne,
+
+ // All bindings of the same object are getting disconnected. As an optimization, it is
+ // therefore valid to disconnect all bindings in one go.
+ DisconnectAll
+ };
+
+ // disconnectMode can be ignored, it is just a hint for potential optimization
+ virtual void disconnect(DisconnectMode disconnectMode) = 0;
+
enum Type { PropertyBinding, ValueTypeProxy };
virtual Type bindingType() const { return PropertyBinding; }
@@ -123,6 +152,7 @@ public:
virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags);
virtual void update(QDeclarativePropertyPrivate::WriteFlags);
+ virtual void disconnect(DisconnectMode disconnectMode);
QDeclarativeAbstractBinding *binding(int propertyIndex);
@@ -168,6 +198,7 @@ public:
virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags);
virtual void update(QDeclarativePropertyPrivate::WriteFlags flags);
virtual QString expression() const;
+ virtual void disconnect(DisconnectMode disconnectMode);
typedef int Identifier;
static Identifier Invalid;
diff --git a/src/declarative/qml/qdeclarativeboundsignal.cpp b/src/declarative/qml/qdeclarativeboundsignal.cpp
index 089449edbe..c6ab1f1925 100644
--- a/src/declarative/qml/qdeclarativeboundsignal.cpp
+++ b/src/declarative/qml/qdeclarativeboundsignal.cpp
@@ -97,21 +97,23 @@ QDeclarativeAbstractBoundSignal::~QDeclarativeAbstractBoundSignal()
QDeclarativeBoundSignal::QDeclarativeBoundSignal(QObject *scope, const QMetaMethod &signal,
QObject *parent)
-: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0)
+: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0),
+ m_scope(scope, this)
{
- // This is thread safe. Although it may be updated by two threads, they
- // will both set it to the same value - so the worst thing that can happen
- // is that they both do the work to figure it out. Boo hoo.
- if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount();
-
- QDeclarative_setParent_noEvent(this, parent);
- QDeclarativePropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx);
+ init(parent);
}
QDeclarativeBoundSignal::QDeclarativeBoundSignal(QDeclarativeContext *ctxt, const QString &val,
QObject *scope, const QMetaMethod &signal,
QObject *parent)
-: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0)
+: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0),
+ m_scope(scope, this)
+{
+ init(parent);
+ m_expression = new QDeclarativeExpression(ctxt, scope, val);
+}
+
+void QDeclarativeBoundSignal::init(QObject *parent)
{
// This is thread safe. Although it may be updated by two threads, they
// will both set it to the same value - so the worst thing that can happen
@@ -119,17 +121,25 @@ QDeclarativeBoundSignal::QDeclarativeBoundSignal(QDeclarativeContext *ctxt, cons
if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount();
QDeclarative_setParent_noEvent(this, parent);
- QDeclarativePropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx);
+ QDeclarativePropertyPrivate::connect(m_scope, m_signal.methodIndex(), this, evaluateIdx);
- m_expression = new QDeclarativeExpression(ctxt, scope, val);
+ QDeclarativeData * const data = QDeclarativeData::get(m_scope, true);
+ data->addBoundSignal(this);
}
QDeclarativeBoundSignal::~QDeclarativeBoundSignal()
{
+ unregisterScopeObject();
delete m_expression;
m_expression = 0;
}
+void QDeclarativeBoundSignal::disconnect()
+{
+ QObjectPrivate * const priv = QObjectPrivate::get(m_scope);
+ priv->disconnectNotify(m_signal.signature());
+}
+
int QDeclarativeBoundSignal::index() const
{
return m_signal.methodIndex();
@@ -196,6 +206,15 @@ int QDeclarativeBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a)
}
}
+void QDeclarativeBoundSignal::unregisterScopeObject()
+{
+ if (m_scope) {
+ QDeclarativeData * const data = QDeclarativeData::get(m_scope, false);
+ if (data)
+ data->removeBoundSignal(this);
+ }
+}
+
QDeclarativeBoundSignalParameters::QDeclarativeBoundSignalParameters(const QMetaMethod &method,
QObject *parent)
: QObject(parent), types(0), values(0)
diff --git a/src/declarative/qml/qdeclarativeboundsignal_p.h b/src/declarative/qml/qdeclarativeboundsignal_p.h
index a0dfe18f32..4ba8592ae6 100644
--- a/src/declarative/qml/qdeclarativeboundsignal_p.h
+++ b/src/declarative/qml/qdeclarativeboundsignal_p.h
@@ -54,6 +54,7 @@
//
#include "qdeclarativeexpression.h"
+#include "qdeclarativeguard_p.h"
#include <QtCore/qmetaobject.h>
@@ -67,6 +68,10 @@ class QDeclarativeAbstractBoundSignal : public QObject
public:
QDeclarativeAbstractBoundSignal(QObject *parent = 0);
virtual ~QDeclarativeAbstractBoundSignal() = 0;
+ virtual void disconnect() = 0;
+
+protected slots:
+ virtual void unregisterScopeObject() = 0;
};
class QDeclarativeBoundSignalParameters;
@@ -78,6 +83,8 @@ public:
const QMetaMethod &signal, QObject *parent);
virtual ~QDeclarativeBoundSignal();
+ void disconnect();
+
int index() const;
QDeclarativeExpression *expression() const;
@@ -88,14 +95,35 @@ public:
static QDeclarativeBoundSignal *cast(QObject *);
protected:
+ void unregisterScopeObject();
virtual int qt_metacall(QMetaObject::Call c, int id, void **a);
private:
+ class ScopeGuard : public QDeclarativeGuard<QObject>
+ {
+ public:
+ ScopeGuard(QObject *object, QDeclarativeBoundSignal *signal)
+ : QDeclarativeGuard<QObject>(object), m_signal(signal)
+ {
+ }
+
+ void objectDestroyed(QObject *obj) {
+ Q_UNUSED(obj);
+ m_signal->unregisterScopeObject();
+ }
+
+ private:
+ QDeclarativeBoundSignal *m_signal;
+ };
+
+ void init(QObject *parent);
+
QDeclarativeExpression *m_expression;
QMetaMethod m_signal;
bool m_paramsValid : 1;
bool m_isEvaluating : 1;
QDeclarativeBoundSignalParameters *m_params;
+ ScopeGuard m_scope;
};
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecompiledbindings.cpp b/src/declarative/qml/qdeclarativecompiledbindings.cpp
index 3ee365a560..5aefa4a917 100644
--- a/src/declarative/qml/qdeclarativecompiledbindings.cpp
+++ b/src/declarative/qml/qdeclarativecompiledbindings.cpp
@@ -216,7 +216,8 @@ public:
// Inherited from QDeclarativeAbstractBinding
virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags);
virtual void update(QDeclarativePropertyPrivate::WriteFlags flags);
- virtual void destroy();
+ virtual void destroy(DestroyMode mode);
+ virtual void disconnect(DisconnectMode disconnectMode);
int index:30;
bool enabled:1;
@@ -238,6 +239,7 @@ public:
QDeclarativeRefCount *dataRef;
Binding *m_bindings;
quint32 *m_signalTable;
+ bool m_bindingsDisconnected;
static int methodCount;
@@ -246,9 +248,10 @@ public:
QDeclarativeDelayedError *error, QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags);
- inline void unsubscribe(int subIndex);
inline void subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex);
inline void subscribe(QObject *o, int notifyIndex, int subIndex);
+ inline void disconnectAll();
+ inline void disconnectOne(Binding *bindingToDisconnect);
QDeclarativePropertyCache::Data *findproperty(QObject *obj,
const QScriptDeclarativeClass::Identifier &name,
@@ -268,7 +271,8 @@ public:
};
QDeclarativeCompiledBindingsPrivate::QDeclarativeCompiledBindingsPrivate()
-: subscriptions(0), identifiers(0), programData(0), dataRef(0), m_bindings(0), m_signalTable(0)
+ : subscriptions(0), identifiers(0), programData(0), dataRef(0), m_bindings(0), m_signalTable(0),
+ m_bindingsDisconnected(false)
{
}
@@ -343,14 +347,25 @@ void QDeclarativeCompiledBindingsPrivate::Binding::update(QDeclarativePropertyPr
QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding);
}
-void QDeclarativeCompiledBindingsPrivate::Binding::destroy()
+void QDeclarativeCompiledBindingsPrivate::Binding::destroy(DestroyMode mode)
{
+ if (mode == DisconnectBinding)
+ disconnect(QDeclarativeAbstractBinding::DisconnectOne);
+
enabled = false;
removeFromObject();
clear();
parent->q_func()->release();
}
+void QDeclarativeCompiledBindingsPrivate::Binding::disconnect(DisconnectMode disconnectMode)
+{
+ if (disconnectMode == QDeclarativeAbstractBinding::DisconnectAll)
+ parent->disconnectAll();
+ else
+ parent->disconnectOne(this);
+}
+
int QDeclarativeCompiledBindings::qt_metacall(QMetaObject::Call c, int id, void **)
{
Q_D(QDeclarativeCompiledBindings);
@@ -696,26 +711,20 @@ struct QDeclarativeBindingCompilerPrivate
QByteArray buildExceptionData() const;
};
-void QDeclarativeCompiledBindingsPrivate::unsubscribe(int subIndex)
-{
- QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
- sub->disconnect();
-}
-
void QDeclarativeCompiledBindingsPrivate::subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex)
{
Q_Q(QDeclarativeCompiledBindings);
- unsubscribe(subIndex);
+ QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
+ sub->disconnect();
if (p->idValues[idIndex]) {
- QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex);
sub->target = q;
sub->targetMethod = methodCount + subIndex;
sub->connect(&p->idValues[idIndex].bindings);
}
}
-
+
void QDeclarativeCompiledBindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex)
{
Q_Q(QDeclarativeCompiledBindings);
@@ -729,6 +738,43 @@ void QDeclarativeCompiledBindingsPrivate::subscribe(QObject *o, int notifyIndex,
sub->disconnect();
}
+void QDeclarativeCompiledBindingsPrivate::disconnectAll()
+{
+ // This gets called multiple times in QDeclarativeData::disconnectNotifiers(), avoid unneeded
+ // work for all but the first call.
+ if (m_bindingsDisconnected)
+ return;
+
+ // We disconnect all subscriptions, so we can call disconnect() unconditionally if there is at
+ // least one connection
+ Program *program = (Program *)programData;
+ for (int subIndex = 0; subIndex < program->subscriptions; ++subIndex) {
+ Subscription * const sub = (subscriptions + subIndex);
+ if (sub->isConnected())
+ sub->disconnect();
+ }
+ m_bindingsDisconnected = true;
+}
+
+void QDeclarativeCompiledBindingsPrivate::disconnectOne(
+ QDeclarativeCompiledBindingsPrivate::Binding *bindingToDisconnect)
+{
+ // We iterate over the signal table to find all subscriptions for this binding. This is slowish,
+ // but disconnectOne() is only called when overwriting a binding, which is quite rare.
+ Program *program = (Program *)programData;
+ for (int subIndex = 0; subIndex < program->subscriptions; ++subIndex) {
+ Subscription * const sub = (subscriptions + subIndex);
+ quint32 *reeval = m_signalTable + m_signalTable[subIndex];
+ quint32 bindingCount = *reeval;
+ ++reeval;
+ for (quint32 bindingIndex = 0; bindingIndex < bindingCount; ++bindingIndex) {
+ Binding * const binding = m_bindings + reeval[bindingIndex];
+ if (binding == bindingToDisconnect)
+ sub->deref();
+ }
+ }
+}
+
// Conversion functions - these MUST match the QtScript expression path
inline static qreal toReal(Register *reg, int type, bool *ok = 0)
{
diff --git a/src/declarative/qml/qdeclarativedata_p.h b/src/declarative/qml/qdeclarativedata_p.h
index 7d7140670d..0057840593 100644
--- a/src/declarative/qml/qdeclarativedata_p.h
+++ b/src/declarative/qml/qdeclarativedata_p.h
@@ -61,6 +61,7 @@ QT_BEGIN_NAMESPACE
class QDeclarativeGuardImpl;
class QDeclarativeCompiledData;
class QDeclarativeAbstractBinding;
+class QDeclarativeAbstractBoundSignal;
class QDeclarativeContext;
class QDeclarativePropertyCache;
class QDeclarativeContextData;
@@ -154,9 +155,12 @@ public:
bool hasExtendedData() const { return extendedData != 0; }
QDeclarativeNotifier *objectNameNotifier() const;
QHash<int, QObject *> *attachedProperties() const;
+ void addBoundSignal(QDeclarativeAbstractBoundSignal *signal);
+ void removeBoundSignal(QDeclarativeAbstractBoundSignal *signal);
+ void disconnectNotifiers();
private:
- // For objectNameNotifier and attachedProperties
+ // For objectNameNotifier, attachedProperties and bound signal list
mutable QDeclarativeDataExtended *extendedData;
};
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp
index a787fb69af..92a739115a 100644
--- a/src/declarative/qml/qdeclarativeengine.cpp
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -42,6 +42,7 @@
#include "private/qdeclarativeengine_p.h"
#include "qdeclarativeengine.h"
+#include "private/qdeclarativeboundsignal_p.h"
#include "private/qdeclarativecontext_p.h"
#include "private/qdeclarativecompiler_p.h"
#include "private/qdeclarativeglobalscriptclass_p.h"
@@ -547,6 +548,11 @@ void QDeclarativePrivate::qdeclarativeelement_destructor(QObject *o)
d->context->destroy();
d->context = 0;
}
+
+ // Disconnect the notifiers now - during object destruction this would be too late, since
+ // the disconnect call wouldn't be able to call disconnectNotify(), as it isn't possible to
+ // get the metaobject anymore.
+ d->disconnectNotifiers();
}
}
@@ -1108,6 +1114,7 @@ public:
QHash<int, QObject *> attachedProperties;
QDeclarativeNotifier objectNameNotifier;
+ QList<QDeclarativeAbstractBoundSignal *> boundSignals;
};
QDeclarativeDataExtended::QDeclarativeDataExtended()
@@ -1130,6 +1137,32 @@ QHash<int, QObject *> *QDeclarativeData::attachedProperties() const
return &extendedData->attachedProperties;
}
+void QDeclarativeData::addBoundSignal(QDeclarativeAbstractBoundSignal *signal)
+{
+ if (!extendedData) extendedData = new QDeclarativeDataExtended;
+ extendedData->boundSignals.append(signal);
+}
+
+void QDeclarativeData::removeBoundSignal(QDeclarativeAbstractBoundSignal *signal)
+{
+ if (extendedData)
+ extendedData->boundSignals.removeAll(signal);
+}
+
+void QDeclarativeData::disconnectNotifiers()
+{
+ QDeclarativeAbstractBinding *binding = bindings;
+ while (binding) {
+ binding->disconnect(QDeclarativeAbstractBinding::DisconnectAll);
+ binding = binding->m_nextBinding;
+ }
+
+ if (extendedData) {
+ Q_FOREACH (QDeclarativeAbstractBoundSignal *signal, extendedData->boundSignals)
+ signal->disconnect();
+ }
+}
+
void QDeclarativeData::destroyed(QObject *object)
{
if (deferredComponent)
@@ -1145,7 +1178,7 @@ void QDeclarativeData::destroyed(QObject *object)
QDeclarativeAbstractBinding *next = binding->m_nextBinding;
binding->m_prevBinding = 0;
binding->m_nextBinding = 0;
- binding->destroy();
+ binding->destroy(QDeclarativeAbstractBinding::KeepBindingConnected);
binding = next;
}
diff --git a/src/declarative/qml/qdeclarativenotifier.cpp b/src/declarative/qml/qdeclarativenotifier.cpp
index b6250380ec..a3fae936f8 100644
--- a/src/declarative/qml/qdeclarativenotifier.cpp
+++ b/src/declarative/qml/qdeclarativenotifier.cpp
@@ -71,8 +71,10 @@ void QDeclarativeNotifierEndpoint::connect(QObject *source, int sourceSignal)
{
Signal *s = toSignal();
- if (s->source == source && s->sourceSignal == sourceSignal)
+ if (s->source == source && s->sourceSignal == sourceSignal) {
+ refCount++;
return;
+ }
disconnect();
@@ -80,6 +82,7 @@ void QDeclarativeNotifierEndpoint::connect(QObject *source, int sourceSignal)
s->source = source;
s->sourceSignal = sourceSignal;
+ refCount++;
}
void QDeclarativeNotifierEndpoint::copyAndClear(QDeclarativeNotifierEndpoint &other)
diff --git a/src/declarative/qml/qdeclarativenotifier_p.h b/src/declarative/qml/qdeclarativenotifier_p.h
index 524a96697f..ee80c9a2be 100644
--- a/src/declarative/qml/qdeclarativenotifier_p.h
+++ b/src/declarative/qml/qdeclarativenotifier_p.h
@@ -43,6 +43,7 @@
#define QDECLARATIVENOTIFIER_P_H
#include "private/qdeclarativeguard_p.h"
+#include <QtCore/qmetaobject.h>
QT_BEGIN_NAMESPACE
@@ -77,8 +78,13 @@ public:
void connect(QObject *source, int sourceSignal);
inline void connect(QDeclarativeNotifier *);
+
+ // Disconnects unconditionally, regardless of the refcount
inline void disconnect();
+ // Decreases the refcount and disconnects when refcount reaches 0
+ inline void deref();
+
void copyAndClear(QDeclarativeNotifierEndpoint &other);
private:
@@ -110,6 +116,8 @@ private:
Notifier notifier;
};
+ quint16 refCount;
+
inline Notifier *toNotifier();
inline Notifier *asNotifier();
inline Signal *toSignal();
@@ -143,12 +151,12 @@ void QDeclarativeNotifier::notify()
}
QDeclarativeNotifierEndpoint::QDeclarativeNotifierEndpoint()
-: target(0), targetMethod(0), type(InvalidType)
+ : target(0), targetMethod(0), type(InvalidType), refCount(0)
{
}
QDeclarativeNotifierEndpoint::QDeclarativeNotifierEndpoint(QObject *t, int m)
-: target(t), targetMethod(m), type(InvalidType)
+: target(t), targetMethod(m), type(InvalidType), refCount(0)
{
}
@@ -186,8 +194,10 @@ void QDeclarativeNotifierEndpoint::connect(QDeclarativeNotifier *notifier)
{
Notifier *n = toNotifier();
- if (n->notifier == notifier)
+ if (n->notifier == notifier) {
+ refCount++;
return;
+ }
disconnect();
@@ -196,6 +206,7 @@ void QDeclarativeNotifierEndpoint::connect(QDeclarativeNotifier *notifier)
notifier->endpoints = this;
n->prev = &notifier->endpoints;
n->notifier = notifier;
+ refCount++;
}
void QDeclarativeNotifierEndpoint::disconnect()
@@ -204,6 +215,9 @@ void QDeclarativeNotifierEndpoint::disconnect()
Signal *s = asSignal();
if (s->source) {
QMetaObject::disconnectOne(s->source, s->sourceSignal, target, targetMethod);
+ QObjectPrivate * const priv = QObjectPrivate::get(s->source);
+ const QMetaMethod signal = s->source->metaObject()->method(s->sourceSignal);
+ priv->disconnectNotify(signal.signature());
s->source = 0;
}
} else if (type == NotifierType) {
@@ -217,6 +231,14 @@ void QDeclarativeNotifierEndpoint::disconnect()
n->disconnected = 0;
n->notifier = 0;
}
+ refCount = 0;
+}
+
+void QDeclarativeNotifierEndpoint::deref()
+{
+ refCount--;
+ if (refCount <= 0)
+ disconnect();
}
QDeclarativeNotifierEndpoint::Notifier *QDeclarativeNotifierEndpoint::toNotifier()
diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp
index 84f492d858..2867d27379 100644
--- a/src/declarative/qml/qdeclarativeproperty.cpp
+++ b/src/declarative/qml/qdeclarativeproperty.cpp
@@ -1626,13 +1626,17 @@ it connects any lazy "proxy" signal connections set up by QML.
It is possible that this logic should be moved to QMetaObject::connect().
*/
-bool QDeclarativePropertyPrivate::connect(const QObject *sender, int signal_index,
+bool QDeclarativePropertyPrivate::connect(QObject *sender, int signal_index,
const QObject *receiver, int method_index,
int type, int *types)
{
flush_vme_signal(sender, signal_index);
flush_vme_signal(receiver, method_index);
+ const QMetaMethod signal = sender->metaObject()->method(signal_index);
+ QObjectPrivate * const senderPriv = QObjectPrivate::get(sender);
+ senderPriv->connectNotify(signal.signature());
+
return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
}
diff --git a/src/declarative/qml/qdeclarativeproperty_p.h b/src/declarative/qml/qdeclarativeproperty_p.h
index 21e33419b3..4847445b97 100644
--- a/src/declarative/qml/qdeclarativeproperty_p.h
+++ b/src/declarative/qml/qdeclarativeproperty_p.h
@@ -134,7 +134,7 @@ public:
static int valueTypeCoreIndex(const QDeclarativeProperty &that);
static int bindingIndex(const QDeclarativeProperty &that);
static QMetaMethod findSignalByName(const QMetaObject *mo, const QByteArray &);
- static bool connect(const QObject *sender, int signal_index,
+ static bool connect(QObject *sender, int signal_index,
const QObject *receiver, int method_index,
int type = 0, int *types = 0);
static const QMetaObject *metaObjectForProperty(const QMetaObject *, int);