1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2019 The Qt Company Ltd. |
4 | ** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com> |
5 | ** Contact: https://www.qt.io/licensing/ |
6 | ** |
7 | ** This file is part of the QtCore module of the Qt Toolkit. |
8 | ** |
9 | ** $QT_BEGIN_LICENSE:LGPL$ |
10 | ** Commercial License Usage |
11 | ** Licensees holding valid commercial Qt licenses may use this file in |
12 | ** accordance with the commercial license agreement provided with the |
13 | ** Software or, alternatively, in accordance with the terms contained in |
14 | ** a written agreement between you and The Qt Company. For licensing terms |
15 | ** and conditions see https://www.qt.io/terms-conditions. For further |
16 | ** information use the contact form at https://www.qt.io/contact-us. |
17 | ** |
18 | ** GNU Lesser General Public License Usage |
19 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
20 | ** General Public License version 3 as published by the Free Software |
21 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
22 | ** packaging of this file. Please review the following information to |
23 | ** ensure the GNU Lesser General Public License version 3 requirements |
24 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
25 | ** |
26 | ** GNU General Public License Usage |
27 | ** Alternatively, this file may be used under the terms of the GNU |
28 | ** General Public License version 2.0 or (at your option) the GNU General |
29 | ** Public license version 3 or any later version approved by the KDE Free |
30 | ** Qt Foundation. The licenses are as published by the Free Software |
31 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
32 | ** included in the packaging of this file. Please review the following |
33 | ** information to ensure the GNU General Public License requirements will |
34 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
35 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
36 | ** |
37 | ** $QT_END_LICENSE$ |
38 | ** |
39 | ****************************************************************************/ |
40 | |
41 | #ifndef QOBJECT_P_H |
42 | #define QOBJECT_P_H |
43 | |
44 | // |
45 | // W A R N I N G |
46 | // ------------- |
47 | // |
48 | // This file is not part of the Qt API. It exists for the convenience |
49 | // of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header |
50 | // file may change from version to version without notice, or even be removed. |
51 | // |
52 | // We mean it. |
53 | // |
54 | |
55 | #include <QtCore/private/qglobal_p.h> |
56 | #include "QtCore/qcoreevent.h" |
57 | #include "QtCore/qlist.h" |
58 | #include "QtCore/qobject.h" |
59 | #include "QtCore/qpointer.h" |
60 | #include "QtCore/qreadwritelock.h" |
61 | #include "QtCore/qsharedpointer.h" |
62 | #include "QtCore/qvariant.h" |
63 | #include "QtCore/qproperty.h" |
64 | |
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 (*parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *); |
93 | static void (*signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **); |
94 | static int (*receivers)(QAbstractDeclarativeData *, const QObject *, int); |
95 | static bool (*isSignalConnected)(QAbstractDeclarativeData *, const QObject *, int); |
96 | static void (*setWidgetParent)(QObject *, QObject *); // Used by the QML engine to specify parents for widgets. Set by QtWidgets. |
97 | }; |
98 | |
99 | class Q_CORE_EXPORT QObjectPrivate : public QObjectData |
100 | { |
101 | Q_DECLARE_PUBLIC(QObject) |
102 | |
103 | public: |
104 | struct |
105 | { |
106 | () {} |
107 | QList<QByteArray> ; |
108 | QList<QVariant> ; |
109 | QList<int> ; |
110 | QList<QPointer<QObject>> ; |
111 | QString ; |
112 | }; |
113 | |
114 | typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **); |
115 | struct Connection; |
116 | struct SignalVector; |
117 | |
118 | struct ConnectionOrSignalVector { |
119 | union { |
120 | // linked list of orphaned connections that need cleaning up |
121 | ConnectionOrSignalVector *nextInOrphanList; |
122 | // linked list of connections connected to slots in this object |
123 | Connection *next; |
124 | }; |
125 | |
126 | static SignalVector *asSignalVector(ConnectionOrSignalVector *c) |
127 | { |
128 | if (reinterpret_cast<quintptr>(c) & 1) |
129 | return reinterpret_cast<SignalVector *>(reinterpret_cast<quintptr>(c) & ~quintptr(1u)); |
130 | return nullptr; |
131 | } |
132 | static Connection *fromSignalVector(SignalVector *v) { |
133 | return reinterpret_cast<Connection *>(reinterpret_cast<quintptr>(v) | quintptr(1u)); |
134 | } |
135 | }; |
136 | |
137 | struct Connection : public ConnectionOrSignalVector |
138 | { |
139 | // linked list of connections connected to slots in this object, next is in base class |
140 | Connection **prev; |
141 | // linked list of connections connected to signals in this object |
142 | QAtomicPointer<Connection> nextConnectionList; |
143 | Connection *prevConnectionList; |
144 | |
145 | QObject *sender; |
146 | QAtomicPointer<QObject> receiver; |
147 | QAtomicPointer<QThreadData> receiverThreadData; |
148 | union { |
149 | StaticMetaCallFunction callFunction; |
150 | QtPrivate::QSlotObjectBase *slotObj; |
151 | }; |
152 | QAtomicPointer<const int> argumentTypes; |
153 | QAtomicInt ref_; |
154 | uint id = 0; |
155 | ushort method_offset; |
156 | ushort method_relative; |
157 | signed int signal_index : 27; // In signal range (see QObjectPrivate::signalIndex()) |
158 | ushort connectionType : 2; // 0 == auto, 1 == direct, 2 == queued, 3 == blocking |
159 | ushort isSlotObject : 1; |
160 | ushort ownArgumentTypes : 1; |
161 | ushort isSingleShot : 1; |
162 | Connection() : ref_(2), ownArgumentTypes(true) { |
163 | //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection |
164 | } |
165 | ~Connection(); |
166 | int method() const { Q_ASSERT(!isSlotObject); return method_offset + method_relative; } |
167 | void ref() { ref_.ref(); } |
168 | void freeSlotObject() |
169 | { |
170 | if (isSlotObject) { |
171 | slotObj->destroyIfLastRef(); |
172 | isSlotObject = false; |
173 | } |
174 | } |
175 | void deref() |
176 | { |
177 | if (!ref_.deref()) { |
178 | Q_ASSERT(!receiver.loadRelaxed()); |
179 | Q_ASSERT(!isSlotObject); |
180 | delete this; |
181 | } |
182 | } |
183 | }; |
184 | // ConnectionList is a singly-linked list |
185 | struct ConnectionList { |
186 | QAtomicPointer<Connection> first; |
187 | QAtomicPointer<Connection> last; |
188 | }; |
189 | |
190 | struct Sender |
191 | { |
192 | Sender(QObject *receiver, QObject *sender, int signal) |
193 | : receiver(receiver), sender(sender), signal(signal) |
194 | { |
195 | if (receiver) { |
196 | ConnectionData *cd = receiver->d_func()->connections.loadRelaxed(); |
197 | previous = cd->currentSender; |
198 | cd->currentSender = this; |
199 | } |
200 | } |
201 | ~Sender() |
202 | { |
203 | if (receiver) |
204 | receiver->d_func()->connections.loadRelaxed()->currentSender = previous; |
205 | } |
206 | void receiverDeleted() |
207 | { |
208 | Sender *s = this; |
209 | while (s) { |
210 | s->receiver = nullptr; |
211 | s = s->previous; |
212 | } |
213 | } |
214 | Sender *previous; |
215 | QObject *receiver; |
216 | QObject *sender; |
217 | int signal; |
218 | }; |
219 | |
220 | struct SignalVector : public ConnectionOrSignalVector { |
221 | quintptr allocated; |
222 | // ConnectionList signals[] |
223 | ConnectionList &at(int i) |
224 | { |
225 | return reinterpret_cast<ConnectionList *>(this + 1)[i + 1]; |
226 | } |
227 | const ConnectionList &at(int i) const |
228 | { |
229 | return reinterpret_cast<const ConnectionList *>(this + 1)[i + 1]; |
230 | } |
231 | int count() const { return static_cast<int>(allocated); } |
232 | }; |
233 | |
234 | /* |
235 | This contains the all connections from and to an object. |
236 | |
237 | The signalVector contains the lists of connections for a given signal. The index in the vector correspond |
238 | to the signal index. The signal index is the one returned by QObjectPrivate::signalIndex (not |
239 | QMetaObject::indexOfSignal). allsignals contains a list of special connections that will get invoked on |
240 | any signal emission. This is done by connecting to signal index -1. |
241 | |
242 | This vector is protected by the object mutex (signalSlotLock()) |
243 | |
244 | Each Connection is also part of a 'senders' linked list. This one contains all connections connected |
245 | to a slot in this object. The mutex of the receiver must be locked when touching the pointers of this |
246 | linked list. |
247 | */ |
248 | struct ConnectionData { |
249 | // the id below is used to avoid activating new connections. When the object gets |
250 | // deleted it's set to 0, so that signal emission stops |
251 | QAtomicInteger<uint> currentConnectionId; |
252 | QAtomicInt ref; |
253 | QAtomicPointer<SignalVector> signalVector; |
254 | Connection *senders = nullptr; |
255 | Sender *currentSender = nullptr; // object currently activating the object |
256 | QAtomicPointer<Connection> orphaned; |
257 | |
258 | ~ConnectionData() |
259 | { |
260 | deleteOrphaned(orphaned.loadRelaxed()); |
261 | SignalVector *v = signalVector.loadRelaxed(); |
262 | if (v) |
263 | free(v); |
264 | } |
265 | |
266 | // must be called on the senders connection data |
267 | // assumes the senders and receivers lock are held |
268 | void removeConnection(Connection *c); |
269 | void cleanOrphanedConnections(QObject *sender) |
270 | { |
271 | if (orphaned.loadRelaxed() && ref.loadAcquire() == 1) |
272 | cleanOrphanedConnectionsImpl(sender); |
273 | } |
274 | void cleanOrphanedConnectionsImpl(QObject *sender); |
275 | |
276 | ConnectionList &connectionsForSignal(int signal) |
277 | { |
278 | return signalVector.loadRelaxed()->at(signal); |
279 | } |
280 | |
281 | void resizeSignalVector(uint size) |
282 | { |
283 | SignalVector *vector = this->signalVector.loadRelaxed(); |
284 | if (vector && vector->allocated > size) |
285 | return; |
286 | size = (size + 7) & ~7; |
287 | SignalVector *newVector = reinterpret_cast<SignalVector *>(malloc(sizeof(SignalVector) + (size + 1) * sizeof(ConnectionList))); |
288 | int start = -1; |
289 | if (vector) { |
290 | memcpy(newVector, vector, sizeof(SignalVector) + (vector->allocated + 1) * sizeof(ConnectionList)); |
291 | start = vector->count(); |
292 | } |
293 | for (int i = start; i < int(size); ++i) |
294 | newVector->at(i) = ConnectionList(); |
295 | newVector->next = nullptr; |
296 | newVector->allocated = size; |
297 | |
298 | signalVector.storeRelaxed(newVector); |
299 | if (vector) { |
300 | vector->nextInOrphanList = orphaned.loadRelaxed(); |
301 | orphaned.storeRelaxed(ConnectionOrSignalVector::fromSignalVector(vector)); |
302 | } |
303 | } |
304 | int signalVectorCount() const |
305 | { |
306 | return signalVector.loadAcquire() ? signalVector.loadRelaxed()->count() : -1; |
307 | } |
308 | |
309 | static void deleteOrphaned(ConnectionOrSignalVector *c); |
310 | }; |
311 | |
312 | QObjectPrivate(int version = QObjectPrivateVersion); |
313 | virtual ~QObjectPrivate(); |
314 | void deleteChildren(); |
315 | |
316 | inline void checkForIncompatibleLibraryVersion(int version) const; |
317 | |
318 | void setParent_helper(QObject *); |
319 | void moveToThread_helper(); |
320 | void setThreadData_helper(QThreadData *currentData, QThreadData *targetData); |
321 | void _q_reregisterTimers(void *pointer); |
322 | |
323 | bool isSender(const QObject *receiver, const char *signal) const; |
324 | QObjectList receiverList(const char *signal) const; |
325 | QObjectList senderList() const; |
326 | |
327 | void addConnection(int signal, Connection *c); |
328 | |
329 | static QObjectPrivate *get(QObject *o) { return o->d_func(); } |
330 | static const QObjectPrivate *get(const QObject *o) { return o->d_func(); } |
331 | |
332 | int signalIndex(const char *signalName, const QMetaObject **meta = nullptr) const; |
333 | bool isSignalConnected(uint signalIdx, bool checkDeclarative = true) const; |
334 | bool maybeSignalConnected(uint signalIndex) const; |
335 | inline bool isDeclarativeSignalConnected(uint signalIdx) const; |
336 | |
337 | // To allow abitrary objects to call connectNotify()/disconnectNotify() without making |
338 | // the API public in QObject. This is used by QQmlNotifierEndpoint. |
339 | inline void connectNotify(const QMetaMethod &signal); |
340 | inline void disconnectNotify(const QMetaMethod &signal); |
341 | |
342 | template <typename Func1, typename Func2> |
343 | static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, |
344 | const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot, |
345 | Qt::ConnectionType type = Qt::AutoConnection); |
346 | |
347 | template <typename Func1, typename Func2> |
348 | static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, |
349 | const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot); |
350 | |
351 | static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index, |
352 | const QObject *receiver, void **slot, |
353 | QtPrivate::QSlotObjectBase *slotObj, int type, |
354 | const int *types, const QMetaObject *senderMetaObject); |
355 | static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type); |
356 | static bool disconnect(const QObject *sender, int signal_index, void **slot); |
357 | static bool disconnect(Connection *c); |
358 | |
359 | void ensureConnectionData() |
360 | { |
361 | if (connections.loadRelaxed()) |
362 | return; |
363 | ConnectionData *cd = new ConnectionData; |
364 | cd->ref.ref(); |
365 | connections.storeRelaxed(cd); |
366 | } |
367 | public: |
368 | ExtraData *; // extra data set by the user |
369 | // This atomic requires acquire/release semantics in a few places, |
370 | // e.g. QObject::moveToThread must synchronize with QCoreApplication::postEvent, |
371 | // because postEvent is thread-safe. |
372 | // However, most of the code paths involving QObject are only reentrant and |
373 | // not thread-safe, so synchronization should not be necessary there. |
374 | QAtomicPointer<QThreadData> threadData; // id of the thread that owns the object |
375 | |
376 | using ConnectionDataPointer = QExplicitlySharedDataPointer<ConnectionData>; |
377 | QAtomicPointer<ConnectionData> connections; |
378 | |
379 | union { |
380 | QObject *currentChildBeingDeleted; // should only be used when QObjectData::isDeletingChildren is set |
381 | QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module |
382 | }; |
383 | |
384 | // these objects are all used to indicate that a QObject was deleted |
385 | // plus QPointer, which keeps a separate list |
386 | QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount; |
387 | QBindingStorage bindingStorage; |
388 | }; |
389 | |
390 | Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_MOVABLE_TYPE); |
391 | |
392 | /* |
393 | Catch mixing of incompatible library versions. |
394 | |
395 | Should be called from the constructor of every non-final subclass |
396 | of QObjectPrivate, to ensure we catch incompatibilities between |
397 | the intermediate base and subclasses thereof. |
398 | */ |
399 | inline void QObjectPrivate::checkForIncompatibleLibraryVersion(int version) const |
400 | { |
401 | #if defined(QT_BUILD_INTERNAL) |
402 | // Don't check the version parameter in internal builds. |
403 | // This allows incompatible versions to be loaded, possibly for testing. |
404 | Q_UNUSED(version); |
405 | #else |
406 | if (Q_UNLIKELY(version != QObjectPrivateVersion)) { |
407 | qFatal("Cannot mix incompatible Qt library (%d.%d.%d) with this library (%d.%d.%d)" , |
408 | (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff, |
409 | (QObjectPrivateVersion >> 16) & 0xff, (QObjectPrivateVersion >> 8) & 0xff, QObjectPrivateVersion & 0xff); |
410 | } |
411 | #endif |
412 | } |
413 | |
414 | inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const |
415 | { |
416 | return declarativeData && QAbstractDeclarativeData::isSignalConnected |
417 | && QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index); |
418 | } |
419 | |
420 | inline void QObjectPrivate::connectNotify(const QMetaMethod &signal) |
421 | { |
422 | q_ptr->connectNotify(signal); |
423 | } |
424 | |
425 | inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal) |
426 | { |
427 | q_ptr->disconnectNotify(signal); |
428 | } |
429 | |
430 | namespace QtPrivate { |
431 | template<typename Func, typename Args, typename R> class QPrivateSlotObject : public QSlotObjectBase |
432 | { |
433 | typedef QtPrivate::FunctionPointer<Func> FuncType; |
434 | Func function; |
435 | static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret) |
436 | { |
437 | switch (which) { |
438 | case Destroy: |
439 | delete static_cast<QPrivateSlotObject*>(this_); |
440 | break; |
441 | case Call: |
442 | FuncType::template call<Args, R>(static_cast<QPrivateSlotObject*>(this_)->function, |
443 | static_cast<typename FuncType::Object *>(QObjectPrivate::get(r)), a); |
444 | break; |
445 | case Compare: |
446 | *ret = *reinterpret_cast<Func *>(a) == static_cast<QPrivateSlotObject*>(this_)->function; |
447 | break; |
448 | case NumOperations: ; |
449 | } |
450 | } |
451 | public: |
452 | explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {} |
453 | }; |
454 | } //namespace QtPrivate |
455 | |
456 | template <typename Func1, typename Func2> |
457 | inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, |
458 | const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot, |
459 | Qt::ConnectionType type) |
460 | { |
461 | typedef QtPrivate::FunctionPointer<Func1> SignalType; |
462 | typedef QtPrivate::FunctionPointer<Func2> SlotType; |
463 | static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value, |
464 | "No Q_OBJECT in the class with the signal" ); |
465 | |
466 | //compilation error if the arguments does not match. |
467 | static_assert(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount), |
468 | "The slot requires more arguments than the signal provides." ); |
469 | static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value), |
470 | "Signal and slot arguments are not compatible." ); |
471 | static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value), |
472 | "Return type of the slot is not compatible with the return type of the signal." ); |
473 | |
474 | const int *types = nullptr; |
475 | if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection) |
476 | types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types(); |
477 | |
478 | return QObject::connectImpl(sender, reinterpret_cast<void **>(&signal), |
479 | receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot), |
480 | new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value, |
481 | typename SignalType::ReturnType>(slot), |
482 | type, types, &SignalType::Object::staticMetaObject); |
483 | } |
484 | |
485 | template <typename Func1, typename Func2> |
486 | bool QObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object* sender, Func1 signal, |
487 | const typename QtPrivate::FunctionPointer< Func2 >::Object* receiverPrivate, Func2 slot) |
488 | { |
489 | typedef QtPrivate::FunctionPointer<Func1> SignalType; |
490 | typedef QtPrivate::FunctionPointer<Func2> SlotType; |
491 | static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value, |
492 | "No Q_OBJECT in the class with the signal" ); |
493 | //compilation error if the arguments does not match. |
494 | static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value), |
495 | "Signal and slot arguments are not compatible." ); |
496 | return QObject::disconnectImpl(sender, reinterpret_cast<void **>(&signal), |
497 | receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot), |
498 | &SignalType::Object::staticMetaObject); |
499 | } |
500 | |
501 | Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE); |
502 | Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE); |
503 | |
504 | class QSemaphore; |
505 | class Q_CORE_EXPORT QAbstractMetaCallEvent : public QEvent |
506 | { |
507 | public: |
508 | QAbstractMetaCallEvent(const QObject *sender, int signalId, QSemaphore *semaphore = nullptr) |
509 | : QEvent(MetaCall), signalId_(signalId), sender_(sender) |
510 | #if QT_CONFIG(thread) |
511 | , semaphore_(semaphore) |
512 | #endif |
513 | { Q_UNUSED(semaphore); } |
514 | ~QAbstractMetaCallEvent(); |
515 | |
516 | virtual void placeMetaCall(QObject *object) = 0; |
517 | |
518 | inline const QObject *sender() const { return sender_; } |
519 | inline int signalId() const { return signalId_; } |
520 | |
521 | private: |
522 | int signalId_; |
523 | const QObject *sender_; |
524 | #if QT_CONFIG(thread) |
525 | QSemaphore *semaphore_; |
526 | #endif |
527 | }; |
528 | |
529 | class Q_CORE_EXPORT QMetaCallEvent : public QAbstractMetaCallEvent |
530 | { |
531 | public: |
532 | // blocking queued with semaphore - args always owned by caller |
533 | QMetaCallEvent(ushort method_offset, ushort method_relative, |
534 | QObjectPrivate::StaticMetaCallFunction callFunction, |
535 | const QObject *sender, int signalId, |
536 | void **args, QSemaphore *semaphore); |
537 | QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, |
538 | const QObject *sender, int signalId, |
539 | void **args, QSemaphore *semaphore); |
540 | |
541 | // queued - args allocated by event, copied by caller |
542 | QMetaCallEvent(ushort method_offset, ushort method_relative, |
543 | QObjectPrivate::StaticMetaCallFunction callFunction, |
544 | const QObject *sender, int signalId, |
545 | int nargs); |
546 | QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, |
547 | const QObject *sender, int signalId, |
548 | int nargs); |
549 | |
550 | ~QMetaCallEvent() override; |
551 | |
552 | inline int id() const { return d.method_offset_ + d.method_relative_; } |
553 | inline const void * const* args() const { return d.args_; } |
554 | inline void ** args() { return d.args_; } |
555 | inline const QMetaType *types() const { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); } |
556 | inline QMetaType *types() { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); } |
557 | |
558 | virtual void placeMetaCall(QObject *object) override; |
559 | |
560 | private: |
561 | inline void allocArgs(); |
562 | |
563 | struct Data { |
564 | QtPrivate::QSlotObjectBase *slotObj_; |
565 | void **args_; |
566 | QObjectPrivate::StaticMetaCallFunction callFunction_; |
567 | int nargs_; |
568 | ushort method_offset_; |
569 | ushort method_relative_; |
570 | } d; |
571 | // preallocate enough space for three arguments |
572 | alignas(void *) char prealloc_[3 * sizeof(void *) + 3 * sizeof(QMetaType)]; |
573 | }; |
574 | |
575 | class QBoolBlocker |
576 | { |
577 | Q_DISABLE_COPY_MOVE(QBoolBlocker) |
578 | public: |
579 | explicit inline QBoolBlocker(bool &b, bool value = true) : block(b), reset(b) { block = value; } |
580 | inline ~QBoolBlocker() { block = reset; } |
581 | |
582 | private: |
583 | bool █ |
584 | bool reset; |
585 | }; |
586 | |
587 | void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o); |
588 | |
589 | struct QAbstractDynamicMetaObject; |
590 | struct Q_CORE_EXPORT QDynamicMetaObjectData |
591 | { |
592 | virtual ~QDynamicMetaObjectData(); |
593 | virtual void objectDestroyed(QObject *) { delete this; } |
594 | |
595 | virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) = 0; |
596 | virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **) = 0; |
597 | }; |
598 | |
599 | struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject |
600 | { |
601 | ~QAbstractDynamicMetaObject(); |
602 | |
603 | QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) override { return this; } |
604 | virtual int createProperty(const char *, const char *) { return -1; } |
605 | int metaCall(QObject *, QMetaObject::Call c, int _id, void **a) override |
606 | { return metaCall(c, _id, a); } |
607 | virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; } // Compat overload |
608 | }; |
609 | |
610 | inline const QBindingStorage *qGetBindingStorage(const QObjectPrivate *o) |
611 | { |
612 | return &o->bindingStorage; |
613 | } |
614 | inline QBindingStorage *qGetBindingStorage(QObjectPrivate *o) |
615 | { |
616 | return &o->bindingStorage; |
617 | } |
618 | |
619 | |
620 | QT_END_NAMESPACE |
621 | |
622 | #endif // QOBJECT_P_H |
623 | |