Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
qproperty_p.h
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QPROPERTY_P_H
5#define QPROPERTY_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists for the convenience
12// of a number of Qt sources files. This header file may change from
13// version to version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <private/qglobal_p.h>
19#include <qproperty.h>
20
21#include <qmetaobject.h>
22#include <qscopedpointer.h>
24#include <qvariant.h>
25#include <vector>
26#include <QtCore/QVarLengthArray>
27
29
30namespace QtPrivate {
31 Q_CORE_EXPORT bool isAnyBindingEvaluating();
33}
34
35
43{
44private:
45 QPropertyObserver *d = nullptr;
46public:
50 { qt_ptr_swap(d, other.d); }
51 QBindingObserverPtr(QBindingObserverPtr &&other) noexcept : d(std::exchange(other.d, nullptr)) {}
53
54
55 inline QBindingObserverPtr(QPropertyObserver *observer) noexcept;
56 inline ~QBindingObserverPtr();
57 inline QPropertyBindingPrivate *binding() const noexcept;
58 inline QPropertyObserver *operator ->();
59};
60
62
63// Keep all classes related to QProperty in one compilation unit. Performance of this code is crucial and
64// we need to allow the compiler to inline where it makes sense.
65
66// This is a helper "namespace"
68{
70
72 {
73 return ptr->binding();
74 }
75
77 {
78 auto &d = ptr->d_ref();
79 observer->prev = reinterpret_cast<QPropertyObserver**>(&d);
80 d = reinterpret_cast<quintptr>(observer);
81 }
82 static void fixupAfterMove(QtPrivate::QPropertyBindingData *ptr);
83 void Q_ALWAYS_INLINE addObserver(QPropertyObserver *observer);
84 inline void setFirstObserver(QPropertyObserver *observer);
85 inline QPropertyObserverPointer firstObserver() const;
87
88 inline int observerCount() const;
89
90 template <typename T>
92 {
93 return QPropertyBindingDataPointer{&property.bindingData()};
94 }
95};
96
98{
99 Q_DISABLE_COPY_MOVE(QPropertyObserverNodeProtector)
100
104 {
105 // insert m_placeholder after observer into the linked list
106 QPropertyObserver *next = observer->next.data();
107 m_placeHolder.next = next;
108 observer->next = static_cast<QPropertyObserver *>(&m_placeHolder);
109 if (next)
110 next->prev = &m_placeHolder.next;
111 m_placeHolder.prev = &observer->next;
113 }
114
115 QPropertyObserver *next() const { return m_placeHolder.next.data(); }
116
118};
119
120// This is a helper "namespace"
122{
124
125 void unlink()
126 {
127 unlink_common();
128#if QT_DEPRECATED_SINCE(6, 6)
129 if (ptr->next.tag() == QPropertyObserver::ObserverIsAlias)
130 ptr->aliasData = nullptr;
131#endif
132 }
133
135 {
136#if QT_DEPRECATED_SINCE(6, 6)
137 Q_ASSERT(ptr->next.tag() != QPropertyObserver::ObserverIsAlias);
138#endif
139 unlink_common();
140 }
141
142 void setBindingToNotify(QPropertyBindingPrivate *binding);
143 void setBindingToNotify_unsafe(QPropertyBindingPrivate *binding);
144 void setChangeHandler(QPropertyObserver::ChangeHandler changeHandler);
145
146 enum class Notify {Everything, OnlyChangeHandlers};
147
148 void notify(QUntypedPropertyData *propertyDataPtr);
149#ifndef QT_NO_DEBUG
150 void noSelfDependencies(QPropertyBindingPrivate *binding);
151#else
152 void noSelfDependencies(QPropertyBindingPrivate *) {}
153#endif
154 void evaluateBindings(PendingBindingObserverList &bindingObservers, QBindingStatus *status);
155 void observeProperty(QPropertyBindingDataPointer property);
156
157 explicit operator bool() const { return ptr != nullptr; }
158
159 QPropertyObserverPointer nextObserver() const { return {ptr->next.data()}; }
160
162 {
164 return ptr->binding;
165 };
166
167private:
168 void unlink_common()
169 {
170 if (ptr->next)
171 ptr->next->prev = ptr->prev;
172 if (ptr->prev)
173 ptr->prev.setPointer(ptr->next.data());
174 ptr->next = nullptr;
175 ptr->prev.clear();
176 }
177};
178
180{
181public:
184};
185
186namespace QtPrivate {
187
189{
192 {
193 *currentState = previousState;
194 }
195
197 BindingEvaluationState *previousState = nullptr;
198 BindingEvaluationState **currentState = nullptr;
200};
201
210{
213 {
214 *currentState = previousState;
215 *currentlyEvaluatingBindingList = bindingState;
216 }
218 CompatPropertySafePoint *previousState = nullptr;
219 CompatPropertySafePoint **currentState = nullptr;
220 QtPrivate::BindingEvaluationState **currentlyEvaluatingBindingList = nullptr;
221 QtPrivate::BindingEvaluationState *bindingState = nullptr;
222};
223
224}
225
227{
228private:
231
232 using ObserverArray = std::array<QPropertyObserver, 4>;
233
234private:
235
236 // used to detect binding loops for lazy evaluated properties
237 bool updating = false;
238 bool hasStaticObserver = false;
239 bool pendingNotify = false;
240 bool hasBindingWrapper:1;
241 // used to detect binding loops for eagerly evaluated properties
242 bool isQQmlPropertyBinding:1;
243 /* a sticky binding does not get removed in removeBinding
244 this is used to support QQmlPropertyData::DontRemoveBinding
245 in qtdeclarative
246 */
247 bool m_sticky:1;
248
250
251 union {
252 QtPrivate::QPropertyObserverCallback staticObserverCallback = nullptr;
254 };
255 ObserverArray inlineDependencyObservers; // for things we are observing
256
257 QPropertyObserverPointer firstObserver; // list of observers observing us
258 QScopedPointer<std::vector<QPropertyObserver>> heapObservers; // for things we are observing
259
260protected:
261 QUntypedPropertyData *propertyDataPtr = nullptr;
262
263 /* For bindings set up from C++, location stores where the binding was created in the C++ source
264 For QQmlPropertyBinding that information does not make sense, and the location in the QML file
265 is stored somewhere else. To make efficient use of the space, we instead provide a scratch space
266 for QQmlPropertyBinding (which stores further binding information there).
267 Anything stored in the union must be trivially destructible.
268 (checked in qproperty.cpp)
269 */
271 union {
273 struct {
274 std::byte declarativeExtraData[sizeof(QPropertyBindingSourceLocation) - sizeof(DeclarativeErrorCallback)];
276 };
277 };
278private:
280
281 QMetaType metaType;
282
283public:
284 static constexpr size_t getSizeEnsuringAlignment() {
285 constexpr auto align = alignof (std::max_align_t) - 1;
286 constexpr size_t sizeEnsuringAlignment = (sizeof(QPropertyBindingPrivate) + align) & ~align;
287 static_assert (sizeEnsuringAlignment % alignof (std::max_align_t) == 0,
288 "Required for placement new'ing the function behind it.");
289 return sizeEnsuringAlignment;
290 }
291
292
293 // public because the auto-tests access it, too.
294 size_t dependencyObserverCount = 0;
295
296 bool isUpdating() {return updating;}
297 void setSticky(bool keep = true) {m_sticky = keep;}
298 bool isSticky() {return m_sticky;}
299 void scheduleNotify() {pendingNotify = true;}
300
302 const QPropertyBindingSourceLocation &location, bool isQQmlPropertyBinding=false)
303 : hasBindingWrapper(false)
304 , isQQmlPropertyBinding(isQQmlPropertyBinding)
305 , m_sticky(false)
306 , vtable(vtable)
308 , metaType(metaType)
309 {}
311
312
313 void setProperty(QUntypedPropertyData *propertyPtr) { propertyDataPtr = propertyPtr; }
315 {
316 Q_ASSERT(!(callback && bindingWrapper));
317 if (callback) {
318 hasStaticObserver = true;
319 hasBindingWrapper = false;
320 staticObserverCallback = callback;
321 } else if (bindingWrapper) {
322 hasStaticObserver = false;
323 hasBindingWrapper = true;
324 staticBindingWrapper = bindingWrapper;
325 } else {
326 hasStaticObserver = false;
327 hasBindingWrapper = false;
328 staticObserverCallback = nullptr;
329 }
330 }
332 {
333 observer.ptr->prev = const_cast<QPropertyObserver **>(&firstObserver.ptr);
334 firstObserver = observer;
335 }
336
338 {
339 auto observers = firstObserver;
340 firstObserver.ptr = nullptr;
341 return observers;
342 }
343
344 void clearDependencyObservers();
345
347 if (dependencyObserverCount < inlineDependencyObservers.size()) {
348 ++dependencyObserverCount;
349 return {&inlineDependencyObservers[dependencyObserverCount - 1]};
350 }
351 return allocateDependencyObserver_slow();
352 }
353
354 QPropertyObserverPointer allocateDependencyObserver_slow();
355
357 {
358 if (!hasCustomVTable())
359 return this->location;
361 constexpr auto msg = "Custom location";
362 location.fileName = msg;
363 return location;
364 }
366 QMetaType valueMetaType() const { return metaType; }
367
368 void unlinkAndDeref();
369
370 bool evaluateRecursive(PendingBindingObserverList &bindingObservers, QBindingStatus *status = nullptr);
371
372 bool Q_ALWAYS_INLINE evaluateRecursive_inline(PendingBindingObserverList &bindingObservers, QBindingStatus *status);
373
374 void notifyNonRecursive(const PendingBindingObserverList &bindingObservers);
375 enum NotificationState : bool { Delayed, Sent };
376 NotificationState notifyNonRecursive();
377
379 { return static_cast<QPropertyBindingPrivate *>(binding.d.data()); }
380
382 { error = std::move(e); }
383
385 {
386 hasStaticObserver = false;
387 hasBindingWrapper = false;
388 propertyDataPtr = nullptr;
389 clearDependencyObservers();
390 }
391
392 static QPropertyBindingPrivate *currentlyEvaluatingBinding();
393
394 bool hasCustomVTable() const
395 {
396 return vtable->size == 0;
397 }
398
400 if (priv->hasCustomVTable()) {
401 // special hack for QQmlPropertyBinding which has a
402 // different memory layout than normal QPropertyBindings
403 priv->vtable->destroy(priv);
404 } else{
405 priv->~QPropertyBindingPrivate();
406 delete[] reinterpret_cast<std::byte *>(priv);
407 }
408 }
409};
410
412{
413 if (auto *b = binding()) {
414 b->firstObserver.ptr = observer;
415 return;
416 }
417 auto &d = ptr->d_ref();
418 d = reinterpret_cast<quintptr>(observer);
419}
420
422{
423 auto &d = ptr->d_ref();
424 if (ptr->isNotificationDelayed()) {
425 QPropertyProxyBindingData *proxy = ptr->proxyData();
427 proxy->originalBindingData = ptr;
428 }
429 // If QPropertyBindingData has been moved, and it has an observer
430 // we have to adjust the firstObserver's prev pointer to point to
431 // the moved to QPropertyBindingData's d_ptr
433 return; // nothing to do if the observer is stored in the binding
434 if (auto observer = reinterpret_cast<QPropertyObserver *>(d))
435 observer->prev = reinterpret_cast<QPropertyObserver **>(&d);
436}
437
439{
440 if (auto *b = binding())
441 return b->firstObserver;
442 return { reinterpret_cast<QPropertyObserver *>(ptr->d()) };
443}
444
450{
451 if (!ptr->isNotificationDelayed())
452 return nullptr;
453 return ptr->proxyData();
454}
455
457{
458 int count = 0;
459 for (auto observer = firstObserver(); observer; observer = observer.nextObserver())
460 ++count;
461 return count;
462}
463
464namespace QtPrivate {
465 Q_CORE_EXPORT bool isPropertyInBindingWrapper(const QUntypedPropertyData *property);
466 void Q_CORE_EXPORT initBindingStatusThreadId();
467}
468
469template<typename Class, typename T, auto Offset, auto Setter, auto Signal = nullptr,
470 auto Getter = nullptr>
472{
473 template<typename Property, typename>
475
477 using SignalTakesValue = std::is_invocable<decltype(Signal), Class, T>;
478 Class *owner()
479 {
480 char *that = reinterpret_cast<char *>(this);
481 return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
482 }
483 const Class *owner() const
484 {
485 char *that = const_cast<char *>(reinterpret_cast<const char *>(this));
486 return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
487 }
488
490 {
491 auto *thisData = static_cast<ThisType *>(dataPtr);
493 binding.vtable->call(type, &copy, binding.functor);
494 if constexpr (QTypeTraits::has_operator_equal_v<T>)
495 if (copy.valueBypassingBindings() == thisData->valueBypassingBindings())
496 return false;
497 // ensure value and setValue know we're currently evaluating our binding
498 QBindingStorage *storage = qGetBindingStorage(thisData->owner());
499 QtPrivate::CompatPropertySafePoint guardThis(storage->bindingStatus, thisData);
500 (thisData->owner()->*Setter)(copy.valueBypassingBindings());
501 return true;
502 }
503 bool inBindingWrapper(const QBindingStorage *storage) const
504 {
505 return storage->bindingStatus && storage->bindingStatus->currentCompatProperty
507 }
508
509 inline static T getPropertyValue(const QUntypedPropertyData *d) {
510 auto prop = static_cast<const ThisType *>(d);
511 if constexpr (std::is_null_pointer_v<decltype(Getter)>)
512 return prop->value();
513 else
514 return (prop->owner()->*Getter)();
515 }
516
517public:
521
523 explicit QObjectCompatProperty(const T &initialValue) : QPropertyData<T>(initialValue) {}
524 explicit QObjectCompatProperty(T &&initialValue) : QPropertyData<T>(std::move(initialValue)) {}
525
527 {
529 // make sure we don't register this binding as a dependency to itself
530 if (storage->bindingStatus && storage->bindingStatus->currentlyEvaluatingBinding && !inBindingWrapper(storage))
531 storage->registerDependency_helper(this);
532 return this->val;
533 }
534
536 {
537 if constexpr (QTypeTraits::is_dereferenceable_v<T>) {
538 return value();
539 } else if constexpr (std::is_pointer_v<T>) {
540 value();
541 return this->val;
542 } else {
543 return;
544 }
545 }
546
548 {
549 return value();
550 }
551
552 operator parameter_type() const
553 {
554 return value();
555 }
556
558 {
560 if (auto *bd = storage->bindingData(this)) {
561 // make sure we don't remove the binding if called from the bindingWrapper
562 if (bd->hasBinding() && !inBindingWrapper(storage))
563 bd->removeBinding_helper();
564 }
565 this->val = t;
566 }
567
569 {
570 setValue(newValue);
571 return *this;
572 }
573
575 {
577 QUntypedPropertyBinding oldBinding(bd->setBinding(newBinding, this, nullptr, bindingWrapper));
578 // notification is already handled in QPropertyBindingData::setBinding
579 return static_cast<QPropertyBinding<T> &>(oldBinding);
580 }
581
582 bool setBinding(const QUntypedPropertyBinding &newBinding)
583 {
584 if (!newBinding.isNull() && newBinding.valueMetaType() != QMetaType::fromType<T>())
585 return false;
586 setBinding(static_cast<const QPropertyBinding<T> &>(newBinding));
587 return true;
588 }
589
590#ifndef Q_QDOC
591 template <typename Functor>
594 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
595 {
596 return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
597 }
598#else
599 template <typename Functor>
600 QPropertyBinding<T> setBinding(Functor f);
601#endif
602
603 bool hasBinding() const {
604 auto *bd = qGetBindingStorage(owner())->bindingData(this);
605 return bd && bd->binding() != nullptr;
606 }
607
609 {
611 if (auto *bd = storage->bindingData(this)) {
612 // make sure we don't remove the binding if called from the bindingWrapper
613 if (bd->hasBinding() && !inBindingWrapper(storage))
614 bd->removeBinding_helper();
615 }
616 }
617
618 void notify()
619 {
621 if (auto bd = storage->bindingData(this, false)) {
622 // This partly duplicates QPropertyBindingData::notifyObservers because we want to
623 // check for inBindingWrapper() after checking for isNotificationDelayed() and
624 // firstObserver. This is because inBindingWrapper() is the most expensive check.
625 if (!bd->isNotificationDelayed()) {
627 if (QPropertyObserverPointer observer = d.firstObserver()) {
628 if (!inBindingWrapper(storage)) {
629 PendingBindingObserverList bindingObservers;
630 if (bd->notifyObserver_helper(this, storage, observer, bindingObservers)
631 == QtPrivate::QPropertyBindingData::Evaluated) {
632 // evaluateBindings() can trash the observers. We need to re-fetch here.
633 if (QPropertyObserverPointer observer = d.firstObserver())
634 observer.notify(this);
635 for (auto&& bindingObserver: bindingObservers)
636 bindingObserver.binding()->notifyNonRecursive();
637 }
638 }
639 }
640 }
641 }
642 if constexpr (!std::is_null_pointer_v<decltype(Signal)>) {
643 if constexpr (SignalTakesValue::value)
644 (owner()->*Signal)(getPropertyValue(this));
645 else
646 (owner()->*Signal)();
647 }
648 }
649
651 {
652 auto *bd = qGetBindingStorage(owner())->bindingData(this);
653 return static_cast<QPropertyBinding<T> &&>(QUntypedPropertyBinding(bd ? bd->binding() : nullptr));
654 }
655
657 {
658 return setBinding(QPropertyBinding<T>());
659 }
660
661 template<typename Functor>
663 {
664 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
665 return QPropertyChangeHandler<Functor>(*this, f);
666 }
667
668 template<typename Functor>
670 {
671 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
672 f();
673 return onValueChanged(f);
674 }
675
676 template<typename Functor>
678 {
679 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
680 return QPropertyNotifier(*this, f);
681 }
682
684 {
685 auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
686 return *storage->bindingData(const_cast<QObjectCompatProperty *>(this), true);
687 }
688};
689
690namespace QtPrivate {
691template<typename Class, typename Ty, auto Offset, auto Setter, auto Signal, auto Getter>
693 QObjectCompatProperty<Class, Ty, Offset, Setter, Signal, Getter>, std::void_t<Class>>
694{
696 using T = typename Property::value_type;
697public:
698 static constexpr QBindableInterface iface = {
699 [](const QUntypedPropertyData *d, void *value) -> void
700 { *static_cast<T*>(value) = Property::getPropertyValue(d); },
701 [](QUntypedPropertyData *d, const void *value) -> void
702 {
703 (static_cast<Property *>(d)->owner()->*Setter)(*static_cast<const T*>(value));
704 },
706 { return static_cast<const Property *>(d)->binding(); },
708 { return static_cast<Property *>(d)->setBinding(static_cast<const QPropertyBinding<T> &>(binding)); },
710 { return Qt::makePropertyBinding([d]() -> T { return Property::getPropertyValue(d); }, location); },
711 [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void
712 { observer->setSource(static_cast<const Property *>(d)->bindingData()); },
713 []() { return QMetaType::fromType<T>(); }
714 };
715};
716}
717
718#define QT_OBJECT_COMPAT_PROPERTY_4(Class, Type, name, setter) \
719 static constexpr size_t _qt_property_##name##_offset() { \
720 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
721 return offsetof(Class, name); \
722 QT_WARNING_POP \
723 } \
724 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter> name;
725
726#define QT_OBJECT_COMPAT_PROPERTY_5(Class, Type, name, setter, signal) \
727 static constexpr size_t _qt_property_##name##_offset() { \
728 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
729 return offsetof(Class, name); \
730 QT_WARNING_POP \
731 } \
732 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter, signal> name;
733
734#define Q_OBJECT_COMPAT_PROPERTY(...) \
735 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
736 QT_OVERLOADED_MACRO(QT_OBJECT_COMPAT_PROPERTY, __VA_ARGS__) \
737 QT_WARNING_POP
738
739#define QT_OBJECT_COMPAT_PROPERTY_WITH_ARGS_5(Class, Type, name, setter, value) \
740 static constexpr size_t _qt_property_##name##_offset() { \
741 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
742 return offsetof(Class, name); \
743 QT_WARNING_POP \
744 } \
745 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter> name = \
746 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter>( \
747 value);
748
749#define QT_OBJECT_COMPAT_PROPERTY_WITH_ARGS_6(Class, Type, name, setter, signal, value) \
750 static constexpr size_t _qt_property_##name##_offset() { \
751 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
752 return offsetof(Class, name); \
753 QT_WARNING_POP \
754 } \
755 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter, signal> name = \
756 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter, \
757 signal>(value);
758
759#define QT_OBJECT_COMPAT_PROPERTY_WITH_ARGS_7(Class, Type, name, setter, signal, getter, value) \
760 static constexpr size_t _qt_property_##name##_offset() { \
761 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
762 return offsetof(Class, name); \
763 QT_WARNING_POP \
764 } \
765 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter, signal, getter>\
766 name = QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter, \
767 signal, getter>(value);
768
769#define Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(...) \
770 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
771 QT_OVERLOADED_MACRO(QT_OBJECT_COMPAT_PROPERTY_WITH_ARGS, __VA_ARGS__) \
772 QT_WARNING_POP
773
774
775namespace QtPrivate {
776Q_CORE_EXPORT BindingEvaluationState *suspendCurrentBindingStatus();
777Q_CORE_EXPORT void restoreBindingStatus(BindingEvaluationState *status);
778}
779
781{
783 {
784 return bindable.iface;
785 }
786
788 {
789 return bindable.data;
790 }
791};
792
794{
795 if (updating) {
797 if (isQQmlPropertyBinding)
798 errorCallBack(this);
799 return false;
800 }
801
802 /*
803 * Evaluating the binding might lead to the binding being broken. This can
804 * cause ref to reach zero at the end of the function. However, the
805 * updateGuard's destructor will then still trigger, trying to set the
806 * updating bool to its old value
807 * To prevent this, we create a QPropertyBindingPrivatePtr which ensures
808 * that the object is still alive when updateGuard's dtor runs.
809 */
810 QPropertyBindingPrivatePtr keepAlive {this};
811
812 QScopedValueRollback<bool> updateGuard(updating, true);
813
814 QtPrivate::BindingEvaluationState evaluationFrame(this, status);
815
816 auto bindingFunctor = reinterpret_cast<std::byte *>(this) +
818 bool changed = false;
819 if (hasBindingWrapper) {
820 changed = staticBindingWrapper(metaType, propertyDataPtr,
821 {vtable, bindingFunctor});
822 } else {
823 changed = vtable->call(metaType, propertyDataPtr, bindingFunctor);
824 }
825 // If there was a change, we must set pendingNotify.
826 // If there was not, we must not clear it, as that only should happen in notifyRecursive
827 pendingNotify = pendingNotify || changed;
828 if (!changed || !firstObserver)
829 return changed;
830
831 firstObserver.noSelfDependencies(this);
832 firstObserver.evaluateBindings(bindingObservers, status);
833 return true;
834}
835
845{
846 auto observer = const_cast<QPropertyObserver*>(ptr);
847 /*
848 * The basic idea of the loop is as follows: We iterate over all observers in the linked list,
849 * and execute the functionality corresponding to their tag.
850 * However, complication arise due to the fact that the triggered operations might modify the list,
851 * which includes deletion and move of the current and next nodes.
852 * Therefore, we take a few safety precautions:
853 * 1. Before executing any action which might modify the list, we insert a placeholder node after the current node.
854 * As that one is stack allocated and owned by us, we can rest assured that it is
855 * still there after the action has executed, and placeHolder->next points to the actual next node in the list.
856 * Note that taking next at the beginning of the loop does not work, as the executed action might either move
857 * or delete that node.
858 * 2. After the triggered action has finished, we can use the next pointer in the placeholder node as a safe way to
859 * retrieve the next node.
860 * 3. Some care needs to be taken to avoid infinite recursion with change handlers, so we add an extra test there, that
861 * checks whether we're already have the same change handler in our call stack. This can be done by checking whether
862 * the node after the current one is a placeholder node.
863 */
864 while (observer) {
865 QPropertyObserver *next = observer->next.data();
866 switch (QPropertyObserver::ObserverTag(observer->next.tag())) {
868 {
869 auto handlerToCall = observer->changeHandler;
870 // prevent recursion
871 if (next && next->next.tag() == QPropertyObserver::ObserverIsPlaceholder) {
872 observer = next->next.data();
873 continue;
874 }
875 // handlerToCall might modify the list
876 QPropertyObserverNodeProtector protector(observer);
877 handlerToCall(observer, propertyDataPtr);
878 next = protector.next();
879 break;
880 }
882 break;
884 // recursion is already properly handled somewhere else
885 break;
886#if QT_DEPRECATED_SINCE(6, 6)
887 case QPropertyObserver::ObserverIsAlias:
888 break;
889#endif
890 default: Q_UNREACHABLE();
891 }
892 observer = next;
893 }
894}
895
897{
898 QPropertyObserverPointer d{static_cast<QPropertyObserver *>(&m_placeHolder)};
899 d.unlink_fast();
900}
901
903{
904 Q_ASSERT(d);
905 QPropertyObserverPointer{d}.binding()->addRef();
906}
907
909
911
913
914namespace QtPrivate {
916{
917 QPropertyBindingData bindingData_;
918 QObject *obj;
919 QMetaProperty metaProperty_;
920
921#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
922 static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret);
923#else
924 static void impl(QSlotObjectBase *this_, QObject *r, void **a, int which, bool *ret);
925#endif
926
928
929public:
931 {
932 if (ptr->isImpl(&QPropertyAdaptorSlotObject::impl)) {
933 auto p = static_cast<QPropertyAdaptorSlotObject *>(ptr);
934 if (p->metaProperty_.propertyIndex() == propertyIndex)
935 return p;
936 }
937 return nullptr;
938 }
939
940 inline const QPropertyBindingData &bindingData() const { return bindingData_; }
941 inline QPropertyBindingData &bindingData() { return bindingData_; }
942 inline QObject *object() const { return obj; }
943 inline const QMetaProperty &metaProperty() const { return metaProperty_; }
944
945 friend class QT_PREPEND_NAMESPACE(QUntypedBindable);
946};
947}
948
950
951#endif // QPROPERTY_P_H
QtPrivate::QPropertyBindingData * bindingData(const QUntypedPropertyData *data) const
\inmodule QtCore
\inmodule QtCore
Definition qmetatype.h:320
\macro Q_OBJECT_BINDABLE_PROPERTY(containingClass, type, name, signal)
QPropertyBinding< T > binding() const
typename QPropertyData< T >::value_type value_type
QtPrivate::QPropertyBindingData & bindingData() const
QObjectCompatProperty & operator=(parameter_type newValue)
typename QPropertyData< T >::arrow_operator_result arrow_operator_result
typename QPropertyData< T >::parameter_type parameter_type
parameter_type value() const
QObjectCompatProperty()=default
QPropertyChangeHandler< Functor > onValueChanged(Functor f)
void setValue(parameter_type t)
void removeBindingUnlessInWrapper()
bool setBinding(const QUntypedPropertyBinding &newBinding)
QPropertyBinding< T > setBinding(Functor &&f, const QPropertyBindingSourceLocation &location=QT_PROPERTY_DEFAULT_BINDING_LOCATION, std::enable_if_t< std::is_invocable_v< Functor > > *=nullptr)
arrow_operator_result operator->() const
QObjectCompatProperty(T &&initialValue)
QPropertyNotifier addNotifier(Functor f)
parameter_type operator*() const
QObjectCompatProperty(const T &initialValue)
QPropertyBinding< T > takeBinding()
QPropertyChangeHandler< Functor > subscribe(Functor f)
bool hasBinding() const
QPropertyBinding< T > setBinding(const QPropertyBinding< T > &newBinding)
\inmodule QtCore
Definition qobject.h:90
\inmodule QtCore
Definition qproperty.h:131
Type
This enum specifies which error occurred.
Definition qproperty.h:133
T * data() const noexcept
QPropertyBindingError bindingError() const
QMetaType valueMetaType() const
void setStaticObserver(QtPrivate::QPropertyObserverCallback callback, QtPrivate::QPropertyBindingWrapper bindingWrapper)
QPropertyBindingSourceLocation sourceLocation() const
QPropertyBindingSourceLocation location
QPropertyObserverPointer takeObservers()
void setSticky(bool keep=true)
static constexpr size_t getSizeEnsuringAlignment()
void setProperty(QUntypedPropertyData *propertyPtr)
QPropertyBindingPrivate(QMetaType metaType, const QtPrivate::BindingFunctionVTable *vtable, const QPropertyBindingSourceLocation &location, bool isQQmlPropertyBinding=false)
static void destroyAndFreeMemory(QPropertyBindingPrivate *priv)
Q_ALWAYS_INLINE QPropertyObserverPointer allocateDependencyObserver()
bool hasCustomVTable() const
void setError(QPropertyBindingError &&e)
bool Q_ALWAYS_INLINE evaluateRecursive_inline(PendingBindingObserverList &bindingObservers, QBindingStatus *status)
void(*)(QPropertyBindingPrivate *) DeclarativeErrorCallback
static QPropertyBindingPrivate * get(const QUntypedPropertyBinding &binding)
DeclarativeErrorCallback errorCallBack
QtPrivate::QPropertyBindingWrapper staticBindingWrapper
void prependObserver(QPropertyObserverPointer observer)
\inmodule QtCore
Definition qproperty.h:291
\inmodule QtCore
Definition qproperty.h:69
std::conditional_t< UseReferences, const T &, T > parameter_type
Definition qproperty.h:78
std::conditional_t< std::is_pointer_v< T >, const T &, std::conditional_t< QTypeTraits::is_dereferenceable_v< T >, const T &, void > > arrow_operator_result
Definition qproperty.h:81
\inmodule QtCore
Definition qproperty.h:318
void(*)(QPropertyObserver *, QUntypedPropertyData *) ChangeHandler
Definition qproperty.h:236
\inmodule QtCore
Definition qproperty.h:349
\inmodule QtCore
\inmodule QtCore
Definition qshareddata.h:19
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
void setTag(Tag tag)
\inmodule QtCore
Definition qproperty.h:677
const QtPrivate::QBindableInterface * iface
Definition qproperty.h:681
QUntypedPropertyData * data
Definition qproperty.h:680
QMetaType valueMetaType() const
Returns the meta-type of the binding.
bool isNull() const
Returns true if the QUntypedPropertyBinding is null.
QPropertyBindingData & bindingData()
const QMetaProperty & metaProperty() const
static QPropertyAdaptorSlotObject * cast(QSlotObjectBase *ptr, int propertyIndex)
const QPropertyBindingData & bindingData() const
QPropertyBindingPrivate * binding() const
QUntypedPropertyBinding setBinding(const QUntypedPropertyBinding &newBinding, QUntypedPropertyData *propertyDataPtr, QPropertyObserverCallback staticObserverCallback=nullptr, QPropertyBindingWrapper bindingWrapper=nullptr)
static constexpr quintptr BindingBit
double e
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
bool bindingWrapper(QMetaType type, QUntypedPropertyData *d, QtPrivate::QPropertyBindingFunction binding, QUntypedPropertyData *temp, void *value)
constexpr size_t getOffset(size_t o)
\macro QT_NAMESPACE
bool(*)(QMetaType, QUntypedPropertyData *dataPtr, QPropertyBindingFunction) QPropertyBindingWrapper
bool isAnyBindingEvaluating()
bool isPropertyInBindingWrapper(const QUntypedPropertyData *property)
void(*)(QUntypedPropertyData *) QPropertyObserverCallback
auto makePropertyBinding(Functor &&f, const QPropertyBindingSourceLocation &location=QT_PROPERTY_DEFAULT_BINDING_LOCATION, std::enable_if_t< std::is_invocable_v< Functor > > *=nullptr)
Definition qproperty.h:212
static jboolean copy(JNIEnv *, jobject)
#define Q_NODISCARD_CTOR
#define Q_ALWAYS_INLINE
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
quint16 Offset
return ret
static ControlElement< T > * ptr(QWidget *widget)
static const QMetaObjectPrivate * priv(const uint *data)
const QBindingStorage * qGetBindingStorage(const QObject *o)
Definition qobject.h:429
GLint location
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
[7]
GLboolean r
[2]
GLenum GLenum GLsizei count
GLfloat GLfloat f
GLenum type
GLhandleARB obj
[2]
GLuint GLfloat * val
GLdouble GLdouble t
Definition qopenglext.h:243
GLfloat GLfloat p
[1]
#define QT_PROPERTY_DEFAULT_BINDING_LOCATION
Definition qproperty.h:46
@ Everything
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
constexpr void qt_ptr_swap(T *&lhs, T *&rhs) noexcept
Definition qswap.h:43
size_t quintptr
Definition qtypes.h:72
const char property[13]
Definition qwizard.cpp:101
settings setValue("DataPump/bgcolor", color)
QStorageInfo storage
[1]
QSharedPointer< T > other(t)
[5]
QNetworkProxy proxy
[0]
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QBindingObserverPtr)
QBindingObserverPtr(QBindingObserverPtr &&other) noexcept
Definition qproperty_p.h:51
QBindingObserverPtr()=default
void swap(QBindingObserverPtr &other) noexcept
Definition qproperty_p.h:49
QPropertyObserver * operator->()
QPropertyBindingPrivate * binding() const noexcept
Q_DISABLE_COPY(QBindingObserverPtr)
static QPropertyProxyBindingData * proxyData(QtPrivate::QPropertyBindingData *ptr)
static void fixupAfterMove(QtPrivate::QPropertyBindingData *ptr)
static QPropertyBindingDataPointer get(QProperty< T > &property)
Definition qproperty_p.h:91
QPropertyBindingPrivate * binding() const
Definition qproperty_p.h:71
void setObservers(QPropertyObserver *observer)
Definition qproperty_p.h:76
QPropertyObserverPointer firstObserver() const
void setFirstObserver(QPropertyObserver *observer)
QPropertyObserver * next() const
void notify(QUntypedPropertyData *propertyDataPtr)
QPropertyBindingPrivate * binding() const
QPropertyObserver * ptr
QPropertyObserverPointer nextObserver() const
static QtPrivate::QBindableInterface const * getInterface(const QUntypedBindable &bindable)
static QUntypedPropertyData * getPropertyData(const QUntypedBindable &bindable)
QPropertyBindingPrivate * binding
QVarLengthArray< const QPropertyBindingData *, 8 > alreadyCaptureProperties
QUntypedPropertyData * property
const QtPrivate::BindingFunctionVTable * vtable