1/****************************************************************************
2**
3** Copyright (C) 2019 The Qt Company Ltd.
4** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#ifndef QOBJECT_P_H
42#define QOBJECT_P_H
43
44//
45// W A R N I N G
46// -------------
47//
48// This file is not part of the Qt API. It exists for the convenience
49// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
50// file may change from version to version without notice, or even be removed.
51//
52// We mean it.
53//
54
55#include <QtCore/private/qglobal_p.h>
56#include "QtCore/qcoreevent.h"
57#include "QtCore/qlist.h"
58#include "QtCore/qobject.h"
59#include "QtCore/qpointer.h"
60#include "QtCore/qreadwritelock.h"
61#include "QtCore/qsharedpointer.h"
62#include "QtCore/qvariant.h"
63#include "QtCore/qproperty.h"
64
65QT_BEGIN_NAMESPACE
66
67class QVariant;
68class QThreadData;
69class QObjectConnectionListVector;
70namespace QtSharedPointer { struct ExternalRefCountData; }
71
72/* for Qt Test */
73struct QSignalSpyCallbackSet
74{
75 typedef void (*BeginCallback)(QObject *caller, int signal_or_method_index, void **argv);
76 typedef void (*EndCallback)(QObject *caller, int signal_or_method_index);
77 BeginCallback signal_begin_callback,
78 slot_begin_callback;
79 EndCallback signal_end_callback,
80 slot_end_callback;
81};
82void Q_CORE_EXPORT qt_register_signal_spy_callbacks(QSignalSpyCallbackSet *callback_set);
83
84extern Q_CORE_EXPORT QBasicAtomicPointer<QSignalSpyCallbackSet> qt_signal_spy_callback_set;
85
86enum { QObjectPrivateVersion = QT_VERSION };
87
88class Q_CORE_EXPORT QAbstractDeclarativeData
89{
90public:
91 static void (*destroyed)(QAbstractDeclarativeData *, QObject *);
92 static void (*parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *);
93 static void (*signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **);
94 static int (*receivers)(QAbstractDeclarativeData *, const QObject *, int);
95 static bool (*isSignalConnected)(QAbstractDeclarativeData *, const QObject *, int);
96 static void (*setWidgetParent)(QObject *, QObject *); // Used by the QML engine to specify parents for widgets. Set by QtWidgets.
97};
98
99class Q_CORE_EXPORT QObjectPrivate : public QObjectData
100{
101 Q_DECLARE_PUBLIC(QObject)
102
103public:
104 struct ExtraData
105 {
106 ExtraData() {}
107 QList<QByteArray> propertyNames;
108 QList<QVariant> propertyValues;
109 QList<int> runningTimers;
110 QList<QPointer<QObject>> eventFilters;
111 QString objectName;
112 };
113
114 typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **);
115 struct Connection;
116 struct SignalVector;
117
118 struct ConnectionOrSignalVector {
119 union {
120 // linked list of orphaned connections that need cleaning up
121 ConnectionOrSignalVector *nextInOrphanList;
122 // linked list of connections connected to slots in this object
123 Connection *next;
124 };
125
126 static SignalVector *asSignalVector(ConnectionOrSignalVector *c)
127 {
128 if (reinterpret_cast<quintptr>(c) & 1)
129 return reinterpret_cast<SignalVector *>(reinterpret_cast<quintptr>(c) & ~quintptr(1u));
130 return nullptr;
131 }
132 static Connection *fromSignalVector(SignalVector *v) {
133 return reinterpret_cast<Connection *>(reinterpret_cast<quintptr>(v) | quintptr(1u));
134 }
135 };
136
137 struct Connection : public ConnectionOrSignalVector
138 {
139 // linked list of connections connected to slots in this object, next is in base class
140 Connection **prev;
141 // linked list of connections connected to signals in this object
142 QAtomicPointer<Connection> nextConnectionList;
143 Connection *prevConnectionList;
144
145 QObject *sender;
146 QAtomicPointer<QObject> receiver;
147 QAtomicPointer<QThreadData> receiverThreadData;
148 union {
149 StaticMetaCallFunction callFunction;
150 QtPrivate::QSlotObjectBase *slotObj;
151 };
152 QAtomicPointer<const int> argumentTypes;
153 QAtomicInt ref_;
154 uint id = 0;
155 ushort method_offset;
156 ushort method_relative;
157 signed int signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
158 ushort connectionType : 2; // 0 == auto, 1 == direct, 2 == queued, 3 == blocking
159 ushort isSlotObject : 1;
160 ushort ownArgumentTypes : 1;
161 ushort isSingleShot : 1;
162 Connection() : ref_(2), ownArgumentTypes(true) {
163 //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection
164 }
165 ~Connection();
166 int method() const { Q_ASSERT(!isSlotObject); return method_offset + method_relative; }
167 void ref() { ref_.ref(); }
168 void freeSlotObject()
169 {
170 if (isSlotObject) {
171 slotObj->destroyIfLastRef();
172 isSlotObject = false;
173 }
174 }
175 void deref()
176 {
177 if (!ref_.deref()) {
178 Q_ASSERT(!receiver.loadRelaxed());
179 Q_ASSERT(!isSlotObject);
180 delete this;
181 }
182 }
183 };
184 // ConnectionList is a singly-linked list
185 struct ConnectionList {
186 QAtomicPointer<Connection> first;
187 QAtomicPointer<Connection> last;
188 };
189
190 struct Sender
191 {
192 Sender(QObject *receiver, QObject *sender, int signal)
193 : receiver(receiver), sender(sender), signal(signal)
194 {
195 if (receiver) {
196 ConnectionData *cd = receiver->d_func()->connections.loadRelaxed();
197 previous = cd->currentSender;
198 cd->currentSender = this;
199 }
200 }
201 ~Sender()
202 {
203 if (receiver)
204 receiver->d_func()->connections.loadRelaxed()->currentSender = previous;
205 }
206 void receiverDeleted()
207 {
208 Sender *s = this;
209 while (s) {
210 s->receiver = nullptr;
211 s = s->previous;
212 }
213 }
214 Sender *previous;
215 QObject *receiver;
216 QObject *sender;
217 int signal;
218 };
219
220 struct SignalVector : public ConnectionOrSignalVector {
221 quintptr allocated;
222 // ConnectionList signals[]
223 ConnectionList &at(int i)
224 {
225 return reinterpret_cast<ConnectionList *>(this + 1)[i + 1];
226 }
227 const ConnectionList &at(int i) const
228 {
229 return reinterpret_cast<const ConnectionList *>(this + 1)[i + 1];
230 }
231 int count() const { return static_cast<int>(allocated); }
232 };
233
234 /*
235 This contains the all connections from and to an object.
236
237 The signalVector contains the lists of connections for a given signal. The index in the vector correspond
238 to the signal index. The signal index is the one returned by QObjectPrivate::signalIndex (not
239 QMetaObject::indexOfSignal). allsignals contains a list of special connections that will get invoked on
240 any signal emission. This is done by connecting to signal index -1.
241
242 This vector is protected by the object mutex (signalSlotLock())
243
244 Each Connection is also part of a 'senders' linked list. This one contains all connections connected
245 to a slot in this object. The mutex of the receiver must be locked when touching the pointers of this
246 linked list.
247 */
248 struct ConnectionData {
249 // the id below is used to avoid activating new connections. When the object gets
250 // deleted it's set to 0, so that signal emission stops
251 QAtomicInteger<uint> currentConnectionId;
252 QAtomicInt ref;
253 QAtomicPointer<SignalVector> signalVector;
254 Connection *senders = nullptr;
255 Sender *currentSender = nullptr; // object currently activating the object
256 QAtomicPointer<Connection> orphaned;
257
258 ~ConnectionData()
259 {
260 deleteOrphaned(orphaned.loadRelaxed());
261 SignalVector *v = signalVector.loadRelaxed();
262 if (v)
263 free(v);
264 }
265
266 // must be called on the senders connection data
267 // assumes the senders and receivers lock are held
268 void removeConnection(Connection *c);
269 void cleanOrphanedConnections(QObject *sender)
270 {
271 if (orphaned.loadRelaxed() && ref.loadAcquire() == 1)
272 cleanOrphanedConnectionsImpl(sender);
273 }
274 void cleanOrphanedConnectionsImpl(QObject *sender);
275
276 ConnectionList &connectionsForSignal(int signal)
277 {
278 return signalVector.loadRelaxed()->at(signal);
279 }
280
281 void resizeSignalVector(uint size)
282 {
283 SignalVector *vector = this->signalVector.loadRelaxed();
284 if (vector && vector->allocated > size)
285 return;
286 size = (size + 7) & ~7;
287 SignalVector *newVector = reinterpret_cast<SignalVector *>(malloc(sizeof(SignalVector) + (size + 1) * sizeof(ConnectionList)));
288 int start = -1;
289 if (vector) {
290 memcpy(newVector, vector, sizeof(SignalVector) + (vector->allocated + 1) * sizeof(ConnectionList));
291 start = vector->count();
292 }
293 for (int i = start; i < int(size); ++i)
294 newVector->at(i) = ConnectionList();
295 newVector->next = nullptr;
296 newVector->allocated = size;
297
298 signalVector.storeRelaxed(newVector);
299 if (vector) {
300 vector->nextInOrphanList = orphaned.loadRelaxed();
301 orphaned.storeRelaxed(ConnectionOrSignalVector::fromSignalVector(vector));
302 }
303 }
304 int signalVectorCount() const
305 {
306 return signalVector.loadAcquire() ? signalVector.loadRelaxed()->count() : -1;
307 }
308
309 static void deleteOrphaned(ConnectionOrSignalVector *c);
310 };
311
312 QObjectPrivate(int version = QObjectPrivateVersion);
313 virtual ~QObjectPrivate();
314 void deleteChildren();
315
316 inline void checkForIncompatibleLibraryVersion(int version) const;
317
318 void setParent_helper(QObject *);
319 void moveToThread_helper();
320 void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
321 void _q_reregisterTimers(void *pointer);
322
323 bool isSender(const QObject *receiver, const char *signal) const;
324 QObjectList receiverList(const char *signal) const;
325 QObjectList senderList() const;
326
327 void addConnection(int signal, Connection *c);
328
329 static QObjectPrivate *get(QObject *o) { return o->d_func(); }
330 static const QObjectPrivate *get(const QObject *o) { return o->d_func(); }
331
332 int signalIndex(const char *signalName, const QMetaObject **meta = nullptr) const;
333 bool isSignalConnected(uint signalIdx, bool checkDeclarative = true) const;
334 bool maybeSignalConnected(uint signalIndex) const;
335 inline bool isDeclarativeSignalConnected(uint signalIdx) const;
336
337 // To allow abitrary objects to call connectNotify()/disconnectNotify() without making
338 // the API public in QObject. This is used by QQmlNotifierEndpoint.
339 inline void connectNotify(const QMetaMethod &signal);
340 inline void disconnectNotify(const QMetaMethod &signal);
341
342 template <typename Func1, typename Func2>
343 static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
344 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
345 Qt::ConnectionType type = Qt::AutoConnection);
346
347 template <typename Func1, typename Func2>
348 static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
349 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot);
350
351 static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index,
352 const QObject *receiver, void **slot,
353 QtPrivate::QSlotObjectBase *slotObj, int type,
354 const int *types, const QMetaObject *senderMetaObject);
355 static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type);
356 static bool disconnect(const QObject *sender, int signal_index, void **slot);
357 static bool disconnect(Connection *c);
358
359 void ensureConnectionData()
360 {
361 if (connections.loadRelaxed())
362 return;
363 ConnectionData *cd = new ConnectionData;
364 cd->ref.ref();
365 connections.storeRelaxed(cd);
366 }
367public:
368 ExtraData *extraData; // extra data set by the user
369 // This atomic requires acquire/release semantics in a few places,
370 // e.g. QObject::moveToThread must synchronize with QCoreApplication::postEvent,
371 // because postEvent is thread-safe.
372 // However, most of the code paths involving QObject are only reentrant and
373 // not thread-safe, so synchronization should not be necessary there.
374 QAtomicPointer<QThreadData> threadData; // id of the thread that owns the object
375
376 using ConnectionDataPointer = QExplicitlySharedDataPointer<ConnectionData>;
377 QAtomicPointer<ConnectionData> connections;
378
379 union {
380 QObject *currentChildBeingDeleted; // should only be used when QObjectData::isDeletingChildren is set
381 QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module
382 };
383
384 // these objects are all used to indicate that a QObject was deleted
385 // plus QPointer, which keeps a separate list
386 QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount;
387 QBindingStorage bindingStorage;
388};
389
390Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_MOVABLE_TYPE);
391
392/*
393 Catch mixing of incompatible library versions.
394
395 Should be called from the constructor of every non-final subclass
396 of QObjectPrivate, to ensure we catch incompatibilities between
397 the intermediate base and subclasses thereof.
398*/
399inline void QObjectPrivate::checkForIncompatibleLibraryVersion(int version) const
400{
401#if defined(QT_BUILD_INTERNAL)
402 // Don't check the version parameter in internal builds.
403 // This allows incompatible versions to be loaded, possibly for testing.
404 Q_UNUSED(version);
405#else
406 if (Q_UNLIKELY(version != QObjectPrivateVersion)) {
407 qFatal("Cannot mix incompatible Qt library (%d.%d.%d) with this library (%d.%d.%d)",
408 (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff,
409 (QObjectPrivateVersion >> 16) & 0xff, (QObjectPrivateVersion >> 8) & 0xff, QObjectPrivateVersion & 0xff);
410 }
411#endif
412}
413
414inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const
415{
416 return declarativeData && QAbstractDeclarativeData::isSignalConnected
417 && QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index);
418}
419
420inline void QObjectPrivate::connectNotify(const QMetaMethod &signal)
421{
422 q_ptr->connectNotify(signal);
423}
424
425inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal)
426{
427 q_ptr->disconnectNotify(signal);
428}
429
430namespace QtPrivate {
431template<typename Func, typename Args, typename R> class QPrivateSlotObject : public QSlotObjectBase
432{
433 typedef QtPrivate::FunctionPointer<Func> FuncType;
434 Func function;
435 static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
436 {
437 switch (which) {
438 case Destroy:
439 delete static_cast<QPrivateSlotObject*>(this_);
440 break;
441 case Call:
442 FuncType::template call<Args, R>(static_cast<QPrivateSlotObject*>(this_)->function,
443 static_cast<typename FuncType::Object *>(QObjectPrivate::get(r)), a);
444 break;
445 case Compare:
446 *ret = *reinterpret_cast<Func *>(a) == static_cast<QPrivateSlotObject*>(this_)->function;
447 break;
448 case NumOperations: ;
449 }
450 }
451public:
452 explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
453};
454} //namespace QtPrivate
455
456template <typename Func1, typename Func2>
457inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
458 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
459 Qt::ConnectionType type)
460{
461 typedef QtPrivate::FunctionPointer<Func1> SignalType;
462 typedef QtPrivate::FunctionPointer<Func2> SlotType;
463 static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
464 "No Q_OBJECT in the class with the signal");
465
466 //compilation error if the arguments does not match.
467 static_assert(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
468 "The slot requires more arguments than the signal provides.");
469 static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
470 "Signal and slot arguments are not compatible.");
471 static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
472 "Return type of the slot is not compatible with the return type of the signal.");
473
474 const int *types = nullptr;
475 if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
476 types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
477
478 return QObject::connectImpl(sender, reinterpret_cast<void **>(&signal),
479 receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot),
480 new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
481 typename SignalType::ReturnType>(slot),
482 type, types, &SignalType::Object::staticMetaObject);
483}
484
485template <typename Func1, typename Func2>
486bool QObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object* sender, Func1 signal,
487 const typename QtPrivate::FunctionPointer< Func2 >::Object* receiverPrivate, Func2 slot)
488{
489 typedef QtPrivate::FunctionPointer<Func1> SignalType;
490 typedef QtPrivate::FunctionPointer<Func2> SlotType;
491 static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
492 "No Q_OBJECT in the class with the signal");
493 //compilation error if the arguments does not match.
494 static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
495 "Signal and slot arguments are not compatible.");
496 return QObject::disconnectImpl(sender, reinterpret_cast<void **>(&signal),
497 receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot),
498 &SignalType::Object::staticMetaObject);
499}
500
501Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE);
502Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE);
503
504class QSemaphore;
505class Q_CORE_EXPORT QAbstractMetaCallEvent : public QEvent
506{
507public:
508 QAbstractMetaCallEvent(const QObject *sender, int signalId, QSemaphore *semaphore = nullptr)
509 : QEvent(MetaCall), signalId_(signalId), sender_(sender)
510#if QT_CONFIG(thread)
511 , semaphore_(semaphore)
512#endif
513 { Q_UNUSED(semaphore); }
514 ~QAbstractMetaCallEvent();
515
516 virtual void placeMetaCall(QObject *object) = 0;
517
518 inline const QObject *sender() const { return sender_; }
519 inline int signalId() const { return signalId_; }
520
521private:
522 int signalId_;
523 const QObject *sender_;
524#if QT_CONFIG(thread)
525 QSemaphore *semaphore_;
526#endif
527};
528
529class Q_CORE_EXPORT QMetaCallEvent : public QAbstractMetaCallEvent
530{
531public:
532 // blocking queued with semaphore - args always owned by caller
533 QMetaCallEvent(ushort method_offset, ushort method_relative,
534 QObjectPrivate::StaticMetaCallFunction callFunction,
535 const QObject *sender, int signalId,
536 void **args, QSemaphore *semaphore);
537 QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
538 const QObject *sender, int signalId,
539 void **args, QSemaphore *semaphore);
540
541 // queued - args allocated by event, copied by caller
542 QMetaCallEvent(ushort method_offset, ushort method_relative,
543 QObjectPrivate::StaticMetaCallFunction callFunction,
544 const QObject *sender, int signalId,
545 int nargs);
546 QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
547 const QObject *sender, int signalId,
548 int nargs);
549
550 ~QMetaCallEvent() override;
551
552 inline int id() const { return d.method_offset_ + d.method_relative_; }
553 inline const void * const* args() const { return d.args_; }
554 inline void ** args() { return d.args_; }
555 inline const QMetaType *types() const { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); }
556 inline QMetaType *types() { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); }
557
558 virtual void placeMetaCall(QObject *object) override;
559
560private:
561 inline void allocArgs();
562
563 struct Data {
564 QtPrivate::QSlotObjectBase *slotObj_;
565 void **args_;
566 QObjectPrivate::StaticMetaCallFunction callFunction_;
567 int nargs_;
568 ushort method_offset_;
569 ushort method_relative_;
570 } d;
571 // preallocate enough space for three arguments
572 alignas(void *) char prealloc_[3 * sizeof(void *) + 3 * sizeof(QMetaType)];
573};
574
575class QBoolBlocker
576{
577 Q_DISABLE_COPY_MOVE(QBoolBlocker)
578public:
579 explicit inline QBoolBlocker(bool &b, bool value = true) : block(b), reset(b) { block = value; }
580 inline ~QBoolBlocker() { block = reset; }
581
582private:
583 bool &block;
584 bool reset;
585};
586
587void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o);
588
589struct QAbstractDynamicMetaObject;
590struct Q_CORE_EXPORT QDynamicMetaObjectData
591{
592 virtual ~QDynamicMetaObjectData();
593 virtual void objectDestroyed(QObject *) { delete this; }
594
595 virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) = 0;
596 virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **) = 0;
597};
598
599struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject
600{
601 ~QAbstractDynamicMetaObject();
602
603 QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) override { return this; }
604 virtual int createProperty(const char *, const char *) { return -1; }
605 int metaCall(QObject *, QMetaObject::Call c, int _id, void **a) override
606 { return metaCall(c, _id, a); }
607 virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; } // Compat overload
608};
609
610inline const QBindingStorage *qGetBindingStorage(const QObjectPrivate *o)
611{
612 return &o->bindingStorage;
613}
614inline QBindingStorage *qGetBindingStorage(QObjectPrivate *o)
615{
616 return &o->bindingStorage;
617}
618
619
620QT_END_NAMESPACE
621
622#endif // QOBJECT_P_H
623