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 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);
280 void cleanOrphanedConnections(QObject *sender)
281 {
282 if (orphaned.loadRelaxed() && ref.loadAcquire() == 1)
283 cleanOrphanedConnectionsImpl(sender);
284 }
285 void cleanOrphanedConnectionsImpl(QObject *sender);
286
287 ConnectionList &connectionsForSignal(int signal)
288 {
289 return signalVector.loadRelaxed()->at(signal);
290 }
291
292 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 }
314 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
338 static QObjectPrivate *get(QObject *o) {
339 return o->d_func();
340 }
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
369 void ensureConnectionData()
370 {
371 if (connections.loadRelaxed())
372 return;
373 ConnectionData *cd = new ConnectionData;
374 cd->ref.ref();
375 connections.storeRelaxed(cd);
376 }
377public:
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
399Q_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*/
408inline 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
423inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const
424{
425 return declarativeData && QAbstractDeclarativeData::isSignalConnected
426 && QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index);
427}
428
429inline void QObjectPrivate::connectNotify(const QMetaMethod &signal)
430{
431 q_ptr->connectNotify(signal);
432}
433
434inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal)
435{
436 q_ptr->disconnectNotify(signal);
437}
438
439namespace QtPrivate {
440template<typename Func, typename Args, typename R> class QPrivateSlotObject : public QSlotObjectBase
441{
442 typedef QtPrivate::FunctionPointer<Func> FuncType;
443 Func function;
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 }
460public:
461 explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
462};
463} //namespace QtPrivate
464
465template <typename Func1, typename Func2>
466inline 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
494template <typename Func1, typename Func2>
495bool 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
510Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE);
511Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE);
512
513class QSemaphore;
514class Q_CORE_EXPORT QAbstractMetaCallEvent : public QEvent
515{
516public:
517 QAbstractMetaCallEvent(const QObject *sender, int signalId, QSemaphore *semaphore = nullptr)
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
527 inline const QObject *sender() const { return sender_; }
528 inline int signalId() const { return signalId_; }
529
530private:
531 int signalId_;
532 const QObject *sender_;
533#if QT_CONFIG(thread)
534 QSemaphore *semaphore_;
535#endif
536};
537
538class Q_CORE_EXPORT QMetaCallEvent : public QAbstractMetaCallEvent
539{
540public:
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
561 inline int id() const { return d.method_offset_ + d.method_relative_; }
562 inline const void * const* args() const { return d.args_; }
563 inline void ** args() { return d.args_; }
564 inline const int *types() const { return reinterpret_cast<int*>(d.args_ + d.nargs_); }
565 inline int *types() { return reinterpret_cast<int*>(d.args_ + d.nargs_); }
566
567 virtual void placeMetaCall(QObject *object) override;
568
569private:
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
584class QBoolBlocker
585{
586 Q_DISABLE_COPY_MOVE(QBoolBlocker)
587public:
588 explicit inline QBoolBlocker(bool &b, bool value=true):block(b), reset(b){block = value;}
589 inline ~QBoolBlocker(){block = reset; }
590private:
591 bool &block;
592 bool reset;
593};
594
595void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o);
596
597struct QAbstractDynamicMetaObject;
598struct Q_CORE_EXPORT QDynamicMetaObjectData
599{
600 virtual ~QDynamicMetaObjectData();
601 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
607struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject
608{
609 ~QAbstractDynamicMetaObject();
610
611 QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) override { return this; }
612 virtual int createProperty(const char *, const char *) { return -1; }
613 int metaCall(QObject *, QMetaObject::Call c, int _id, void **a) override
614 { return metaCall(c, _id, a); }
615 virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; } // Compat overload
616};
617
618QT_END_NAMESPACE
619
620#endif // QOBJECT_P_H
621

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