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
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 (*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
102struct QAbstractDeclarativeDataImpl : public QAbstractDeclarativeData
103{
104 quint32 ownedByQml1:1;
105 quint32 unused: 31;
106};
107
108class Q_CORE_EXPORT QObjectPrivate : public QObjectData
109{
110 Q_DECLARE_PUBLIC(QObject)
111
112public:
113 struct ExtraData
114 {
115 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
138 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 }
143 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;
172 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();
176 int method() const { Q_ASSERT(!isSlotObject); return method_offset + method_relative; }
177 void ref() { ref_.ref(); }
178 void freeSlotObject()
179 {
180 if (isSlotObject) {
181 slotObj->destroyIfLastRef();
182 isSlotObject = false;
183 }
184 }
185 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 {
201 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 }
210 ~Sender()
211 {
212 if (receiver)
213 receiver->d_func()->connections.loadRelaxed()->currentSender = previous;
214 }
215 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[]
232 ConnectionList &at(int i)
233 {
234 return reinterpret_cast<ConnectionList *>(this + 1)[i + 1];
235 }
236 const ConnectionList &at(int i) const
237 {
238 return reinterpret_cast<const ConnectionList *>(this + 1)[i + 1];
239 }
240 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
269 ~ConnectionData()
270 {
271 Q_ASSERT(ref.loadRelaxed() == 0);
272 auto *c = orphaned.fetchAndStoreRelaxed(newValue: nullptr);
273 if (c)
274 deleteOrphaned(c);
275 SignalVector *v = signalVector.loadRelaxed();
276 if (v)
277 free(ptr: v);
278 }
279
280 // must be called on the senders connection data
281 // assumes the senders and receivers lock are held
282 void removeConnection(Connection *c);
283 enum LockPolicy {
284 NeedToLock,
285 // Beware that we need to temporarily release the lock
286 // and thus calling code must carefully consider whether
287 // invariants still hold.
288 AlreadyLockedAndTemporarilyReleasingLock
289 };
290 void cleanOrphanedConnections(QObject *sender, LockPolicy lockPolicy = NeedToLock)
291 {
292 if (orphaned.loadRelaxed() && ref.loadAcquire() == 1)
293 cleanOrphanedConnectionsImpl(sender, lockPolicy);
294 }
295 void cleanOrphanedConnectionsImpl(QObject *sender, LockPolicy lockPolicy);
296
297 ConnectionList &connectionsForSignal(int signal)
298 {
299 return signalVector.loadRelaxed()->at(i: signal);
300 }
301
302 void resizeSignalVector(uint size) {
303 SignalVector *vector = this->signalVector.loadRelaxed();
304 if (vector && vector->allocated > size)
305 return;
306 size = (size + 7) & ~7;
307 SignalVector *newVector = reinterpret_cast<SignalVector *>(malloc(size: sizeof(SignalVector) + (size + 1) * sizeof(ConnectionList)));
308 int start = -1;
309 if (vector) {
310 memcpy(dest: newVector, src: vector, n: sizeof(SignalVector) + (vector->allocated + 1) * sizeof(ConnectionList));
311 start = vector->count();
312 }
313 for (int i = start; i < int(size); ++i)
314 newVector->at(i) = ConnectionList();
315 newVector->next = nullptr;
316 newVector->allocated = size;
317
318 signalVector.storeRelaxed(newValue: newVector);
319 if (vector) {
320 Connection *o = nullptr;
321 /* No ABA issue here: When adding a node, we only care about the list head, it doesn't
322 * matter if the tail changes.
323 */
324 do {
325 o = orphaned.loadRelaxed();
326 vector->nextInOrphanList = o;
327 } while (!orphaned.testAndSetRelease(expectedValue: o, newValue: ConnectionOrSignalVector::fromSignalVector(v: vector)));
328 }
329 }
330 int signalVectorCount() const {
331 return signalVector.loadAcquire() ? signalVector.loadRelaxed()->count() : -1;
332 }
333
334 static void deleteOrphaned(ConnectionOrSignalVector *c);
335 };
336
337 QObjectPrivate(int version = QObjectPrivateVersion);
338 virtual ~QObjectPrivate();
339 void deleteChildren();
340
341 inline void checkForIncompatibleLibraryVersion(int version) const;
342
343 void setParent_helper(QObject *);
344 void moveToThread_helper();
345 void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
346 void _q_reregisterTimers(void *pointer);
347
348 bool isSender(const QObject *receiver, const char *signal) const;
349 QObjectList receiverList(const char *signal) const;
350 QObjectList senderList() const;
351
352 void addConnection(int signal, Connection *c);
353
354 static QObjectPrivate *get(QObject *o) {
355 return o->d_func();
356 }
357 static const QObjectPrivate *get(const QObject *o) { return o->d_func(); }
358
359 int signalIndex(const char *signalName, const QMetaObject **meta = nullptr) const;
360 bool isSignalConnected(uint signalIdx, bool checkDeclarative = true) const;
361 bool maybeSignalConnected(uint signalIndex) const;
362 inline bool isDeclarativeSignalConnected(uint signalIdx) const;
363
364 // To allow abitrary objects to call connectNotify()/disconnectNotify() without making
365 // the API public in QObject. This is used by QQmlNotifierEndpoint.
366 inline void connectNotify(const QMetaMethod &signal);
367 inline void disconnectNotify(const QMetaMethod &signal);
368
369 template <typename Func1, typename Func2>
370 static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
371 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
372 Qt::ConnectionType type = Qt::AutoConnection);
373
374 template <typename Func1, typename Func2>
375 static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
376 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot);
377
378 static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index,
379 const QObject *receiver, void **slot,
380 QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
381 const int *types, const QMetaObject *senderMetaObject);
382 static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type);
383 static QMetaObject::Connection connect(const QObject *sender, int signal_index,
384 const QObject *receiver,
385 QtPrivate::QSlotObjectBase *slotObj,
386 Qt::ConnectionType type);
387 static bool disconnect(const QObject *sender, int signal_index, void **slot);
388 static bool disconnect(const QObject *sender, int signal_index, const QObject *receiver,
389 void **slot);
390
391 void ensureConnectionData()
392 {
393 if (connections.loadRelaxed())
394 return;
395 ConnectionData *cd = new ConnectionData;
396 cd->ref.ref();
397 connections.storeRelaxed(newValue: cd);
398 }
399public:
400 ExtraData *extraData; // extra data set by the user
401 // This atomic requires acquire/release semantics in a few places,
402 // e.g. QObject::moveToThread must synchronize with QCoreApplication::postEvent,
403 // because postEvent is thread-safe.
404 // However, most of the code paths involving QObject are only reentrant and
405 // not thread-safe, so synchronization should not be necessary there.
406 QAtomicPointer<QThreadData> threadData; // id of the thread that owns the object
407
408 using ConnectionDataPointer = QExplicitlySharedDataPointer<ConnectionData>;
409 QAtomicPointer<ConnectionData> connections;
410
411 union {
412 QObject *currentChildBeingDeleted; // should only be used when QObjectData::isDeletingChildren is set
413 QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module
414 };
415
416 // these objects are all used to indicate that a QObject was deleted
417 // plus QPointer, which keeps a separate list
418 QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount;
419};
420
421Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_MOVABLE_TYPE);
422
423/*
424 Catch mixing of incompatible library versions.
425
426 Should be called from the constructor of every non-final subclass
427 of QObjectPrivate, to ensure we catch incompatibilities between
428 the intermediate base and subclasses thereof.
429*/
430inline void QObjectPrivate::checkForIncompatibleLibraryVersion(int version) const
431{
432#if defined(QT_BUILD_INTERNAL)
433 // Don't check the version parameter in internal builds.
434 // This allows incompatible versions to be loaded, possibly for testing.
435 Q_UNUSED(version);
436#else
437 if (Q_UNLIKELY(version != QObjectPrivateVersion)) {
438 qFatal("Cannot mix incompatible Qt library (%d.%d.%d) with this library (%d.%d.%d)",
439 (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff,
440 (QObjectPrivateVersion >> 16) & 0xff, (QObjectPrivateVersion >> 8) & 0xff, QObjectPrivateVersion & 0xff);
441 }
442#endif
443}
444
445inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const
446{
447 return declarativeData && QAbstractDeclarativeData::isSignalConnected
448 && QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index);
449}
450
451inline void QObjectPrivate::connectNotify(const QMetaMethod &signal)
452{
453 q_ptr->connectNotify(signal);
454}
455
456inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal)
457{
458 q_ptr->disconnectNotify(signal);
459}
460
461namespace QtPrivate {
462template<typename Func, typename Args, typename R> class QPrivateSlotObject : public QSlotObjectBase
463{
464 typedef QtPrivate::FunctionPointer<Func> FuncType;
465 Func function;
466 static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
467 {
468 switch (which) {
469 case Destroy:
470 delete static_cast<QPrivateSlotObject*>(this_);
471 break;
472 case Call:
473 FuncType::template call<Args, R>(static_cast<QPrivateSlotObject*>(this_)->function,
474 static_cast<typename FuncType::Object *>(QObjectPrivate::get(o: r)), a);
475 break;
476 case Compare:
477 *ret = *reinterpret_cast<Func *>(a) == static_cast<QPrivateSlotObject*>(this_)->function;
478 break;
479 case NumOperations: ;
480 }
481 }
482public:
483 explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
484};
485} //namespace QtPrivate
486
487template <typename Func1, typename Func2>
488inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
489 const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
490 Qt::ConnectionType type)
491{
492 typedef QtPrivate::FunctionPointer<Func1> SignalType;
493 typedef QtPrivate::FunctionPointer<Func2> SlotType;
494 Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
495 "No Q_OBJECT in the class with the signal");
496
497 //compilation error if the arguments does not match.
498 Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
499 "The slot requires more arguments than the signal provides.");
500 Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
501 "Signal and slot arguments are not compatible.");
502 Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
503 "Return type of the slot is not compatible with the return type of the signal.");
504
505 const int *types = nullptr;
506 if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
507 types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
508
509 return QObject::connectImpl(sender, signal: reinterpret_cast<void **>(&signal),
510 receiver: receiverPrivate->q_ptr, slotPtr: reinterpret_cast<void **>(&slot),
511 slot: new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
512 typename SignalType::ReturnType>(slot),
513 type, types, senderMetaObject: &SignalType::Object::staticMetaObject);
514}
515
516template <typename Func1, typename Func2>
517bool QObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object* sender, Func1 signal,
518 const typename QtPrivate::FunctionPointer< Func2 >::Object* receiverPrivate, Func2 slot)
519{
520 typedef QtPrivate::FunctionPointer<Func1> SignalType;
521 typedef QtPrivate::FunctionPointer<Func2> SlotType;
522 Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
523 "No Q_OBJECT in the class with the signal");
524 //compilation error if the arguments does not match.
525 Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
526 "Signal and slot arguments are not compatible.");
527 return QObject::disconnectImpl(sender, signal: reinterpret_cast<void **>(&signal),
528 receiver: receiverPrivate->q_ptr, slot: reinterpret_cast<void **>(&slot),
529 senderMetaObject: &SignalType::Object::staticMetaObject);
530}
531
532Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE);
533Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE);
534
535class QSemaphore;
536class Q_CORE_EXPORT QAbstractMetaCallEvent : public QEvent
537{
538public:
539 QAbstractMetaCallEvent(const QObject *sender, int signalId, QSemaphore *semaphore = nullptr)
540 : QEvent(MetaCall), signalId_(signalId), sender_(sender)
541#if QT_CONFIG(thread)
542 , semaphore_(semaphore)
543#endif
544 { Q_UNUSED(semaphore); }
545 ~QAbstractMetaCallEvent();
546
547 virtual void placeMetaCall(QObject *object) = 0;
548
549 inline const QObject *sender() const { return sender_; }
550 inline int signalId() const { return signalId_; }
551
552private:
553 int signalId_;
554 const QObject *sender_;
555#if QT_CONFIG(thread)
556 QSemaphore *semaphore_;
557#endif
558};
559
560class Q_CORE_EXPORT QMetaCallEvent : public QAbstractMetaCallEvent
561{
562public:
563 // blocking queued with semaphore - args always owned by caller
564 QMetaCallEvent(ushort method_offset, ushort method_relative,
565 QObjectPrivate::StaticMetaCallFunction callFunction,
566 const QObject *sender, int signalId,
567 void **args, QSemaphore *semaphore);
568 QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
569 const QObject *sender, int signalId,
570 void **args, QSemaphore *semaphore);
571
572 // queued - args allocated by event, copied by caller
573 QMetaCallEvent(ushort method_offset, ushort method_relative,
574 QObjectPrivate::StaticMetaCallFunction callFunction,
575 const QObject *sender, int signalId,
576 int nargs);
577 QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
578 const QObject *sender, int signalId,
579 int nargs);
580
581 ~QMetaCallEvent() override;
582
583 inline int id() const { return d.method_offset_ + d.method_relative_; }
584 inline const void * const* args() const { return d.args_; }
585 inline void ** args() { return d.args_; }
586 inline const int *types() const { return reinterpret_cast<int*>(d.args_ + d.nargs_); }
587 inline int *types() { return reinterpret_cast<int*>(d.args_ + d.nargs_); }
588
589 virtual void placeMetaCall(QObject *object) override;
590
591private:
592 inline void allocArgs();
593
594 struct Data {
595 QtPrivate::QSlotObjectBase *slotObj_;
596 void **args_;
597 QObjectPrivate::StaticMetaCallFunction callFunction_;
598 int nargs_;
599 ushort method_offset_;
600 ushort method_relative_;
601 } d;
602 // preallocate enough space for three arguments
603 char prealloc_[3*(sizeof(void*) + sizeof(int))];
604};
605
606class QBoolBlocker
607{
608 Q_DISABLE_COPY_MOVE(QBoolBlocker)
609public:
610 explicit inline QBoolBlocker(bool &b, bool value=true):block(b), reset(b){block = value;}
611 inline ~QBoolBlocker(){block = reset; }
612private:
613 bool &block;
614 bool reset;
615};
616
617void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o);
618
619struct QAbstractDynamicMetaObject;
620struct Q_CORE_EXPORT QDynamicMetaObjectData
621{
622 virtual ~QDynamicMetaObjectData();
623 virtual void objectDestroyed(QObject *) { delete this; }
624
625 virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) = 0;
626 virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **) = 0;
627};
628
629struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject
630{
631 ~QAbstractDynamicMetaObject();
632
633 QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) override { return this; }
634 virtual int createProperty(const char *, const char *) { return -1; }
635 int metaCall(QObject *, QMetaObject::Call c, int _id, void **a) override
636 { return metaCall(c, _id, a); }
637 virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; } // Compat overload
638};
639
640QT_END_NAMESPACE
641
642#endif // QOBJECT_P_H
643

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