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#include "QtCore/private/qproperty_p.h"
65
66QT_BEGIN_NAMESPACE
67
68class QVariant;
69class QThreadData;
70class QObjectConnectionListVector;
71namespace QtSharedPointer { struct ExternalRefCountData; }
72
73/* for Qt Test */
74struct QSignalSpyCallbackSet
75{
76 typedef void (*BeginCallback)(QObject *caller, int signal_or_method_index, void **argv);
77 typedef void (*EndCallback)(QObject *caller, int signal_or_method_index);
78 BeginCallback signal_begin_callback,
79 slot_begin_callback;
80 EndCallback signal_end_callback,
81 slot_end_callback;
82};
83void Q_CORE_EXPORT qt_register_signal_spy_callbacks(QSignalSpyCallbackSet *callback_set);
84
85extern Q_CORE_EXPORT QBasicAtomicPointer<QSignalSpyCallbackSet> qt_signal_spy_callback_set;
86
87enum { QObjectPrivateVersion = QT_VERSION };
88
89class Q_CORE_EXPORT QAbstractDeclarativeData
90{
91public:
92 static void (*destroyed)(QAbstractDeclarativeData *, 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(QObjectPrivate *ptr) : parent(ptr) { }
107
108 inline void setObjectNameForwarder(const QString &name)
109 {
110 parent->q_func()->setObjectName(name);
111 }
112
113 inline void nameChangedForwarder(const QString &name)
114 {
115 Q_EMIT parent->q_func()->objectNameChanged(name, QObject::QPrivateSignal());
116 }
117
118 QList<QByteArray> propertyNames;
119 QList<QVariant> propertyValues;
120 QList<int> runningTimers;
121 QList<QPointer<QObject>> eventFilters;
122 Q_OBJECT_COMPAT_PROPERTY(QObjectPrivate::ExtraData, QString, objectName,
123 &QObjectPrivate::ExtraData::setObjectNameForwarder,
124 &QObjectPrivate::ExtraData::nameChangedForwarder)
125 QObjectPrivate *parent;
126 };
127
128 typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **);
129 struct Connection;
130 struct SignalVector;
131
132 struct ConnectionOrSignalVector {
133 union {
134 // linked list of orphaned connections that need cleaning up
135 ConnectionOrSignalVector *nextInOrphanList;
136 // linked list of connections connected to slots in this object
137 Connection *next;
138 };
139
140 static SignalVector *asSignalVector(ConnectionOrSignalVector *c)
141 {
142 if (reinterpret_cast<quintptr>(c) & 1)
143 return reinterpret_cast<SignalVector *>(reinterpret_cast<quintptr>(c) & ~quintptr(1u));
144 return nullptr;
145 }
146 static Connection *fromSignalVector(SignalVector *v) {
147 return reinterpret_cast<Connection *>(reinterpret_cast<quintptr>(v) | quintptr(1u));
148 }
149 };
150
151 struct Connection : public ConnectionOrSignalVector
152 {
153 // linked list of connections connected to slots in this object, next is in base class
154 Connection **prev;
155 // linked list of connections connected to signals in this object
156 QAtomicPointer<Connection> nextConnectionList;
157 Connection *prevConnectionList;
158
159 QObject *sender;
160 QAtomicPointer<QObject> receiver;
161 QAtomicPointer<QThreadData> receiverThreadData;
162 union {
163 StaticMetaCallFunction callFunction;
164 QtPrivate::QSlotObjectBase *slotObj;
165 };
166 QAtomicPointer<const int> argumentTypes;
167 QAtomicInt ref_;
168 uint id = 0;
169 ushort method_offset;
170 ushort method_relative;
171 signed int signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
172 ushort connectionType : 2; // 0 == auto, 1 == direct, 2 == queued, 3 == blocking
173 ushort isSlotObject : 1;
174 ushort ownArgumentTypes : 1;
175 ushort isSingleShot : 1;
176 Connection() : ref_(2), ownArgumentTypes(true) {
177 //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection
178 }
179 ~Connection();
180 int method() const { Q_ASSERT(!isSlotObject); return method_offset + method_relative; }
181 void ref() { ref_.ref(); }
182 void freeSlotObject()
183 {
184 if (isSlotObject) {
185 slotObj->destroyIfLastRef();
186 isSlotObject = false;
187 }
188 }
189 void deref()
190 {
191 if (!ref_.deref()) {
192 Q_ASSERT(!receiver.loadRelaxed());
193 Q_ASSERT(!isSlotObject);
194 delete this;
195 }
196 }
197 };
198 // ConnectionList is a singly-linked list
199 struct ConnectionList {
200 QAtomicPointer<Connection> first;
201 QAtomicPointer<Connection> last;
202 };
203
204 struct Sender
205 {
206 Sender(QObject *receiver, QObject *sender, int signal)
207 : receiver(receiver), sender(sender), signal(signal)
208 {
209 if (receiver) {
210 ConnectionData *cd = receiver->d_func()->connections.loadRelaxed();
211 previous = cd->currentSender;
212 cd->currentSender = this;
213 }
214 }
215 ~Sender()
216 {
217 if (receiver)
218 receiver->d_func()->connections.loadRelaxed()->currentSender = previous;
219 }
220 void receiverDeleted()
221 {
222 Sender *s = this;
223 while (s) {
224 s->receiver = nullptr;
225 s = s->previous;
226 }
227 }
228 Sender *previous;
229 QObject *receiver;
230 QObject *sender;
231 int signal;
232 };
233
234 struct SignalVector : public ConnectionOrSignalVector {
235 quintptr allocated;
236 // ConnectionList signals[]
237 ConnectionList &at(int i)
238 {
239 return reinterpret_cast<ConnectionList *>(this + 1)[i + 1];
240 }
241 const ConnectionList &at(int i) const
242 {
243 return reinterpret_cast<const ConnectionList *>(this + 1)[i + 1];
244 }
245 int count() const { return static_cast<int>(allocated); }
246 };
247
248 /*
249 This contains the all connections from and to an object.
250
251 The signalVector contains the lists of connections for a given signal. The index in the vector correspond
252 to the signal index. The signal index is the one returned by QObjectPrivate::signalIndex (not
253 QMetaObject::indexOfSignal). allsignals contains a list of special connections that will get invoked on
254 any signal emission. This is done by connecting to signal index -1.
255
256 This vector is protected by the object mutex (signalSlotLock())
257
258 Each Connection is also part of a 'senders' linked list. This one contains all connections connected
259 to a slot in this object. The mutex of the receiver must be locked when touching the pointers of this
260 linked list.
261 */
262 struct ConnectionData {
263 // the id below is used to avoid activating new connections. When the object gets
264 // deleted it's set to 0, so that signal emission stops
265 QAtomicInteger<uint> currentConnectionId;
266 QAtomicInt ref;
267 QAtomicPointer<SignalVector> signalVector;
268 Connection *senders = nullptr;
269 Sender *currentSender = nullptr; // object currently activating the object
270 QAtomicPointer<Connection> orphaned;
271
272 ~ConnectionData()
273 {
274 Q_ASSERT(ref.loadRelaxed() == 0);
275 auto *c = orphaned.fetchAndStoreRelaxed(nullptr);
276 if (c)
277 deleteOrphaned(c);
278 SignalVector *v = signalVector.loadRelaxed();
279 if (v)
280 free(v);
281 }
282
283 // must be called on the senders connection data
284 // assumes the senders and receivers lock are held
285 void removeConnection(Connection *c);
286 enum LockPolicy {
287 NeedToLock,
288 // Beware that we need to temporarily release the lock
289 // and thus calling code must carefully consider whether
290 // invariants still hold.
291 AlreadyLockedAndTemporarilyReleasingLock
292 };
293 void cleanOrphanedConnections(QObject *sender, LockPolicy lockPolicy = NeedToLock)
294 {
295 if (orphaned.loadRelaxed() && ref.loadAcquire() == 1)
296 cleanOrphanedConnectionsImpl(sender, lockPolicy);
297 }
298 void cleanOrphanedConnectionsImpl(QObject *sender, LockPolicy lockPolicy);
299
300 ConnectionList &connectionsForSignal(int signal)
301 {
302 return signalVector.loadRelaxed()->at(signal);
303 }
304
305 void resizeSignalVector(uint size)
306 {
307 SignalVector *vector = this->signalVector.loadRelaxed();
308 if (vector && vector->allocated > size)
309 return;
310 size = (size + 7) & ~7;
311 SignalVector *newVector = reinterpret_cast<SignalVector *>(malloc(sizeof(SignalVector) + (size + 1) * sizeof(ConnectionList)));
312 int start = -1;
313 if (vector) {
314 memcpy(newVector, vector, sizeof(SignalVector) + (vector->allocated + 1) * sizeof(ConnectionList));
315 start = vector->count();
316 }
317 for (int i = start; i < int(size); ++i)
318 newVector->at(i) = ConnectionList();
319 newVector->next = nullptr;
320 newVector->allocated = size;
321
322 signalVector.storeRelaxed(newVector);
323 if (vector) {
324 Connection *o = nullptr;
325 /* No ABA issue here: When adding a node, we only care about the list head, it doesn't
326 * matter if the tail changes.
327 */
328 do {
329 o = orphaned.loadRelaxed();
330 vector->nextInOrphanList = o;
331 } while (!orphaned.testAndSetRelease(o, ConnectionOrSignalVector::fromSignalVector(vector)));
332
333 }
334 }
335 int signalVectorCount() const
336 {
337 return signalVector.loadAcquire() ? signalVector.loadRelaxed()->count() : -1;
338 }
339
340 static void deleteOrphaned(ConnectionOrSignalVector *c);
341 };
342
343 QObjectPrivate(int version = QObjectPrivateVersion);
344 virtual ~QObjectPrivate();
345 void deleteChildren();
346 // used to clear binding storage early in ~QObject
347 void clearBindingStorage();
348
349 inline void checkForIncompatibleLibraryVersion(int version) const;
350
351 void setParent_helper(QObject *);
352 void moveToThread_helper();
353 void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
354 void _q_reregisterTimers(void *pointer);
355
356 bool isSender(const QObject *receiver, const char *signal) const;
357 QObjectList receiverList(const char *signal) const;
358 QObjectList senderList() const;
359
360 void addConnection(int signal, Connection *c);
361
362 static QObjectPrivate *get(QObject *o) { return o->d_func(); }
363 static const QObjectPrivate *get(const QObject *o) { return o->d_func(); }
364
365 int signalIndex(const char *signalName, const QMetaObject **meta = nullptr) const;
366 bool isSignalConnected(uint signalIdx, bool checkDeclarative = true) const;
367 bool maybeSignalConnected(uint signalIndex) const;
368 inline bool isDeclarativeSignalConnected(uint signalIdx) const;
369
370 // To allow abitrary objects to call connectNotify()/disconnectNotify() without making
371 // the API public in QObject. This is used by QQmlNotifierEndpoint.
372 inline void connectNotify(const QMetaMethod &signal);
373 inline void disconnectNotify(const QMetaMethod &signal);
374
375 template <typename Func1, typename Func2>
376 static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
377 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
378 Qt::ConnectionType type = Qt::AutoConnection);
379
380 template <typename Func1, typename Func2>
381 static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
382 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot);
383
384 static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index,
385 const QObject *receiver, void **slot,
386 QtPrivate::QSlotObjectBase *slotObj, int type,
387 const int *types, const QMetaObject *senderMetaObject);
388 static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type);
389 static QMetaObject::Connection connect(const QObject *sender, int signal_index,
390 const QObject *receiver,
391 QtPrivate::QSlotObjectBase *slotObj,
392 Qt::ConnectionType type);
393 static bool disconnect(const QObject *sender, int signal_index, void **slot);
394 static bool disconnect(const QObject *sender, int signal_index, const QObject *receiver,
395 void **slot);
396 static bool disconnect(Connection *c);
397
398 void ensureConnectionData()
399 {
400 if (connections.loadRelaxed())
401 return;
402 ConnectionData *cd = new ConnectionData;
403 cd->ref.ref();
404 connections.storeRelaxed(cd);
405 }
406
407public:
408 mutable ExtraData *extraData; // extra data set by the user
409 // This atomic requires acquire/release semantics in a few places,
410 // e.g. QObject::moveToThread must synchronize with QCoreApplication::postEvent,
411 // because postEvent is thread-safe.
412 // However, most of the code paths involving QObject are only reentrant and
413 // not thread-safe, so synchronization should not be necessary there.
414 QAtomicPointer<QThreadData> threadData; // id of the thread that owns the object
415
416 using ConnectionDataPointer = QExplicitlySharedDataPointer<ConnectionData>;
417 QAtomicPointer<ConnectionData> connections;
418
419 union {
420 QObject *currentChildBeingDeleted; // should only be used when QObjectData::isDeletingChildren is set
421 QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module
422 };
423
424 // these objects are all used to indicate that a QObject was deleted
425 // plus QPointer, which keeps a separate list
426 QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount;
427};
428
429Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_RELOCATABLE_TYPE);
430
431/*
432 Catch mixing of incompatible library versions.
433
434 Should be called from the constructor of every non-final subclass
435 of QObjectPrivate, to ensure we catch incompatibilities between
436 the intermediate base and subclasses thereof.
437*/
438inline void QObjectPrivate::checkForIncompatibleLibraryVersion(int version) const
439{
440#if defined(QT_BUILD_INTERNAL)
441 // Don't check the version parameter in internal builds.
442 // This allows incompatible versions to be loaded, possibly for testing.
443 Q_UNUSED(version);
444#else
445 if (Q_UNLIKELY(version != QObjectPrivateVersion)) {
446 qFatal("Cannot mix incompatible Qt library (%d.%d.%d) with this library (%d.%d.%d)",
447 (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff,
448 (QObjectPrivateVersion >> 16) & 0xff, (QObjectPrivateVersion >> 8) & 0xff, QObjectPrivateVersion & 0xff);
449 }
450#endif
451}
452
453inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const
454{
455 return declarativeData && QAbstractDeclarativeData::isSignalConnected
456 && QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index);
457}
458
459inline void QObjectPrivate::connectNotify(const QMetaMethod &signal)
460{
461 q_ptr->connectNotify(signal);
462}
463
464inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal)
465{
466 q_ptr->disconnectNotify(signal);
467}
468
469namespace QtPrivate {
470template<typename Func, typename Args, typename R> class QPrivateSlotObject : public QSlotObjectBase
471{
472 typedef QtPrivate::FunctionPointer<Func> FuncType;
473 Func function;
474 static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
475 {
476 switch (which) {
477 case Destroy:
478 delete static_cast<QPrivateSlotObject*>(this_);
479 break;
480 case Call:
481 FuncType::template call<Args, R>(static_cast<QPrivateSlotObject*>(this_)->function,
482 static_cast<typename FuncType::Object *>(QObjectPrivate::get(r)), a);
483 break;
484 case Compare:
485 *ret = *reinterpret_cast<Func *>(a) == static_cast<QPrivateSlotObject*>(this_)->function;
486 break;
487 case NumOperations: ;
488 }
489 }
490public:
491 explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
492};
493} //namespace QtPrivate
494
495template <typename Func1, typename Func2>
496inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
497 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
498 Qt::ConnectionType type)
499{
500 typedef QtPrivate::FunctionPointer<Func1> SignalType;
501 typedef QtPrivate::FunctionPointer<Func2> SlotType;
502 static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
503 "No Q_OBJECT in the class with the signal");
504
505 //compilation error if the arguments does not match.
506 static_assert(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
507 "The slot requires more arguments than the signal provides.");
508 static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
509 "Signal and slot arguments are not compatible.");
510 static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
511 "Return type of the slot is not compatible with the return type of the signal.");
512
513 const int *types = nullptr;
514 if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
515 types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
516
517 return QObject::connectImpl(sender, reinterpret_cast<void **>(&signal),
518 receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot),
519 new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
520 typename SignalType::ReturnType>(slot),
521 type, types, &SignalType::Object::staticMetaObject);
522}
523
524template <typename Func1, typename Func2>
525bool QObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object* sender, Func1 signal,
526 const typename QtPrivate::FunctionPointer< Func2 >::Object* receiverPrivate, Func2 slot)
527{
528 typedef QtPrivate::FunctionPointer<Func1> SignalType;
529 typedef QtPrivate::FunctionPointer<Func2> SlotType;
530 static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
531 "No Q_OBJECT in the class with the signal");
532 //compilation error if the arguments does not match.
533 static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
534 "Signal and slot arguments are not compatible.");
535 return QObject::disconnectImpl(sender, reinterpret_cast<void **>(&signal),
536 receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot),
537 &SignalType::Object::staticMetaObject);
538}
539
540Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_RELOCATABLE_TYPE);
541Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_RELOCATABLE_TYPE);
542
543class QSemaphore;
544class Q_CORE_EXPORT QAbstractMetaCallEvent : public QEvent
545{
546public:
547 QAbstractMetaCallEvent(const QObject *sender, int signalId, QSemaphore *semaphore = nullptr)
548 : QEvent(MetaCall), signalId_(signalId), sender_(sender)
549#if QT_CONFIG(thread)
550 , semaphore_(semaphore)
551#endif
552 { Q_UNUSED(semaphore); }
553 ~QAbstractMetaCallEvent();
554
555 virtual void placeMetaCall(QObject *object) = 0;
556
557 inline const QObject *sender() const { return sender_; }
558 inline int signalId() const { return signalId_; }
559
560private:
561 int signalId_;
562 const QObject *sender_;
563#if QT_CONFIG(thread)
564 QSemaphore *semaphore_;
565#endif
566};
567
568class Q_CORE_EXPORT QMetaCallEvent : public QAbstractMetaCallEvent
569{
570public:
571 // blocking queued with semaphore - args always owned by caller
572 QMetaCallEvent(ushort method_offset, ushort method_relative,
573 QObjectPrivate::StaticMetaCallFunction callFunction,
574 const QObject *sender, int signalId,
575 void **args, QSemaphore *semaphore);
576 QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
577 const QObject *sender, int signalId,
578 void **args, QSemaphore *semaphore);
579
580 // queued - args allocated by event, copied by caller
581 QMetaCallEvent(ushort method_offset, ushort method_relative,
582 QObjectPrivate::StaticMetaCallFunction callFunction,
583 const QObject *sender, int signalId,
584 int nargs);
585 QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
586 const QObject *sender, int signalId,
587 int nargs);
588
589 ~QMetaCallEvent() override;
590
591 inline int id() const { return d.method_offset_ + d.method_relative_; }
592 inline const void * const* args() const { return d.args_; }
593 inline void ** args() { return d.args_; }
594 inline const QMetaType *types() const { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); }
595 inline QMetaType *types() { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); }
596
597 virtual void placeMetaCall(QObject *object) override;
598
599private:
600 inline void allocArgs();
601
602 struct Data {
603 QtPrivate::QSlotObjectBase *slotObj_;
604 void **args_;
605 QObjectPrivate::StaticMetaCallFunction callFunction_;
606 int nargs_;
607 ushort method_offset_;
608 ushort method_relative_;
609 } d;
610 // preallocate enough space for three arguments
611 alignas(void *) char prealloc_[3 * sizeof(void *) + 3 * sizeof(QMetaType)];
612};
613
614class QBoolBlocker
615{
616 Q_DISABLE_COPY_MOVE(QBoolBlocker)
617public:
618 explicit inline QBoolBlocker(bool &b, bool value = true) : block(b), reset(b) { block = value; }
619 inline ~QBoolBlocker() { block = reset; }
620
621private:
622 bool &block;
623 bool reset;
624};
625
626void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o);
627
628struct QAbstractDynamicMetaObject;
629struct Q_CORE_EXPORT QDynamicMetaObjectData
630{
631 virtual ~QDynamicMetaObjectData();
632 virtual void objectDestroyed(QObject *) { delete this; }
633
634 virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) = 0;
635 virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **) = 0;
636};
637
638struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject
639{
640 ~QAbstractDynamicMetaObject();
641
642 QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) override { return this; }
643 virtual int createProperty(const char *, const char *) { return -1; }
644 int metaCall(QObject *, QMetaObject::Call c, int _id, void **a) override
645 { return metaCall(c, _id, a); }
646 virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; } // Compat overload
647};
648
649inline const QBindingStorage *qGetBindingStorage(const QObjectPrivate *o)
650{
651 return &o->bindingStorage;
652}
653inline QBindingStorage *qGetBindingStorage(QObjectPrivate *o)
654{
655 return &o->bindingStorage;
656}
657inline const QBindingStorage *qGetBindingStorage(const QObjectPrivate::ExtraData *ed)
658{
659 return &ed->parent->bindingStorage;
660}
661inline QBindingStorage *qGetBindingStorage(QObjectPrivate::ExtraData *ed)
662{
663 return &ed->parent->bindingStorage;
664}
665
666QT_END_NAMESPACE
667
668#endif // QOBJECT_P_H
669

source code of qtbase/src/corelib/kernel/qobject_p.h