Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
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>
23#include <qvariant.h>
24#include <vector>
25#include <QtCore/QVarLengthArray>
26
27#include <memory>
28
30
31namespace QtPrivate {
32 Q_CORE_EXPORT bool isAnyBindingEvaluating();
34}
35
36
44{
45private:
46 QPropertyObserver *d = nullptr;
47public:
51 { qt_ptr_swap(d, other.d); }
52 QBindingObserverPtr(QBindingObserverPtr &&other) noexcept : d(std::exchange(other.d, nullptr)) {}
54
55
56 inline QBindingObserverPtr(QPropertyObserver *observer) noexcept;
57 inline ~QBindingObserverPtr();
58 inline QPropertyBindingPrivate *binding() const noexcept;
59 inline QPropertyObserver *operator ->();
60};
61
63
64// Keep all classes related to QProperty in one compilation unit. Performance of this code is crucial and
65// we need to allow the compiler to inline where it makes sense.
66
67// This is a helper "namespace"
69{
71
73 {
74 return ptr->binding();
75 }
76
78 {
79 auto &d = ptr->d_ref();
80 observer->prev = reinterpret_cast<QPropertyObserver**>(&d);
81 d = reinterpret_cast<quintptr>(observer);
82 }
83 static void fixupAfterMove(QtPrivate::QPropertyBindingData *ptr);
84 void Q_ALWAYS_INLINE addObserver(QPropertyObserver *observer);
85 inline void setFirstObserver(QPropertyObserver *observer);
86 inline QPropertyObserverPointer firstObserver() const;
88
89 inline int observerCount() const;
90
91 template <typename T>
93 {
94 return QPropertyBindingDataPointer{&property.bindingData()};
95 }
96};
97
99{
100 Q_DISABLE_COPY_MOVE(QPropertyObserverNodeProtector)
101
105 {
106 // insert m_placeholder after observer into the linked list
107 QPropertyObserver *next = observer->next.data();
108 m_placeHolder.next = next;
109 observer->next = static_cast<QPropertyObserver *>(&m_placeHolder);
110 if (next)
111 next->prev = &m_placeHolder.next;
112 m_placeHolder.prev = &observer->next;
114 }
115
116 QPropertyObserver *next() const { return m_placeHolder.next.data(); }
117
119};
120
121// This is a helper "namespace"
123{
125
126 void unlink()
127 {
128 unlink_common();
129#if QT_DEPRECATED_SINCE(6, 6)
131 if (ptr->next.tag() == QPropertyObserver::ObserverIsAlias)
132 ptr->aliasData = nullptr;
134#endif
135 }
136
138 {
139#if QT_DEPRECATED_SINCE(6, 6)
141 Q_ASSERT(ptr->next.tag() != QPropertyObserver::ObserverIsAlias);
143#endif
144 unlink_common();
145 }
146
148 {
150 ptr->binding = binding;
152 }
153
154 void setBindingToNotify_unsafe(QPropertyBindingPrivate *binding);
155 void setChangeHandler(QPropertyObserver::ChangeHandler changeHandler);
156
157 enum class Notify {Everything, OnlyChangeHandlers};
158
159 void notify(QUntypedPropertyData *propertyDataPtr);
160#ifndef QT_NO_DEBUG
161 void noSelfDependencies(QPropertyBindingPrivate *binding);
162#else
163 void noSelfDependencies(QPropertyBindingPrivate *) {}
164#endif
165 void evaluateBindings(PendingBindingObserverList &bindingObservers, QBindingStatus *status);
166 void observeProperty(QPropertyBindingDataPointer property);
167
168 explicit operator bool() const { return ptr != nullptr; }
169
170 QPropertyObserverPointer nextObserver() const { return {ptr->next.data()}; }
171
173 {
175 return ptr->binding;
176 }
177
178private:
179 void unlink_common()
180 {
181 if (ptr->next)
182 ptr->next->prev = ptr->prev;
183 if (ptr->prev)
184 ptr->prev.setPointer(ptr->next.data());
185 ptr->next = nullptr;
186 ptr->prev.clear();
187 }
188};
189
196
197namespace QtPrivate {
198
200{
203 {
204 *currentState = previousState;
205 }
206
208 BindingEvaluationState *previousState = nullptr;
209 BindingEvaluationState **currentState = nullptr;
210 QVarLengthArray<const QPropertyBindingData *, 8> alreadyCaptureProperties;
211};
212
221{
224 {
225 *currentState = previousState;
226 *currentlyEvaluatingBindingList = bindingState;
227 }
229 CompatPropertySafePoint *previousState = nullptr;
230 CompatPropertySafePoint **currentState = nullptr;
231 QtPrivate::BindingEvaluationState **currentlyEvaluatingBindingList = nullptr;
232 QtPrivate::BindingEvaluationState *bindingState = nullptr;
233};
234
243{
244 Q_DISABLE_COPY_MOVE(CurrentCompatPropertyThief)
245public:
247 : status(&status->currentCompatProperty)
248 , stolen(std::exchange(status->currentCompatProperty, nullptr))
249 {
250 }
251
253 {
254 *status = stolen;
255 }
256
257private:
258 CompatPropertySafePoint **status = nullptr;
259 CompatPropertySafePoint *stolen = nullptr;
260};
261
262}
263
265{
266private:
269
270 using ObserverArray = std::array<QPropertyObserver, 4>;
271
272private:
273
274 // used to detect binding loops for lazy evaluated properties
275 bool updating = false;
276 bool hasStaticObserver = false;
277 bool pendingNotify = false;
278 bool hasBindingWrapper:1;
279 // used to detect binding loops for eagerly evaluated properties
280 bool isQQmlPropertyBinding:1;
281 /* a sticky binding does not get removed in removeBinding
282 this is used to support QQmlPropertyData::DontRemoveBinding
283 in qtdeclarative
284 */
285 bool m_sticky:1;
286
288
289 union {
290 QtPrivate::QPropertyObserverCallback staticObserverCallback = nullptr;
292 };
293 ObserverArray inlineDependencyObservers; // for things we are observing
294
295 QPropertyObserverPointer firstObserver; // list of observers observing us
296 std::unique_ptr<std::vector<QPropertyObserver>> heapObservers; // for things we are observing
297
298protected:
299 QUntypedPropertyData *propertyDataPtr = nullptr;
300
301 /* For bindings set up from C++, location stores where the binding was created in the C++ source
302 For QQmlPropertyBinding that information does not make sense, and the location in the QML file
303 is stored somewhere else. To make efficient use of the space, we instead provide a scratch space
304 for QQmlPropertyBinding (which stores further binding information there).
305 Anything stored in the union must be trivially destructible.
306 (checked in qproperty.cpp)
307 */
309 union {
311 struct {
312 std::byte declarativeExtraData[sizeof(QPropertyBindingSourceLocation) - sizeof(DeclarativeErrorCallback)];
314 };
315 };
316private:
318
319 QMetaType metaType;
320
321public:
322 static constexpr size_t getSizeEnsuringAlignment() {
323 constexpr auto align = alignof (std::max_align_t) - 1;
324 constexpr size_t sizeEnsuringAlignment = (sizeof(QPropertyBindingPrivate) + align) & ~align;
325 static_assert (sizeEnsuringAlignment % alignof (std::max_align_t) == 0,
326 "Required for placement new'ing the function behind it.");
327 return sizeEnsuringAlignment;
328 }
329
330
331 // public because the auto-tests access it, too.
332 size_t dependencyObserverCount = 0;
333
334 bool isUpdating() {return updating;}
335 void setSticky(bool keep = true) {m_sticky = keep;}
336 bool isSticky() {return m_sticky;}
337 void scheduleNotify() {pendingNotify = true;}
338
340 const QPropertyBindingSourceLocation &location, bool isQQmlPropertyBinding=false)
341 : hasBindingWrapper(false)
342 , isQQmlPropertyBinding(isQQmlPropertyBinding)
343 , m_sticky(false)
344 , vtable(vtable)
346 , metaType(metaType)
347 {}
349
350
351 void setProperty(QUntypedPropertyData *propertyPtr) { propertyDataPtr = propertyPtr; }
353 {
354 Q_ASSERT(!(callback && bindingWrapper));
355 if (callback) {
356 hasStaticObserver = true;
357 hasBindingWrapper = false;
358 staticObserverCallback = callback;
359 } else if (bindingWrapper) {
360 hasStaticObserver = false;
361 hasBindingWrapper = true;
362 staticBindingWrapper = bindingWrapper;
363 } else {
364 hasStaticObserver = false;
365 hasBindingWrapper = false;
366 staticObserverCallback = nullptr;
367 }
368 }
370 {
371 observer.ptr->prev = const_cast<QPropertyObserver **>(&firstObserver.ptr);
372 firstObserver = observer;
373 }
374
376 {
377 auto observers = firstObserver;
378 firstObserver.ptr = nullptr;
379 return observers;
380 }
381
382 void clearDependencyObservers();
383
385 if (dependencyObserverCount < inlineDependencyObservers.size()) {
386 ++dependencyObserverCount;
387 return {&inlineDependencyObservers[dependencyObserverCount - 1]};
388 }
389 return allocateDependencyObserver_slow();
390 }
391
392 QPropertyObserverPointer allocateDependencyObserver_slow();
393
395 {
396 if (!hasCustomVTable())
397 return this->location;
399 constexpr auto msg = "Custom location";
400 location.fileName = msg;
401 return location;
402 }
404 QMetaType valueMetaType() const { return metaType; }
405
406 void unlinkAndDeref();
407
408 bool evaluateRecursive(PendingBindingObserverList &bindingObservers, QBindingStatus *status = nullptr);
409
410 bool Q_ALWAYS_INLINE evaluateRecursive_inline(PendingBindingObserverList &bindingObservers, QBindingStatus *status);
411
412 void notifyNonRecursive(const PendingBindingObserverList &bindingObservers);
413 enum NotificationState : bool { Delayed, Sent };
414 NotificationState notifyNonRecursive();
415
417 { return static_cast<QPropertyBindingPrivate *>(binding.d.data()); }
418
420 { error = std::move(e); }
421
423 {
424 hasStaticObserver = false;
425 hasBindingWrapper = false;
426 propertyDataPtr = nullptr;
427 clearDependencyObservers();
428 }
429
430 static QPropertyBindingPrivate *currentlyEvaluatingBinding();
431
432 bool hasCustomVTable() const
433 {
434 return vtable->size == 0;
435 }
436
438 if (priv->hasCustomVTable()) {
439 // special hack for QQmlPropertyBinding which has a
440 // different memory layout than normal QPropertyBindings
441 priv->vtable->destroy(priv);
442 } else{
443 priv->~QPropertyBindingPrivate();
444 delete[] reinterpret_cast<std::byte *>(priv);
445 }
446 }
447};
448
450{
451 if (auto *b = binding()) {
452 b->firstObserver.ptr = observer;
453 return;
454 }
455 auto &d = ptr->d_ref();
456 d = reinterpret_cast<quintptr>(observer);
457}
458
460{
461 auto &d = ptr->d_ref();
462 if (ptr->isNotificationDelayed()) {
463 QPropertyProxyBindingData *proxy = ptr->proxyData();
465 proxy->originalBindingData = ptr;
466 }
467 // If QPropertyBindingData has been moved, and it has an observer
468 // we have to adjust the firstObserver's prev pointer to point to
469 // the moved to QPropertyBindingData's d_ptr
471 return; // nothing to do if the observer is stored in the binding
472 if (auto observer = reinterpret_cast<QPropertyObserver *>(d))
473 observer->prev = reinterpret_cast<QPropertyObserver **>(&d);
474}
475
477{
478 if (auto *b = binding())
479 return b->firstObserver;
480 return { reinterpret_cast<QPropertyObserver *>(ptr->d()) };
481}
482
488{
489 if (!ptr->isNotificationDelayed())
490 return nullptr;
491 return ptr->proxyData();
492}
493
495{
496 int count = 0;
497 for (auto observer = firstObserver(); observer; observer = observer.nextObserver())
498 ++count;
499 return count;
500}
501
502namespace QtPrivate {
503 Q_CORE_EXPORT bool isPropertyInBindingWrapper(const QUntypedPropertyData *property);
504 void Q_CORE_EXPORT initBindingStatusThreadId();
505}
506
507template<typename Class, typename T, auto Offset, auto Setter, auto Signal = nullptr,
508 auto Getter = nullptr>
510{
511 template<typename Property, typename>
513
514 using ThisType = QObjectCompatProperty<Class, T, Offset, Setter, Signal, Getter>;
515 using SignalTakesValue = std::is_invocable<decltype(Signal), Class, T>;
516 Class *owner()
517 {
518 char *that = reinterpret_cast<char *>(this);
519 return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
520 }
521 const Class *owner() const
522 {
523 char *that = const_cast<char *>(reinterpret_cast<const char *>(this));
524 return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
525 }
526
528 {
529 auto *thisData = static_cast<ThisType *>(dataPtr);
530 QBindingStorage *storage = qGetBindingStorage(thisData->owner());
531 QPropertyData<T> copy;
532 {
534 binding.vtable->call(type, &copy, binding.functor);
535 if constexpr (QTypeTraits::has_operator_equal_v<T>)
536 if (copy.valueBypassingBindings() == thisData->valueBypassingBindings())
537 return false;
538 }
539 // ensure value and setValue know we're currently evaluating our binding
540 QtPrivate::CompatPropertySafePoint guardThis(storage->bindingStatus, thisData);
541 (thisData->owner()->*Setter)(copy.valueBypassingBindings());
542 return true;
543 }
544 bool inBindingWrapper(const QBindingStorage *storage) const
545 {
546 return storage->bindingStatus && storage->bindingStatus->currentCompatProperty
548 }
549
550 inline static T getPropertyValue(const QUntypedPropertyData *d) {
551 auto prop = static_cast<const ThisType *>(d);
552 if constexpr (std::is_null_pointer_v<decltype(Getter)>)
553 return prop->value();
554 else
555 return (prop->owner()->*Getter)();
556 }
557
558public:
562
564 explicit QObjectCompatProperty(const T &initialValue) : QPropertyData<T>(initialValue) {}
565 explicit QObjectCompatProperty(T &&initialValue) : QPropertyData<T>(std::move(initialValue)) {}
566
568 {
570 // make sure we don't register this binding as a dependency to itself
571 if (storage->bindingStatus && storage->bindingStatus->currentlyEvaluatingBinding && !inBindingWrapper(storage))
572 storage->registerDependency_helper(this);
573 return this->val;
574 }
575
577 {
578 if constexpr (QTypeTraits::is_dereferenceable_v<T>) {
579 return value();
580 } else if constexpr (std::is_pointer_v<T>) {
581 value();
582 return this->val;
583 } else {
584 return;
585 }
586 }
587
589 {
590 return value();
591 }
592
593 operator parameter_type() const
594 {
595 return value();
596 }
597
599 {
601 if (auto *bd = storage->bindingData(this)) {
602 // make sure we don't remove the binding if called from the bindingWrapper
603 if (bd->hasBinding() && !inBindingWrapper(storage))
604 bd->removeBinding_helper();
605 }
606 this->val = t;
607 }
608
610 {
611 setValue(newValue);
612 return *this;
613 }
614
615 QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding)
616 {
618 QUntypedPropertyBinding oldBinding(bd->setBinding(newBinding, this, nullptr, bindingWrapper));
619 // notification is already handled in QPropertyBindingData::setBinding
620 return static_cast<QPropertyBinding<T> &>(oldBinding);
621 }
622
623 bool setBinding(const QUntypedPropertyBinding &newBinding)
624 {
625 if (!newBinding.isNull() && newBinding.valueMetaType() != QMetaType::fromType<T>())
626 return false;
627 setBinding(static_cast<const QPropertyBinding<T> &>(newBinding));
628 return true;
629 }
630
631#ifndef Q_QDOC
632 template <typename Functor>
633 QPropertyBinding<T> setBinding(Functor &&f,
635 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
636 {
637 return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
638 }
639#else
640 template <typename Functor>
641 QPropertyBinding<T> setBinding(Functor f);
642#endif
643
644 bool hasBinding() const {
645 auto *bd = qGetBindingStorage(owner())->bindingData(this);
646 return bd && bd->binding() != nullptr;
647 }
648
650 {
652 if (auto *bd = storage->bindingData(this)) {
653 // make sure we don't remove the binding if called from the bindingWrapper
654 if (bd->hasBinding() && !inBindingWrapper(storage))
655 bd->removeBinding_helper();
656 }
657 }
658
659 void notify()
660 {
662 if (auto bd = storage->bindingData(this, false)) {
663 // This partly duplicates QPropertyBindingData::notifyObservers because we want to
664 // check for inBindingWrapper() after checking for isNotificationDelayed() and
665 // firstObserver. This is because inBindingWrapper() is the most expensive check.
666 if (!bd->isNotificationDelayed()) {
668 if (QPropertyObserverPointer observer = d.firstObserver()) {
669 if (!inBindingWrapper(storage)) {
670 PendingBindingObserverList bindingObservers;
671 if (bd->notifyObserver_helper(this, storage, observer, bindingObservers)
672 == QtPrivate::QPropertyBindingData::Evaluated) {
673 // evaluateBindings() can trash the observers. We need to re-fetch here.
674 if (QPropertyObserverPointer observer = d.firstObserver())
675 observer.notify(this);
676 for (auto&& bindingObserver: bindingObservers)
677 bindingObserver.binding()->notifyNonRecursive();
678 }
679 }
680 }
681 }
682 }
683 if constexpr (!std::is_null_pointer_v<decltype(Signal)>) {
684 if constexpr (SignalTakesValue::value)
685 (owner()->*Signal)(getPropertyValue(this));
686 else
687 (owner()->*Signal)();
688 }
689 }
690
691 QPropertyBinding<T> binding() const
692 {
693 auto *bd = qGetBindingStorage(owner())->bindingData(this);
694 return static_cast<QPropertyBinding<T> &&>(QUntypedPropertyBinding(bd ? bd->binding() : nullptr));
695 }
696
697 QPropertyBinding<T> takeBinding()
698 {
699 return setBinding(QPropertyBinding<T>());
700 }
701
702 template<typename Functor>
703 QPropertyChangeHandler<Functor> onValueChanged(Functor f)
704 {
705 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
706 return QPropertyChangeHandler<Functor>(*this, f);
707 }
708
709 template<typename Functor>
710 QPropertyChangeHandler<Functor> subscribe(Functor f)
711 {
712 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
713 f();
714 return onValueChanged(f);
715 }
716
717 template<typename Functor>
719 {
720 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
721 return QPropertyNotifier(*this, f);
722 }
723
725 {
726 auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
727 return *storage->bindingData(const_cast<QObjectCompatProperty *>(this), true);
728 }
729};
730
731namespace QtPrivate {
732template<typename Class, typename Ty, auto Offset, auto Setter, auto Signal, auto Getter>
734 QObjectCompatProperty<Class, Ty, Offset, Setter, Signal, Getter>, std::void_t<Class>>
735{
736 using Property = QObjectCompatProperty<Class, Ty, Offset, Setter, Signal, Getter>;
737 using T = typename Property::value_type;
738public:
739 static constexpr QBindableInterface iface = {
740 [](const QUntypedPropertyData *d, void *value) -> void
741 { *static_cast<T*>(value) = Property::getPropertyValue(d); },
742 [](QUntypedPropertyData *d, const void *value) -> void
743 {
744 (static_cast<Property *>(d)->owner()->*Setter)(*static_cast<const T*>(value));
745 },
747 { return static_cast<const Property *>(d)->binding(); },
749 { return static_cast<Property *>(d)->setBinding(static_cast<const QPropertyBinding<T> &>(binding)); },
751 { return Qt::makePropertyBinding([d]() -> T { return Property::getPropertyValue(d); }, location); },
752 [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void
753 { observer->setSource(static_cast<const Property *>(d)->bindingData()); },
754 []() { return QMetaType::fromType<T>(); }
755 };
756};
757}
758
759#define QT_OBJECT_COMPAT_PROPERTY_4(Class, Type, name, setter) \
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> name;
766
767#define QT_OBJECT_COMPAT_PROPERTY_5(Class, Type, name, setter, signal) \
768 static constexpr size_t _qt_property_##name##_offset() { \
769 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
770 return offsetof(Class, name); \
771 QT_WARNING_POP \
772 } \
773 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter, signal> name;
774
775#define Q_OBJECT_COMPAT_PROPERTY(...) \
776 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
777 QT_OVERLOADED_MACRO(QT_OBJECT_COMPAT_PROPERTY, __VA_ARGS__) \
778 QT_WARNING_POP
779
780#define QT_OBJECT_COMPAT_PROPERTY_WITH_ARGS_5(Class, Type, name, setter, value) \
781 static constexpr size_t _qt_property_##name##_offset() { \
782 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
783 return offsetof(Class, name); \
784 QT_WARNING_POP \
785 } \
786 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter> name = \
787 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter>( \
788 value);
789
790#define QT_OBJECT_COMPAT_PROPERTY_WITH_ARGS_6(Class, Type, name, setter, signal, value) \
791 static constexpr size_t _qt_property_##name##_offset() { \
792 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
793 return offsetof(Class, name); \
794 QT_WARNING_POP \
795 } \
796 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter, signal> name = \
797 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter, \
798 signal>(value);
799
800#define QT_OBJECT_COMPAT_PROPERTY_WITH_ARGS_7(Class, Type, name, setter, signal, getter, value) \
801 static constexpr size_t _qt_property_##name##_offset() { \
802 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
803 return offsetof(Class, name); \
804 QT_WARNING_POP \
805 } \
806 QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter, signal, getter>\
807 name = QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter, \
808 signal, getter>(value);
809
810#define Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(...) \
811 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
812 QT_OVERLOADED_MACRO(QT_OBJECT_COMPAT_PROPERTY_WITH_ARGS, __VA_ARGS__) \
813 QT_WARNING_POP
814
815
816namespace QtPrivate {
817Q_CORE_EXPORT BindingEvaluationState *suspendCurrentBindingStatus();
818Q_CORE_EXPORT void restoreBindingStatus(BindingEvaluationState *status);
819}
820
822{
824 {
825 return bindable.iface;
826 }
827
829 {
830 return bindable.data;
831 }
832};
833
835{
836 if (updating) {
838 if (isQQmlPropertyBinding)
839 errorCallBack(this);
840 return false;
841 }
842
843 /*
844 * Evaluating the binding might lead to the binding being broken. This can
845 * cause ref to reach zero at the end of the function. However, the
846 * updateGuard's destructor will then still trigger, trying to set the
847 * updating bool to its old value
848 * To prevent this, we create a QPropertyBindingPrivatePtr which ensures
849 * that the object is still alive when updateGuard's dtor runs.
850 */
851 QPropertyBindingPrivatePtr keepAlive {this};
852
853 QScopedValueRollback<bool> updateGuard(updating, true);
854
855 QtPrivate::BindingEvaluationState evaluationFrame(this, status);
856
857 auto bindingFunctor = reinterpret_cast<std::byte *>(this) +
859 bool changed = false;
860 if (hasBindingWrapper) {
861 changed = staticBindingWrapper(metaType, propertyDataPtr,
862 {vtable, bindingFunctor});
863 } else {
864 changed = vtable->call(metaType, propertyDataPtr, bindingFunctor);
865 }
866 // If there was a change, we must set pendingNotify.
867 // If there was not, we must not clear it, as that only should happen in notifyRecursive
868 pendingNotify = pendingNotify || changed;
869 if (!changed || !firstObserver)
870 return changed;
871
872 firstObserver.noSelfDependencies(this);
873 firstObserver.evaluateBindings(bindingObservers, status);
874 return true;
875}
876
886{
887 auto observer = const_cast<QPropertyObserver*>(ptr);
888 /*
889 * The basic idea of the loop is as follows: We iterate over all observers in the linked list,
890 * and execute the functionality corresponding to their tag.
891 * However, complication arise due to the fact that the triggered operations might modify the list,
892 * which includes deletion and move of the current and next nodes.
893 * Therefore, we take a few safety precautions:
894 * 1. Before executing any action which might modify the list, we insert a placeholder node after the current node.
895 * As that one is stack allocated and owned by us, we can rest assured that it is
896 * still there after the action has executed, and placeHolder->next points to the actual next node in the list.
897 * Note that taking next at the beginning of the loop does not work, as the executed action might either move
898 * or delete that node.
899 * 2. After the triggered action has finished, we can use the next pointer in the placeholder node as a safe way to
900 * retrieve the next node.
901 * 3. Some care needs to be taken to avoid infinite recursion with change handlers, so we add an extra test there, that
902 * checks whether we're already have the same change handler in our call stack. This can be done by checking whether
903 * the node after the current one is a placeholder node.
904 */
905 while (observer) {
906 QPropertyObserver *next = observer->next.data();
907 switch (QPropertyObserver::ObserverTag(observer->next.tag())) {
909 {
910 auto handlerToCall = observer->changeHandler;
911 // prevent recursion
912 if (next && next->next.tag() == QPropertyObserver::ObserverIsPlaceholder) {
913 observer = next->next.data();
914 continue;
915 }
916 // handlerToCall might modify the list
917 QPropertyObserverNodeProtector protector(observer);
918 handlerToCall(observer, propertyDataPtr);
919 next = protector.next();
920 break;
921 }
923 break;
925 // recursion is already properly handled somewhere else
926 break;
927#if QT_DEPRECATED_SINCE(6, 6)
929 case QPropertyObserver::ObserverIsAlias:
930 break;
932#endif
933 default: Q_UNREACHABLE();
934 }
935 observer = next;
936 }
937}
938
940{
941 QPropertyObserverPointer d{static_cast<QPropertyObserver *>(&m_placeHolder)};
942 d.unlink_fast();
943}
944
946{
947 Q_ASSERT(d);
948 QPropertyObserverPointer{d}.binding()->addRef();
949}
950
952{
953 if (!d)
954 return;
955
956 QPropertyBindingPrivate *bindingPrivate = binding();
957 if (!bindingPrivate->deref())
959}
960
962
964
965namespace QtPrivate {
967{
968 QPropertyBindingData bindingData_;
969 QObject *obj;
970 QMetaProperty metaProperty_;
971
972#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
973 static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret);
974#else
975 static void impl(QSlotObjectBase *this_, QObject *r, void **a, int which, bool *ret);
976#endif
977
979
980public:
982 {
983 if (ptr->isImpl(&QPropertyAdaptorSlotObject::impl)) {
984 auto p = static_cast<QPropertyAdaptorSlotObject *>(ptr);
985 if (p->metaProperty_.propertyIndex() == propertyIndex)
986 return p;
987 }
988 return nullptr;
989 }
990
991 inline const QPropertyBindingData &bindingData() const { return bindingData_; }
992 inline QPropertyBindingData &bindingData() { return bindingData_; }
993 inline QObject *object() const { return obj; }
994 inline const QMetaProperty &metaProperty() const { return metaProperty_; }
995
996 friend class QT_PREPEND_NAMESPACE(QUntypedBindable);
997};
998}
999
1001
1002#endif // QPROPERTY_P_H
QtPrivate::QPropertyBindingData * bindingData(const QUntypedPropertyData *data) const
\inmodule QtCore
\inmodule QtCore
Definition qmetatype.h:341
\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:103
\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:69
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:80
std::conditional_t< UseReferences, const T &, T > parameter_type
Definition qproperty.h:78
\inmodule QtCore
Definition qproperty.h:319
void(*)(QPropertyObserver *, QUntypedPropertyData *) ChangeHandler
Definition qproperty.h:236
\inmodule QtCore
Definition qshareddata.h:19
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
void setTag(Tag tag)
\inmodule QtCore
Definition qproperty.h:679
const QtPrivate::QBindableInterface * iface
Definition qproperty.h:683
QUntypedPropertyData * data
Definition qproperty.h:682
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
static constexpr quintptr BindingBit
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_NO_KEYWORDS >
bool isAnyBindingEvaluating()
void(*)(QUntypedPropertyData *) QPropertyObserverCallback
bool(*)(QMetaType, QUntypedPropertyData *dataPtr, QPropertyBindingFunction) QPropertyBindingWrapper
bool isPropertyInBindingWrapper(const QUntypedPropertyData *property)
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 QT_WARNING_POP
#define QT_WARNING_DISABLE_DEPRECATED
#define QT_WARNING_PUSH
#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:469
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
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
constexpr void qt_ptr_swap(T *&lhs, T *&rhs) noexcept
Definition qswap.h:29
size_t quintptr
Definition qtypes.h:167
const char property[13]
Definition qwizard.cpp:101
settings setValue("DataPump/bgcolor", color)
QStorageInfo storage
[1]
QObject::connect nullptr
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:52
QBindingObserverPtr()=default
void swap(QBindingObserverPtr &other) noexcept
Definition qproperty_p.h:50
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:92
QPropertyBindingPrivate * binding() const
Definition qproperty_p.h:72
void setObservers(QPropertyObserver *observer)
Definition qproperty_p.h:77
QPropertyObserverPointer firstObserver() const
void setFirstObserver(QPropertyObserver *observer)
QPropertyObserver * next() const
void notify(QUntypedPropertyData *propertyDataPtr)
QPropertyBindingPrivate * binding() const
QPropertyObserver * ptr
QPropertyObserverPointer nextObserver() const
void setBindingToNotify(QPropertyBindingPrivate *binding)
static QtPrivate::QBindableInterface const * getInterface(const QUntypedBindable &bindable)
static QUntypedPropertyData * getPropertyData(const QUntypedBindable &bindable)
QPropertyBindingPrivate * binding
QVarLengthArray< const QPropertyBindingData *, 8 > alreadyCaptureProperties
QUntypedPropertyData * property
CurrentCompatPropertyThief(QBindingStatus *status)
const QtPrivate::BindingFunctionVTable * vtable