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