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 |
114 | { |
115 | () {} |
116 | #ifndef QT_NO_USERDATA |
117 | QVector<QObjectUserData *> ; |
118 | #endif |
119 | QList<QByteArray> ; |
120 | QVector<QVariant> ; |
121 | QVector<int> ; |
122 | QList<QPointer<QObject> > ; |
123 | QString ; |
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 | } |
377 | public: |
378 | 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 | */ |
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 | |
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 | |
429 | inline void QObjectPrivate::connectNotify(const QMetaMethod &signal) |
430 | { |
431 | q_ptr->connectNotify(signal); |
432 | } |
433 | |
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; |
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: |
461 | explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {} |
462 | }; |
463 | } //namespace QtPrivate |
464 | |
465 | template <typename Func1, typename Func2> |
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> |
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) |
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 | |
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 | |
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 | |
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 | { |
586 | Q_DISABLE_COPY_MOVE(QBoolBlocker) |
587 | public: |
588 | explicit inline QBoolBlocker(bool &b, bool value=true):block(b), reset(b){block = value;} |
589 | inline ~QBoolBlocker(){block = reset; } |
590 | private: |
591 | bool █ |
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(); |
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 | |
607 | struct 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 | |
618 | QT_END_NAMESPACE |
619 | |
620 | #endif // QOBJECT_P_H |
621 | |