1 | // Copyright (C) 2019 The Qt Company Ltd. |
2 | // Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com> |
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
4 | |
5 | #ifndef QOBJECT_P_H |
6 | #define QOBJECT_P_H |
7 | |
8 | // |
9 | // W A R N I N G |
10 | // ------------- |
11 | // |
12 | // This file is not part of the Qt API. It exists for the convenience |
13 | // of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header |
14 | // file may change from version to version without notice, or even be removed. |
15 | // |
16 | // We mean it. |
17 | // |
18 | |
19 | #include <QtCore/private/qglobal_p.h> |
20 | #include "QtCore/qcoreevent.h" |
21 | #include <QtCore/qfunctionaltools_impl.h> |
22 | #include "QtCore/qlist.h" |
23 | #include "QtCore/qobject.h" |
24 | #include "QtCore/qpointer.h" |
25 | #include "QtCore/qvariant.h" |
26 | #include "QtCore/qproperty.h" |
27 | #include <QtCore/qshareddata.h> |
28 | #include "QtCore/private/qproperty_p.h" |
29 | |
30 | #include <string> |
31 | |
32 | QT_BEGIN_NAMESPACE |
33 | |
34 | #ifdef Q_MOC_RUN |
35 | #define QT_ANONYMOUS_PROPERTY(text) QT_ANONYMOUS_PROPERTY(text) |
36 | #define QT_ANONYMOUS_PRIVATE_PROPERTY(d, text) QT_ANONYMOUS_PRIVATE_PROPERTY(d, text) |
37 | #elif !defined QT_NO_META_MACROS |
38 | #define QT_ANONYMOUS_PROPERTY(...) QT_ANNOTATE_CLASS(qt_anonymous_property, __VA_ARGS__) |
39 | #define QT_ANONYMOUS_PRIVATE_PROPERTY(d, text) QT_ANNOTATE_CLASS2(qt_anonymous_private_property, d, text) |
40 | #endif |
41 | |
42 | class QVariant; |
43 | class QThreadData; |
44 | class QObjectConnectionListVector; |
45 | namespace QtSharedPointer { struct ExternalRefCountData; } |
46 | |
47 | /* for Qt Test */ |
48 | struct QSignalSpyCallbackSet |
49 | { |
50 | typedef void (*BeginCallback)(QObject *caller, int signal_or_method_index, void **argv); |
51 | typedef void (*EndCallback)(QObject *caller, int signal_or_method_index); |
52 | BeginCallback signal_begin_callback, |
53 | slot_begin_callback; |
54 | EndCallback signal_end_callback, |
55 | slot_end_callback; |
56 | }; |
57 | void Q_CORE_EXPORT qt_register_signal_spy_callbacks(QSignalSpyCallbackSet *callback_set); |
58 | |
59 | extern Q_CORE_EXPORT QBasicAtomicPointer<QSignalSpyCallbackSet> qt_signal_spy_callback_set; |
60 | |
61 | enum { QObjectPrivateVersion = QT_VERSION }; |
62 | |
63 | class Q_CORE_EXPORT QAbstractDeclarativeData |
64 | { |
65 | public: |
66 | static void (*destroyed)(QAbstractDeclarativeData *, QObject *); |
67 | static void (*signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **); |
68 | static int (*receivers)(QAbstractDeclarativeData *, const QObject *, int); |
69 | static bool (*isSignalConnected)(QAbstractDeclarativeData *, const QObject *, int); |
70 | static void (*setWidgetParent)(QObject *, QObject *); // Used by the QML engine to specify parents for widgets. Set by QtWidgets. |
71 | }; |
72 | |
73 | class Q_CORE_EXPORT QObjectPrivate : public QObjectData |
74 | { |
75 | public: |
76 | Q_DECLARE_PUBLIC(QObject) |
77 | |
78 | struct |
79 | { |
80 | (QObjectPrivate *ptr) : parent(ptr) { } |
81 | |
82 | inline void (const QString &name) |
83 | { |
84 | parent->q_func()->setObjectName(name); |
85 | } |
86 | |
87 | inline void (const QString &name) |
88 | { |
89 | Q_EMIT parent->q_func()->objectNameChanged(objectName: name, QObject::QPrivateSignal()); |
90 | } |
91 | |
92 | QList<QByteArray> ; |
93 | QList<QVariant> ; |
94 | QList<int> ; |
95 | QList<QPointer<QObject>> ; |
96 | Q_OBJECT_COMPAT_PROPERTY(QObjectPrivate::ExtraData, QString, , |
97 | &QObjectPrivate::ExtraData::setObjectNameForwarder, |
98 | &QObjectPrivate::ExtraData::nameChangedForwarder) |
99 | QObjectPrivate *; |
100 | }; |
101 | |
102 | void () |
103 | { |
104 | if (!extraData) |
105 | extraData = new ExtraData(this); |
106 | } |
107 | |
108 | typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **); |
109 | struct Connection; |
110 | struct ConnectionData; |
111 | struct ConnectionList; |
112 | struct ConnectionOrSignalVector; |
113 | struct SignalVector; |
114 | struct Sender; |
115 | struct TaggedSignalVector; |
116 | |
117 | /* |
118 | This contains the all connections from and to an object. |
119 | |
120 | The signalVector contains the lists of connections for a given signal. The index in the vector correspond |
121 | to the signal index. The signal index is the one returned by QObjectPrivate::signalIndex (not |
122 | QMetaObject::indexOfSignal). allsignals contains a list of special connections that will get invoked on |
123 | any signal emission. This is done by connecting to signal index -1. |
124 | |
125 | This vector is protected by the object mutex (signalSlotLock()) |
126 | |
127 | Each Connection is also part of a 'senders' linked list. This one contains all connections connected |
128 | to a slot in this object. The mutex of the receiver must be locked when touching the pointers of this |
129 | linked list. |
130 | */ |
131 | |
132 | QObjectPrivate(int version = QObjectPrivateVersion); |
133 | virtual ~QObjectPrivate(); |
134 | void deleteChildren(); |
135 | // used to clear binding storage early in ~QObject |
136 | void clearBindingStorage(); |
137 | |
138 | inline void checkForIncompatibleLibraryVersion(int version) const; |
139 | |
140 | void setParent_helper(QObject *); |
141 | void moveToThread_helper(); |
142 | void setThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status); |
143 | void _q_reregisterTimers(void *pointer); |
144 | |
145 | bool isSender(const QObject *receiver, const char *signal) const; |
146 | QObjectList receiverList(const char *signal) const; |
147 | QObjectList senderList() const; |
148 | |
149 | inline void ensureConnectionData(); |
150 | inline void addConnection(int signal, Connection *c); |
151 | static inline bool removeConnection(Connection *c); |
152 | |
153 | static QObjectPrivate *get(QObject *o) { return o->d_func(); } |
154 | static const QObjectPrivate *get(const QObject *o) { return o->d_func(); } |
155 | |
156 | int signalIndex(const char *signalName, const QMetaObject **meta = nullptr) const; |
157 | bool isSignalConnected(uint signalIdx, bool checkDeclarative = true) const; |
158 | bool maybeSignalConnected(uint signalIndex) const; |
159 | inline bool isDeclarativeSignalConnected(uint signalIdx) const; |
160 | |
161 | // To allow abitrary objects to call connectNotify()/disconnectNotify() without making |
162 | // the API public in QObject. This is used by QQmlNotifierEndpoint. |
163 | inline void connectNotify(const QMetaMethod &signal); |
164 | inline void disconnectNotify(const QMetaMethod &signal); |
165 | |
166 | void reinitBindingStorageAfterThreadMove(); |
167 | |
168 | template <typename Func1, typename Func2> |
169 | static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, |
170 | const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot, |
171 | Qt::ConnectionType type = Qt::AutoConnection); |
172 | |
173 | template <typename Func1, typename Func2> |
174 | static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, |
175 | const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot); |
176 | |
177 | static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index, |
178 | const QObject *receiver, void **slot, |
179 | QtPrivate::QSlotObjectBase *slotObj, int type, |
180 | const int *types, const QMetaObject *senderMetaObject); |
181 | static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type); |
182 | static QMetaObject::Connection connect(const QObject *sender, int signal_index, |
183 | const QObject *receiver, |
184 | QtPrivate::QSlotObjectBase *slotObj, |
185 | Qt::ConnectionType type); |
186 | static bool disconnect(const QObject *sender, int signal_index, void **slot); |
187 | static bool disconnect(const QObject *sender, int signal_index, const QObject *receiver, |
188 | void **slot); |
189 | |
190 | virtual std::string flagsForDumping() const; |
191 | |
192 | QtPrivate::QPropertyAdaptorSlotObject * |
193 | getPropertyAdaptorSlotObject(const QMetaProperty &property); |
194 | |
195 | public: |
196 | mutable ExtraData *; // extra data set by the user |
197 | // This atomic requires acquire/release semantics in a few places, |
198 | // e.g. QObject::moveToThread must synchronize with QCoreApplication::postEvent, |
199 | // because postEvent is thread-safe. |
200 | // However, most of the code paths involving QObject are only reentrant and |
201 | // not thread-safe, so synchronization should not be necessary there. |
202 | QAtomicPointer<QThreadData> threadData; // id of the thread that owns the object |
203 | |
204 | using ConnectionDataPointer = QExplicitlySharedDataPointer<ConnectionData>; |
205 | QAtomicPointer<ConnectionData> connections; |
206 | |
207 | union { |
208 | QObject *currentChildBeingDeleted; // should only be used when QObjectData::isDeletingChildren is set |
209 | QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module |
210 | }; |
211 | |
212 | // these objects are all used to indicate that a QObject was deleted |
213 | // plus QPointer, which keeps a separate list |
214 | QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount; |
215 | }; |
216 | |
217 | /* |
218 | Catch mixing of incompatible library versions. |
219 | |
220 | Should be called from the constructor of every non-final subclass |
221 | of QObjectPrivate, to ensure we catch incompatibilities between |
222 | the intermediate base and subclasses thereof. |
223 | */ |
224 | inline void QObjectPrivate::checkForIncompatibleLibraryVersion(int version) const |
225 | { |
226 | #if defined(QT_BUILD_INTERNAL) |
227 | // Don't check the version parameter in internal builds. |
228 | // This allows incompatible versions to be loaded, possibly for testing. |
229 | Q_UNUSED(version); |
230 | #else |
231 | if (Q_UNLIKELY(version != QObjectPrivateVersion)) { |
232 | qFatal("Cannot mix incompatible Qt library (%d.%d.%d) with this library (%d.%d.%d)" , |
233 | (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff, |
234 | (QObjectPrivateVersion >> 16) & 0xff, (QObjectPrivateVersion >> 8) & 0xff, QObjectPrivateVersion & 0xff); |
235 | } |
236 | #endif |
237 | } |
238 | |
239 | inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const |
240 | { |
241 | return !isDeletingChildren && declarativeData && QAbstractDeclarativeData::isSignalConnected |
242 | && QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index); |
243 | } |
244 | |
245 | inline void QObjectPrivate::connectNotify(const QMetaMethod &signal) |
246 | { |
247 | q_ptr->connectNotify(signal); |
248 | } |
249 | |
250 | inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal) |
251 | { |
252 | q_ptr->disconnectNotify(signal); |
253 | } |
254 | |
255 | namespace QtPrivate { |
256 | inline const QObject *getQObject(const QObjectPrivate *d) { return d->q_func(); } |
257 | |
258 | template <typename Func> |
259 | using FunctionStorage = QtPrivate::CompactStorage<Func>; |
260 | |
261 | template <typename ObjPrivate> inline void assertObjectType(QObjectPrivate *d) |
262 | { |
263 | using Obj = std::remove_pointer_t<decltype(std::declval<ObjPrivate *>()->q_func())>; |
264 | assertObjectType<Obj>(d->q_ptr); |
265 | } |
266 | |
267 | template<typename Func, typename Args, typename R> |
268 | class QPrivateSlotObject : public QSlotObjectBase, private FunctionStorage<Func> |
269 | { |
270 | typedef QtPrivate::FunctionPointer<Func> FuncType; |
271 | #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) |
272 | static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret) |
273 | #else |
274 | static void impl(QSlotObjectBase *this_, QObject *r, void **a, int which, bool *ret) |
275 | #endif |
276 | { |
277 | const auto that = static_cast<QPrivateSlotObject*>(this_); |
278 | switch (which) { |
279 | case Destroy: |
280 | delete that; |
281 | break; |
282 | case Call: |
283 | FuncType::template call<Args, R>(that->object(), |
284 | static_cast<typename FuncType::Object *>(QObjectPrivate::get(o: r)), a); |
285 | break; |
286 | case Compare: |
287 | *ret = *reinterpret_cast<Func *>(a) == that->object(); |
288 | break; |
289 | case NumOperations: ; |
290 | } |
291 | } |
292 | public: |
293 | explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), FunctionStorage<Func>{std::move(f)} {} |
294 | }; |
295 | } //namespace QtPrivate |
296 | |
297 | template <typename Func1, typename Func2> |
298 | inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, |
299 | const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot, |
300 | Qt::ConnectionType type) |
301 | { |
302 | typedef QtPrivate::FunctionPointer<Func1> SignalType; |
303 | typedef QtPrivate::FunctionPointer<Func2> SlotType; |
304 | static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value, |
305 | "No Q_OBJECT in the class with the signal" ); |
306 | |
307 | //compilation error if the arguments does not match. |
308 | static_assert(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount), |
309 | "The slot requires more arguments than the signal provides." ); |
310 | static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value), |
311 | "Signal and slot arguments are not compatible." ); |
312 | static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value), |
313 | "Return type of the slot is not compatible with the return type of the signal." ); |
314 | |
315 | const int *types = nullptr; |
316 | if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection) |
317 | types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types(); |
318 | |
319 | return QObject::connectImpl(sender, signal: reinterpret_cast<void **>(&signal), |
320 | receiver: QtPrivate::getQObject(d: receiverPrivate), slotPtr: reinterpret_cast<void **>(&slot), |
321 | slot: new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value, |
322 | typename SignalType::ReturnType>(slot), |
323 | type, types, senderMetaObject: &SignalType::Object::staticMetaObject); |
324 | } |
325 | |
326 | template <typename Func1, typename Func2> |
327 | bool QObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object* sender, Func1 signal, |
328 | const typename QtPrivate::FunctionPointer< Func2 >::Object* receiverPrivate, Func2 slot) |
329 | { |
330 | typedef QtPrivate::FunctionPointer<Func1> SignalType; |
331 | typedef QtPrivate::FunctionPointer<Func2> SlotType; |
332 | static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value, |
333 | "No Q_OBJECT in the class with the signal" ); |
334 | //compilation error if the arguments does not match. |
335 | static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value), |
336 | "Signal and slot arguments are not compatible." ); |
337 | return QObject::disconnectImpl(sender, signal: reinterpret_cast<void **>(&signal), |
338 | receiver: receiverPrivate->q_ptr, slot: reinterpret_cast<void **>(&slot), |
339 | senderMetaObject: &SignalType::Object::staticMetaObject); |
340 | } |
341 | |
342 | class QSemaphore; |
343 | class Q_CORE_EXPORT QAbstractMetaCallEvent : public QEvent |
344 | { |
345 | public: |
346 | QAbstractMetaCallEvent(const QObject *sender, int signalId, QSemaphore *semaphore = nullptr) |
347 | : QEvent(MetaCall), signalId_(signalId), sender_(sender) |
348 | #if QT_CONFIG(thread) |
349 | , semaphore_(semaphore) |
350 | #endif |
351 | { Q_UNUSED(semaphore); } |
352 | ~QAbstractMetaCallEvent(); |
353 | |
354 | virtual void placeMetaCall(QObject *object) = 0; |
355 | |
356 | inline const QObject *sender() const { return sender_; } |
357 | inline int signalId() const { return signalId_; } |
358 | |
359 | private: |
360 | int signalId_; |
361 | const QObject *sender_; |
362 | #if QT_CONFIG(thread) |
363 | QSemaphore *semaphore_; |
364 | #endif |
365 | }; |
366 | |
367 | class Q_CORE_EXPORT QMetaCallEvent : public QAbstractMetaCallEvent |
368 | { |
369 | public: |
370 | // blocking queued with semaphore - args always owned by caller |
371 | QMetaCallEvent(ushort method_offset, ushort method_relative, |
372 | QObjectPrivate::StaticMetaCallFunction callFunction, |
373 | const QObject *sender, int signalId, |
374 | void **args, QSemaphore *semaphore); |
375 | QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, |
376 | const QObject *sender, int signalId, |
377 | void **args, QSemaphore *semaphore); |
378 | QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj, |
379 | const QObject *sender, int signalId, |
380 | void **args, QSemaphore *semaphore); |
381 | |
382 | // queued - args allocated by event, copied by caller |
383 | QMetaCallEvent(ushort method_offset, ushort method_relative, |
384 | QObjectPrivate::StaticMetaCallFunction callFunction, |
385 | const QObject *sender, int signalId, |
386 | int nargs); |
387 | QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, |
388 | const QObject *sender, int signalId, |
389 | int nargs); |
390 | QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj, |
391 | const QObject *sender, int signalId, |
392 | int nargs); |
393 | |
394 | ~QMetaCallEvent() override; |
395 | |
396 | template<typename ...Args> |
397 | static QMetaCallEvent *create(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender, |
398 | int signal_index, const Args &...argv) |
399 | { |
400 | const void* const argp[] = { nullptr, std::addressof(argv)... }; |
401 | const QMetaType metaTypes[] = { QMetaType::fromType<void>(), QMetaType::fromType<Args>()... }; |
402 | constexpr auto argc = sizeof...(Args) + 1; |
403 | return create_impl(slotObj, sender, signal_index, argc, argp, metaTypes); |
404 | } |
405 | template<typename ...Args> |
406 | static QMetaCallEvent *create(QtPrivate::SlotObjUniquePtr slotObj, const QObject *sender, |
407 | int signal_index, const Args &...argv) |
408 | { |
409 | const void* const argp[] = { nullptr, std::addressof(argv)... }; |
410 | const QMetaType metaTypes[] = { QMetaType::fromType<void>(), QMetaType::fromType<Args>()... }; |
411 | constexpr auto argc = sizeof...(Args) + 1; |
412 | return create_impl(std::move(slotObj), sender, signal_index, argc, argp, metaTypes); |
413 | } |
414 | |
415 | inline int id() const { return d.method_offset_ + d.method_relative_; } |
416 | inline const void * const* args() const { return d.args_; } |
417 | inline void ** args() { return d.args_; } |
418 | inline const QMetaType *types() const { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); } |
419 | inline QMetaType *types() { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); } |
420 | |
421 | virtual void placeMetaCall(QObject *object) override; |
422 | |
423 | private: |
424 | static QMetaCallEvent *create_impl(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender, |
425 | int signal_index, size_t argc, const void * const argp[], |
426 | const QMetaType metaTypes[]) |
427 | { |
428 | if (slotObj) |
429 | slotObj->ref(); |
430 | return create_impl(slotObj: QtPrivate::SlotObjUniquePtr{slotObj}, sender, |
431 | signal_index, argc, argp, metaTypes); |
432 | } |
433 | static QMetaCallEvent *create_impl(QtPrivate::SlotObjUniquePtr slotObj, const QObject *sender, |
434 | int signal_index, size_t argc, const void * const argp[], |
435 | const QMetaType metaTypes[]); |
436 | inline void allocArgs(); |
437 | |
438 | struct Data { |
439 | QtPrivate::SlotObjUniquePtr slotObj_; |
440 | void **args_; |
441 | QObjectPrivate::StaticMetaCallFunction callFunction_; |
442 | int nargs_; |
443 | ushort method_offset_; |
444 | ushort method_relative_; |
445 | } d; |
446 | // preallocate enough space for three arguments |
447 | alignas(void *) char prealloc_[3 * sizeof(void *) + 3 * sizeof(QMetaType)]; |
448 | }; |
449 | |
450 | class QBoolBlocker |
451 | { |
452 | Q_DISABLE_COPY_MOVE(QBoolBlocker) |
453 | public: |
454 | Q_NODISCARD_CTOR explicit QBoolBlocker(bool &b, bool value = true) |
455 | : block(b), reset(b) |
456 | { block = value; } |
457 | inline ~QBoolBlocker() { block = reset; } |
458 | |
459 | private: |
460 | bool █ |
461 | bool reset; |
462 | }; |
463 | |
464 | void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o); |
465 | |
466 | struct QAbstractDynamicMetaObject; |
467 | struct Q_CORE_EXPORT QDynamicMetaObjectData |
468 | { |
469 | virtual ~QDynamicMetaObjectData(); |
470 | virtual void objectDestroyed(QObject *) { delete this; } |
471 | |
472 | virtual QMetaObject *toDynamicMetaObject(QObject *) = 0; |
473 | virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **) = 0; |
474 | }; |
475 | |
476 | struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject |
477 | { |
478 | ~QAbstractDynamicMetaObject(); |
479 | |
480 | QMetaObject *toDynamicMetaObject(QObject *) override { return this; } |
481 | virtual int createProperty(const char *, const char *) { return -1; } |
482 | int metaCall(QObject *, QMetaObject::Call c, int _id, void **a) override |
483 | { return metaCall(c, _id, a); } |
484 | virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; } // Compat overload |
485 | }; |
486 | |
487 | inline const QBindingStorage *qGetBindingStorage(const QObjectPrivate *o) |
488 | { |
489 | return &o->bindingStorage; |
490 | } |
491 | inline QBindingStorage *qGetBindingStorage(QObjectPrivate *o) |
492 | { |
493 | return &o->bindingStorage; |
494 | } |
495 | inline const QBindingStorage *(const QObjectPrivate::ExtraData *ed) |
496 | { |
497 | return &ed->parent->bindingStorage; |
498 | } |
499 | inline QBindingStorage *(QObjectPrivate::ExtraData *ed) |
500 | { |
501 | return &ed->parent->bindingStorage; |
502 | } |
503 | |
504 | QT_END_NAMESPACE |
505 | |
506 | #endif // QOBJECT_P_H |
507 | |