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 | 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 | } |
399 | public: |
400 | 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 | |
421 | Q_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 | */ |
430 | inline 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 | |
445 | inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const |
446 | { |
447 | return declarativeData && QAbstractDeclarativeData::isSignalConnected |
448 | && QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index); |
449 | } |
450 | |
451 | inline void QObjectPrivate::connectNotify(const QMetaMethod &signal) |
452 | { |
453 | q_ptr->connectNotify(signal); |
454 | } |
455 | |
456 | inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal) |
457 | { |
458 | q_ptr->disconnectNotify(signal); |
459 | } |
460 | |
461 | namespace QtPrivate { |
462 | template<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 | } |
482 | public: |
483 | explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {} |
484 | }; |
485 | } //namespace QtPrivate |
486 | |
487 | template <typename Func1, typename Func2> |
488 | inline 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 | |
516 | template <typename Func1, typename Func2> |
517 | bool 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 | |
532 | Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE); |
533 | Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE); |
534 | |
535 | class QSemaphore; |
536 | class Q_CORE_EXPORT QAbstractMetaCallEvent : public QEvent |
537 | { |
538 | public: |
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 | |
552 | private: |
553 | int signalId_; |
554 | const QObject *sender_; |
555 | #if QT_CONFIG(thread) |
556 | QSemaphore *semaphore_; |
557 | #endif |
558 | }; |
559 | |
560 | class Q_CORE_EXPORT QMetaCallEvent : public QAbstractMetaCallEvent |
561 | { |
562 | public: |
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 | |
591 | private: |
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 | |
606 | class QBoolBlocker |
607 | { |
608 | Q_DISABLE_COPY_MOVE(QBoolBlocker) |
609 | public: |
610 | explicit inline QBoolBlocker(bool &b, bool value=true):block(b), reset(b){block = value;} |
611 | inline ~QBoolBlocker(){block = reset; } |
612 | private: |
613 | bool █ |
614 | bool reset; |
615 | }; |
616 | |
617 | void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o); |
618 | |
619 | struct QAbstractDynamicMetaObject; |
620 | struct 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 | |
629 | struct 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 | |
640 | QT_END_NAMESPACE |
641 | |
642 | #endif // QOBJECT_P_H |
643 | |