summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@qt.io>2020-03-27 14:02:59 +0100
committerSimon Hausmann <simon.hausmann@qt.io>2020-04-06 14:25:12 +0200
commit549712830ba6e8cfe603d22a47190b15f60c7072 (patch)
treef4ce74b351c8b2d58d80b6b611e050498d1eae2c /src/corelib
parentbee2bfc6c6b0d075eb4ba5cc2f158b2eabcbcbb6 (diff)
QProperty: Add support for member function change handlers
When a class has multiple QProperty members to implement functionality, it is common to have functions in the class that react to changes. For example to emit a compatibility signal, in case of Qt Quick to mark the scene graph as dirty, etc. etc. To faciliate this use-case, this patch adds an internal QPropertyMemberChangeHandler template that allows connecting a QProperty field to a member function callback. At the moment that callback is still 3 * sizeof(pointer). This could in theory be reduced to 2 by eliminating the back-pointer (prev) as the observer lives as long as the property. That however belongs into maybe a future patch. In order to get a pointer back to the surrounding object that holds the QProperty as well as provides the callback function, the property system was changed to pass through the address of the QProperty member at run-time, and at compile time the delta from the QProperty member to the beginning of the surrounding class is calculated. Through subtraction we obtain the pointer to the owning object. Change-Id: Ia2976357053f474ff44d0d6f60527c3b8e1f613a Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/kernel/qproperty.cpp12
-rw-r--r--src/corelib/kernel/qproperty.h33
-rw-r--r--src/corelib/kernel/qproperty_p.h4
-rw-r--r--src/corelib/kernel/qpropertybinding.cpp2
-rw-r--r--src/corelib/kernel/qpropertyprivate.h2
5 files changed, 38 insertions, 15 deletions
diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp
index 18580fa756..0e51226b34 100644
--- a/src/corelib/kernel/qproperty.cpp
+++ b/src/corelib/kernel/qproperty.cpp
@@ -226,11 +226,11 @@ void QPropertyBase::registerWithCurrentlyEvaluatingBinding() const
dependencyObserver.observeProperty(d);
}
-void QPropertyBase::notifyObservers()
+void QPropertyBase::notifyObservers(void *propertyDataPtr)
{
QPropertyBasePointer d{this};
if (QPropertyObserverPointer observer = d.firstObserver())
- observer.notify(d.bindingPtr());
+ observer.notify(d.bindingPtr(), propertyDataPtr);
}
int QPropertyBasePointer::observerCount() const
@@ -241,7 +241,7 @@ int QPropertyBasePointer::observerCount() const
return count;
}
-QPropertyObserver::QPropertyObserver(void (*callback)(QPropertyObserver*))
+QPropertyObserver::QPropertyObserver(void (*callback)(QPropertyObserver *, void *))
{
QPropertyObserverPointer d{this};
d.setChangeHandler(callback);
@@ -304,7 +304,7 @@ void QPropertyObserverPointer::unlink()
ptr->prev.clear();
}
-void QPropertyObserverPointer::setChangeHandler(void (*changeHandler)(QPropertyObserver *))
+void QPropertyObserverPointer::setChangeHandler(void (*changeHandler)(QPropertyObserver *, void *))
{
ptr->changeHandler = changeHandler;
ptr->next.setTag(QPropertyObserver::ObserverNotifiesChangeHandler);
@@ -316,7 +316,7 @@ void QPropertyObserverPointer::setBindingToMarkDirty(QPropertyBindingPrivate *bi
ptr->next.setTag(QPropertyObserver::ObserverNotifiesBinding);
}
-void QPropertyObserverPointer::notify(QPropertyBindingPrivate *triggeringBinding)
+void QPropertyObserverPointer::notify(QPropertyBindingPrivate *triggeringBinding, void *propertyDataPtr)
{
bool knownIfPropertyChanged = false;
bool propertyChanged =true;
@@ -334,7 +334,7 @@ void QPropertyObserverPointer::notify(QPropertyBindingPrivate *triggeringBinding
return;
if (auto handlerToCall = std::exchange(observer->changeHandler, nullptr)) {
- handlerToCall(observer);
+ handlerToCall(observer, propertyDataPtr);
observer->changeHandler = handlerToCall;
}
} else {
diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h
index 338c7bbeec..609bb85221 100644
--- a/src/corelib/kernel/qproperty.h
+++ b/src/corelib/kernel/qproperty.h
@@ -348,7 +348,7 @@ public:
private:
void notify()
{
- d.priv.notifyObservers();
+ d.priv.notifyObservers(&d);
}
Q_DISABLE_COPY(QProperty)
@@ -403,7 +403,7 @@ public:
{ setSource(property.d.priv); }
protected:
- QPropertyObserver(void (*callback)(QPropertyObserver*));
+ QPropertyObserver(void (*callback)(QPropertyObserver*, void *));
private:
void setSource(QtPrivate::QPropertyBase &property);
@@ -415,7 +415,7 @@ private:
union {
QPropertyBindingPrivate *bindingToMarkDirty = nullptr;
- void (*changeHandler)(QPropertyObserver*);
+ void (*changeHandler)(QPropertyObserver*, void *);
};
QPropertyObserver(const QPropertyObserver &) = delete;
@@ -434,7 +434,7 @@ class QPropertyChangeHandler : public QPropertyObserver
Functor m_handler;
public:
QPropertyChangeHandler(Functor handler)
- : QPropertyObserver([](QPropertyObserver *self) {
+ : QPropertyObserver([](QPropertyObserver *self, void *) {
auto This = static_cast<QPropertyChangeHandler<Functor>*>(self);
This->m_handler();
})
@@ -444,7 +444,7 @@ public:
template <typename PropertyType>
QPropertyChangeHandler(const QProperty<PropertyType> &property, Functor handler)
- : QPropertyObserver([](QPropertyObserver *self) {
+ : QPropertyObserver([](QPropertyObserver *self, void *) {
auto This = static_cast<QPropertyChangeHandler<Functor>*>(self);
This->m_handler();
})
@@ -475,6 +475,29 @@ QPropertyChangeHandler<Functor> QProperty<T>::subscribe(Functor f)
return onValueChanged(f);
}
+template <auto propertyMember, auto callbackMember>
+struct QPropertyMemberChangeHandler;
+
+template<typename Class, typename PropertyType, PropertyType Class::* PropertyMember, void(Class::*Callback)()>
+struct QPropertyMemberChangeHandler<PropertyMember, Callback> : public QPropertyObserver
+{
+ QPropertyMemberChangeHandler(Class *obj)
+ : QPropertyObserver(notify)
+ {
+ setSource(obj->*PropertyMember);
+ }
+
+ static void notify(QPropertyObserver *, void *propertyDataPtr)
+ {
+ // memberOffset is the offset of the QProperty<> member within the class. We get the absolute address
+ // of that member and subtracting the relative offset gives us the address of the class instance.
+ const size_t memberOffset = reinterpret_cast<size_t>(&(static_cast<Class *>(nullptr)->*PropertyMember));
+ Class *obj = reinterpret_cast<Class *>(reinterpret_cast<char *>(propertyDataPtr) - memberOffset);
+ (obj->*Callback)();
+ }
+};
+
+
QT_END_NAMESPACE
#endif // QPROPERTY_H
diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h
index a50ae0dee1..13cdb311c1 100644
--- a/src/corelib/kernel/qproperty_p.h
+++ b/src/corelib/kernel/qproperty_p.h
@@ -86,9 +86,9 @@ struct QPropertyObserverPointer
void unlink();
void setBindingToMarkDirty(QPropertyBindingPrivate *binding);
- void setChangeHandler(void (*changeHandler)(QPropertyObserver*));
+ void setChangeHandler(void (*changeHandler)(QPropertyObserver *, void *));
- void notify(QPropertyBindingPrivate *triggeringBinding);
+ void notify(QPropertyBindingPrivate *triggeringBinding, void *propertyDataPtr);
void observeProperty(QPropertyBasePointer property);
explicit operator bool() const { return ptr != nullptr; }
diff --git a/src/corelib/kernel/qpropertybinding.cpp b/src/corelib/kernel/qpropertybinding.cpp
index aa7bf1d022..8fdf770d18 100644
--- a/src/corelib/kernel/qpropertybinding.cpp
+++ b/src/corelib/kernel/qpropertybinding.cpp
@@ -63,7 +63,7 @@ void QPropertyBindingPrivate::markDirtyAndNotifyObservers()
{
dirty = true;
if (firstObserver)
- firstObserver.notify(this);
+ firstObserver.notify(this, propertyDataPtr);
}
bool QPropertyBindingPrivate::evaluateIfDirtyAndReturnTrueIfValueChanged()
diff --git a/src/corelib/kernel/qpropertyprivate.h b/src/corelib/kernel/qpropertyprivate.h
index b4f2cd5154..1329ec6682 100644
--- a/src/corelib/kernel/qpropertyprivate.h
+++ b/src/corelib/kernel/qpropertyprivate.h
@@ -89,7 +89,7 @@ public:
void removeBinding();
void registerWithCurrentlyEvaluatingBinding() const;
- void notifyObservers();
+ void notifyObservers(void *propertyDataPtr);
void setExtraBit(bool b)
{