Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qobject.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5
6#include "qobject.h"
7#include "qobject_p.h"
8#include "qobject_p_p.h"
9#include "qmetaobject_p.h"
10
13#include "qcoreapplication.h"
14#include "qcoreapplication_p.h"
15#include "qcoreevent_p.h"
16#include "qloggingcategory.h"
17#include "qvariant.h"
18#include "qmetaobject.h"
19#if QT_CONFIG(regularexpression)
20# include <qregularexpression.h>
21#endif
22#include <qthread.h>
23#include <private/qthread_p.h>
24#include <qdebug.h>
25#include <qpair.h>
26#include <qvarlengtharray.h>
27#include <qscopeguard.h>
28#include <qset.h>
29#if QT_CONFIG(thread)
30#include <qsemaphore.h>
31#endif
32
33#include <private/qorderedmutexlocker_p.h>
34#include <private/qhooks_p.h>
35#include <qtcore_tracepoints_p.h>
36
37#include <new>
38#include <mutex>
39#include <memory>
40
41#include <ctype.h>
42#include <limits.h>
43
45
46Q_TRACE_POINT(qtcore, QObject_ctor, QObject *object);
47Q_TRACE_POINT(qtcore, QObject_dtor, QObject *object);
48Q_TRACE_POINT(qtcore, QMetaObject_activate_entry, QObject *sender, int signalIndex);
49Q_TRACE_POINT(qtcore, QMetaObject_activate_exit);
50Q_TRACE_POINT(qtcore, QMetaObject_activate_slot_entry, QObject *receiver, int slotIndex);
51Q_TRACE_POINT(qtcore, QMetaObject_activate_slot_exit);
52Q_TRACE_POINT(qtcore, QMetaObject_activate_slot_functor_entry, void *slotObject);
53Q_TRACE_POINT(qtcore, QMetaObject_activate_slot_functor_exit);
54Q_TRACE_POINT(qtcore, QMetaObject_activate_declarative_signal_entry, QObject *sender, int signalIndex);
55Q_TRACE_POINT(qtcore, QMetaObject_activate_declarative_signal_exit);
56
58
59Q_LOGGING_CATEGORY(lcConnectSlotsByName, "qt.core.qmetaobject.connectslotsbyname")
60Q_LOGGING_CATEGORY(lcConnect, "qt.core.qobject.connect")
61
63
65{
66 qt_signal_spy_callback_set.storeRelease(callback_set);
67}
68
70{
71}
72
74{
75}
76
78{
79 const auto parameterCount = method.parameterCount();
80 int *typeIds = new int[parameterCount + 1];
81 Q_CHECK_PTR(typeIds);
82 for (int i = 0; i < parameterCount; ++i) {
83 const QMetaType metaType = method.parameterMetaType(i);
84 if (metaType.flags() & QMetaType::IsPointer)
85 typeIds[i] = QMetaType::VoidStar;
86 else
87 typeIds[i] = metaType.id();
88 if (!typeIds[i] && method.parameterTypeName(i).endsWith('*'))
89 typeIds[i] = QMetaType::VoidStar;
90 if (!typeIds[i]) {
91 const QByteArray typeName = method.parameterTypeName(i);
92 qCWarning(lcConnect,
93 "QObject::connect: Cannot queue arguments of type '%s'\n"
94 "(Make sure '%s' is registered using qRegisterMetaType().)",
95 typeName.constData(), typeName.constData());
96 delete[] typeIds;
97 return nullptr;
98 }
99 }
100 typeIds[parameterCount] = 0;
101
102 return typeIds;
103}
104
105static int *queuedConnectionTypes(const QArgumentType *argumentTypes, int argc)
106{
107 auto types = std::make_unique<int[]>(argc + 1);
108 for (int i = 0; i < argc; ++i) {
109 const QArgumentType &type = argumentTypes[i];
110 if (type.type())
111 types[i] = type.type();
112 else if (type.name().endsWith('*'))
113 types[i] = QMetaType::VoidStar;
114 else
115 types[i] = QMetaType::fromName(type.name()).id();
116
117 if (!types[i]) {
118 qCWarning(lcConnect,
119 "QObject::connect: Cannot queue arguments of type '%s'\n"
120 "(Make sure '%s' is registered using qRegisterMetaType().)",
121 type.name().constData(), type.name().constData());
122 return nullptr;
123 }
124 }
125 types[argc] = 0;
126
127 return types.release();
128}
129
130Q_CONSTINIT static QBasicMutex _q_ObjectMutexPool[131];
131
136static inline QBasicMutex *signalSlotLock(const QObject *o)
137{
138 return &_q_ObjectMutexPool[uint(quintptr(o)) % sizeof(_q_ObjectMutexPool)/sizeof(QBasicMutex)];
139}
140
146
154
156{
158}
159
161 : threadData(nullptr), currentChildBeingDeleted(nullptr)
162{
164
165 // QObjectData initialization
166 q_ptr = nullptr;
167 parent = nullptr; // no parent yet. It is set by setParent()
168 isWidget = false; // assume not a widget object
169 blockSig = false; // not blocking signals
170 wasDeleted = false; // double-delete catcher
171 isDeletingChildren = false; // set by deleteChildren()
172 sendChildEvents = true; // if we should send ChildAdded and ChildRemoved events to parent
173 receiveChildEvents = true;
174 postedEvents = 0;
175 extraData = nullptr;
176 metaObject = nullptr;
177 isWindow = false;
178 deleteLaterCalled = false;
179 isQuickItem = false;
180 willBeWidget = false;
181 wasWidget = false;
182}
183
185{
186 auto thisThreadData = threadData.loadRelaxed();
188 if (Q_LIKELY(thisThreadData->thread.loadAcquire() == QThread::currentThread())) {
189 // unregister pending timers
190 if (thisThreadData->hasEventDispatcher())
191 thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimers(q_ptr);
192
193 // release the timer ids back to the pool
194 for (int i = 0; i < extraData->runningTimers.size(); ++i)
196 } else {
197 qWarning("QObject::~QObject: Timers cannot be stopped from another thread");
198 }
199 }
200
201 if (postedEvents)
203
204 thisThreadData->deref();
205
206 if (metaObject)
208
209 delete extraData;
210}
211
216static void computeOffsets(const QMetaObject *metaobject, int *signalOffset, int *methodOffset)
217{
218 *signalOffset = *methodOffset = 0;
219 const QMetaObject *m = metaobject->d.superdata;
220 while (m) {
222 *methodOffset += d->methodCount;
223 Q_ASSERT(d->revision >= 4);
224 *signalOffset += d->signalCount;
225 m = m->d.superdata;
226 }
227}
228
229// Used by QAccessibleWidget
230bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const
231{
232 Q_Q(const QObject);
233 int signal_index = signalIndex(signal);
234 ConnectionData *cd = connections.loadRelaxed();
235 if (signal_index < 0 || !cd)
236 return false;
238 if (signal_index < cd->signalVectorCount()) {
239 const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
240
241 while (c) {
242 if (c->receiver.loadRelaxed() == receiver)
243 return true;
244 c = c->nextConnectionList.loadRelaxed();
245 }
246 }
247 return false;
248}
249
250// Used by QAccessibleWidget
252{
253 QObjectList returnValue;
254 int signal_index = signalIndex(signal);
255 ConnectionData *cd = connections.loadRelaxed();
256 if (signal_index < 0 || !cd)
257 return returnValue;
258 if (signal_index < cd->signalVectorCount()) {
259 const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
260
261 while (c) {
262 QObject *r = c->receiver.loadRelaxed();
263 if (r)
264 returnValue << r;
265 c = c->nextConnectionList.loadRelaxed();
266 }
267 }
268 return returnValue;
269}
270
271// Used by QAccessibleWidget
273{
274 QObjectList returnValue;
275 ConnectionData *cd = connections.loadRelaxed();
276 if (cd) {
277 QMutexLocker locker(signalSlotLock(q_func()));
278 for (Connection *c = cd->senders; c; c = c->next)
279 returnValue << c->sender;
280 }
281 return returnValue;
282}
283
285{
286 if (connections.loadRelaxed())
287 return;
289 cd->ref.ref();
290 connections.storeRelaxed(cd);
291}
292
304{
305 Q_ASSERT(c->sender == q_ptr);
307 ConnectionData *cd = connections.loadRelaxed();
308 cd->resizeSignalVector(signal + 1);
309
310 ConnectionList &connectionList = cd->connectionsForSignal(signal);
311 if (connectionList.last.loadRelaxed()) {
312 Q_ASSERT(connectionList.last.loadRelaxed()->receiver.loadRelaxed());
313 connectionList.last.loadRelaxed()->nextConnectionList.storeRelaxed(c);
314 } else {
315 connectionList.first.storeRelaxed(c);
316 }
317 c->id = ++cd->currentConnectionId;
318 c->prevConnectionList = connectionList.last.loadRelaxed();
319 connectionList.last.storeRelaxed(c);
320
321 QObjectPrivate *rd = QObjectPrivate::get(c->receiver.loadRelaxed());
322 rd->ensureConnectionData();
323
324 c->prev = &(rd->connections.loadRelaxed()->senders);
325 c->next = *c->prev;
326 *c->prev = c;
327 if (c->next)
328 c->next->prev = &c->next;
329}
330
332{
333 Q_ASSERT(c->receiver.loadRelaxed());
334 ConnectionList &connections = signalVector.loadRelaxed()->at(c->signal_index);
335 c->receiver.storeRelaxed(nullptr);
336 QThreadData *td = c->receiverThreadData.loadRelaxed();
337 if (td)
338 td->deref();
339 c->receiverThreadData.storeRelaxed(nullptr);
340
341#ifndef QT_NO_DEBUG
342 bool found = false;
343 for (Connection *cc = connections.first.loadRelaxed(); cc; cc = cc->nextConnectionList.loadRelaxed()) {
344 if (cc == c) {
345 found = true;
346 break;
347 }
348 }
349 Q_ASSERT(found);
350#endif
351
352 // remove from the senders linked list
353 *c->prev = c->next;
354 if (c->next)
355 c->next->prev = c->prev;
356 c->prev = nullptr;
357
358 if (connections.first.loadRelaxed() == c)
359 connections.first.storeRelaxed(c->nextConnectionList.loadRelaxed());
360 if (connections.last.loadRelaxed() == c)
361 connections.last.storeRelaxed(c->prevConnectionList);
362 Q_ASSERT(signalVector.loadRelaxed()->at(c->signal_index).first.loadRelaxed() != c);
363 Q_ASSERT(signalVector.loadRelaxed()->at(c->signal_index).last.loadRelaxed() != c);
364
365 // keep c->nextConnectionList intact, as it might still get accessed by activate
366 Connection *n = c->nextConnectionList.loadRelaxed();
367 if (n)
368 n->prevConnectionList = c->prevConnectionList;
369 if (c->prevConnectionList)
370 c->prevConnectionList->nextConnectionList.storeRelaxed(n);
371 c->prevConnectionList = nullptr;
372
373 Q_ASSERT(c != static_cast<Connection *>(orphaned.load(std::memory_order_relaxed)));
374 // add c to orphanedConnections
375 TaggedSignalVector o = nullptr;
376 /* No ABA issue here: When adding a node, we only care about the list head, it doesn't
377 * matter if the tail changes.
378 */
379 o = orphaned.load(std::memory_order_acquire);
380 do {
381 c->nextInOrphanList = o;
382 } while (!orphaned.compare_exchange_strong(o, TaggedSignalVector(c), std::memory_order_release));
383
384#ifndef QT_NO_DEBUG
385 found = false;
386 for (Connection *cc = connections.first.loadRelaxed(); cc; cc = cc->nextConnectionList.loadRelaxed()) {
387 if (cc == c) {
388 found = true;
389 break;
390 }
391 }
392 Q_ASSERT(!found);
393#endif
394
395}
396
398{
399 QBasicMutex *senderMutex = signalSlotLock(sender);
400 TaggedSignalVector c = nullptr;
401 {
402 std::unique_lock<QBasicMutex> lock(*senderMutex, std::defer_lock_t{});
403 if (lockPolicy == NeedToLock)
404 lock.lock();
405 if (ref.loadAcquire() > 1)
406 return;
407
408 // Since ref == 1, no activate() is in process since we locked the mutex. That implies,
409 // that nothing can reference the orphaned connection objects anymore and they can
410 // be safely deleted
411 c = orphaned.exchange(nullptr, std::memory_order_relaxed);
412 }
413 if (c) {
414 // Deleting c might run arbitrary user code, so we must not hold the lock
415 if (lockPolicy == AlreadyLockedAndTemporarilyReleasingLock) {
416 senderMutex->unlock();
417 deleteOrphaned(c);
418 senderMutex->lock();
419 } else {
420 deleteOrphaned(c);
421 }
422 }
423}
424
426{
427 while (o) {
428 TaggedSignalVector next = nullptr;
429 if (SignalVector *v = static_cast<SignalVector *>(o)) {
430 next = v->nextInOrphanList;
431 free(v);
432 } else {
433 QObjectPrivate::Connection *c = static_cast<Connection *>(o);
434 next = c->nextInOrphanList;
435 Q_ASSERT(!c->receiver.loadRelaxed());
436 Q_ASSERT(!c->prev);
437 c->freeSlotObject();
438 c->deref();
439 }
440 o = next;
441 }
442}
443
450bool QObjectPrivate::isSignalConnected(uint signalIndex, bool checkDeclarative) const
451{
452 if (checkDeclarative && isDeclarativeSignalConnected(signalIndex))
453 return true;
454
455 ConnectionData *cd = connections.loadRelaxed();
456 if (!cd)
457 return false;
458 SignalVector *signalVector = cd->signalVector.loadRelaxed();
459 if (!signalVector)
460 return false;
461
462 if (signalVector->at(-1).first.loadRelaxed())
463 return true;
464
465 if (signalIndex < uint(cd->signalVectorCount())) {
466 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadRelaxed();
467 while (c) {
468 if (c->receiver.loadRelaxed())
469 return true;
470 c = c->nextConnectionList.loadRelaxed();
471 }
472 }
473 return false;
474}
475
477{
478 ConnectionData *cd = connections.loadRelaxed();
479 if (!cd)
480 return false;
481 SignalVector *signalVector = cd->signalVector.loadRelaxed();
482 if (!signalVector)
483 return false;
484
485 if (signalVector->at(-1).first.loadAcquire())
486 return true;
487
488 if (signalIndex < uint(cd->signalVectorCount())) {
489 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadAcquire();
490 return c != nullptr;
491 }
492 return false;
493}
494
496{
497 bindingStorage.reinitAfterThreadMove();
498 for (int i = 0; i < children.size(); ++i)
499 children[i]->d_func()->reinitBindingStorageAfterThreadMove();
500}
501
506{
507#if QT_CONFIG(thread)
508 if (semaphore_)
509 semaphore_->release();
510#endif
511}
512
516inline void QMetaCallEvent::allocArgs()
517{
518 if (!d.nargs_)
519 return;
520
521 constexpr size_t each = sizeof(void*) + sizeof(QMetaType);
522 void *const memory = d.nargs_ * each > sizeof(prealloc_) ?
523 calloc(d.nargs_, each) : prealloc_;
524
526 d.args_ = static_cast<void **>(memory);
527}
528
535QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative,
537 const QObject *sender, int signalId,
538 void **args, QSemaphore *semaphore)
539 : QAbstractMetaCallEvent(sender, signalId, semaphore),
540 d({nullptr, args, callFunction, 0, method_offset, method_relative}),
541 prealloc_()
542{
543}
544
552 const QObject *sender, int signalId,
553 void **args, QSemaphore *semaphore)
554 : QAbstractMetaCallEvent(sender, signalId, semaphore),
555 d({slotO, args, nullptr, 0, 0, ushort(-1)}),
556 prealloc_()
557{
558 if (d.slotObj_)
559 d.slotObj_->ref();
560}
561
568QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative,
570 const QObject *sender, int signalId,
571 int nargs)
572 : QAbstractMetaCallEvent(sender, signalId),
573 d({nullptr, nullptr, callFunction, nargs, method_offset, method_relative}),
574 prealloc_()
575{
576 allocArgs();
577}
578
586 const QObject *sender, int signalId,
587 int nargs)
588 : QAbstractMetaCallEvent(sender, signalId),
589 d({slotO, nullptr, nullptr, nargs, 0, ushort(-1)}),
590 prealloc_()
591{
592 if (d.slotObj_)
593 d.slotObj_->ref();
594 allocArgs();
595}
596
601{
602 if (d.nargs_) {
603 QMetaType *t = types();
604 for (int i = 0; i < d.nargs_; ++i) {
605 if (t[i].isValid() && d.args_[i])
606 t[i].destroy(d.args_[i]);
607 }
608 if (reinterpret_cast<void *>(d.args_) != reinterpret_cast<void *>(prealloc_))
609 free(d.args_);
610 }
611 if (d.slotObj_)
612 d.slotObj_->destroyIfLastRef();
613}
614
619{
620 if (d.slotObj_) {
621 d.slotObj_->call(object, d.args_);
622 } else if (d.callFunction_ && d.method_offset_ <= object->metaObject()->methodOffset()) {
623 d.callFunction_(object, QMetaObject::InvokeMetaMethod, d.method_relative_, d.args_);
624 } else {
626 d.method_offset_ + d.method_relative_, d.args_);
627 }
628}
629
870/*****************************************************************************
871 QObject member functions
872 *****************************************************************************/
873
874// check the constructor's parent thread argument
876 QThreadData *parentThreadData,
877 QThreadData *currentThreadData)
878{
879 if (parent && parentThreadData != currentThreadData) {
880 QThread *parentThread = parentThreadData->thread.loadAcquire();
881 QThread *currentThread = currentThreadData->thread.loadAcquire();
882 qWarning("QObject: Cannot create children for a parent that is in a different thread.\n"
883 "(Parent is %s(%p), parent's thread is %s(%p), current thread is %s(%p)",
884 parent->metaObject()->className(),
885 parent,
886 parentThread ? parentThread->metaObject()->className() : "QThread",
887 parentThread,
888 currentThread ? currentThread->metaObject()->className() : "QThread",
889 currentThread);
890 return false;
891 }
892 return true;
893}
894
912{
913}
914
919 : d_ptr(&dd)
920{
921 Q_ASSERT_X(this != parent, Q_FUNC_INFO, "Cannot parent a QObject to itself");
922
923 Q_D(QObject);
924 d_ptr->q_ptr = this;
925 auto threadData = (parent && !parent->thread()) ? parent->d_func()->threadData.loadRelaxed() : QThreadData::current();
926 threadData->ref();
927 d->threadData.storeRelaxed(threadData);
928 if (parent) {
929 QT_TRY {
930 if (!check_parent_thread(parent, parent ? parent->d_func()->threadData.loadRelaxed() : nullptr, threadData))
931 parent = nullptr;
932 if (d->willBeWidget) {
933 if (parent) {
934 d->parent = parent;
935 d->parent->d_func()->children.append(this);
936 }
937 // no events sent here, this is done at the end of the QWidget constructor
938 } else {
940 }
941 } QT_CATCH(...) {
942 threadData->deref();
944 }
945 }
948 Q_TRACE(QObject_ctor, this);
949}
950
952{
953 bindingStorage.clear();
954}
955
981{
982 Q_D(QObject);
983 d->wasDeleted = true;
984 d->blockSig = 0; // unblock signals so we always emit destroyed()
985
986 if (!d->bindingStorage.isValid()) {
987 // this might be the case after an incomplete thread-move
988 // remove this object from the pending list in that case
989 if (QThread *ownThread = thread()) {
990 auto *privThread = static_cast<QThreadPrivate *>(
991 QObjectPrivate::get(ownThread));
993 }
994 }
995
996 // If we reached this point, we need to clear the binding data
997 // as the corresponding properties are no longer useful
998 d->clearBindingStorage();
999
1000 QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.loadRelaxed();
1001 if (sharedRefcount) {
1002 if (sharedRefcount->strongref.loadRelaxed() > 0) {
1003 qWarning("QObject: shared QObject was deleted directly. The program is malformed and may crash.");
1004 // but continue deleting, it's too late to stop anyway
1005 }
1006
1007 // indicate to all QWeakPointers that this QObject has now been deleted
1008 sharedRefcount->strongref.storeRelaxed(0);
1009 if (!sharedRefcount->weakref.deref())
1010 delete sharedRefcount;
1011 }
1012
1013 if (!d->wasWidget && d->isSignalConnected(0)) {
1014 emit destroyed(this);
1015 }
1016
1017 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::destroyed)
1018 QAbstractDeclarativeData::destroyed(d->declarativeData, this);
1019
1020 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
1021 if (cd) {
1022 if (cd->currentSender) {
1024 cd->currentSender = nullptr;
1025 }
1026
1027 QBasicMutex *signalSlotMutex = signalSlotLock(this);
1028 QMutexLocker locker(signalSlotMutex);
1029
1030 // disconnect all receivers
1031 int receiverCount = cd->signalVectorCount();
1032 for (int signal = -1; signal < receiverCount; ++signal) {
1034
1035 while (QObjectPrivate::Connection *c = connectionList.first.loadRelaxed()) {
1036 Q_ASSERT(c->receiver.loadAcquire());
1037
1038 QBasicMutex *m = signalSlotLock(c->receiver.loadRelaxed());
1039 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1040 if (c == connectionList.first.loadAcquire() && c->receiver.loadAcquire()) {
1041 cd->removeConnection(c);
1042 Q_ASSERT(connectionList.first.loadRelaxed() != c);
1043 }
1044 if (needToUnlock)
1045 m->unlock();
1046 }
1047 }
1048
1049 /* Disconnect all senders:
1050 */
1051 while (QObjectPrivate::Connection *node = cd->senders) {
1052 Q_ASSERT(node->receiver.loadAcquire());
1053 QObject *sender = node->sender;
1054 // Send disconnectNotify before removing the connection from sender's connection list.
1055 // This ensures any eventual destructor of sender will block on getting receiver's lock
1056 // and not finish until we release it.
1057 sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), node->signal_index));
1059 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1060 //the node has maybe been removed while the mutex was unlocked in relock?
1061 if (node != cd->senders) {
1062 // We hold the wrong mutex
1063 Q_ASSERT(needToUnlock);
1064 m->unlock();
1065 continue;
1066 }
1067
1068 QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections.loadRelaxed();
1069 Q_ASSERT(senderData);
1070
1071 QtPrivate::QSlotObjectBase *slotObj = nullptr;
1072 if (node->isSlotObject) {
1073 slotObj = node->slotObj;
1074 node->isSlotObject = false;
1075 }
1076
1077 senderData->removeConnection(node);
1078 /*
1079 When we unlock, another thread has the chance to delete/modify sender data.
1080 Thus we need to call cleanOrphanedConnections before unlocking. We use the
1081 variant of the function which assumes that the lock is already held to avoid
1082 a deadlock.
1083 We need to hold m, the sender lock. Considering that we might execute arbitrary user
1084 code, we should already release the signalSlotMutex here – unless they are the same.
1085 */
1086 const bool locksAreTheSame = signalSlotMutex == m;
1087 if (!locksAreTheSame)
1088 locker.unlock();
1089 senderData->cleanOrphanedConnections(
1090 sender,
1092 );
1093 if (needToUnlock)
1094 m->unlock();
1095
1096 if (locksAreTheSame) // otherwise already unlocked
1097 locker.unlock();
1098 if (slotObj)
1099 slotObj->destroyIfLastRef();
1100 locker.relock();
1101 }
1102
1103 // invalidate all connections on the object and make sure
1104 // activate() will skip them
1106 }
1107 if (cd && !cd->ref.deref())
1108 delete cd;
1109 d->connections.storeRelaxed(nullptr);
1110
1111 if (!d->children.isEmpty())
1112 d->deleteChildren();
1113
1116
1117 Q_TRACE(QObject_dtor, this);
1118
1119 if (d->parent) // remove it from parent object
1120 d->setParent_helper(nullptr);
1121}
1122
1124{
1125 if (ownArgumentTypes) {
1126 const int *v = argumentTypes.loadRelaxed();
1127 if (v != &DIRECT_CONNECTION_ONLY)
1128 delete[] v;
1129 }
1130 if (isSlotObject)
1132}
1133
1134
1250{
1251 Q_D(const QObject);
1252#if QT_CONFIG(thread)
1253 if (QThread::currentThreadId() != d->threadData.loadRelaxed()->threadId.loadRelaxed()) // Unsafe code path
1254 return d->extraData ? d->extraData->objectName.valueBypassingBindings() : QString();
1255#endif
1256 if (!d->extraData && QtPrivate::isAnyBindingEvaluating()) {
1257 QObjectPrivate *dd = const_cast<QObjectPrivate *>(d);
1258 // extraData is mutable, so this should be safe
1260 }
1261 return d->extraData ? d->extraData->objectName : QString();
1262}
1263
1268void QObject::doSetObjectName(const QString &name)
1269{
1270 Q_D(QObject);
1271
1272 d->ensureExtraData();
1273
1274 d->extraData->objectName.removeBindingUnlessInWrapper();
1275
1276 if (d->extraData->objectName != name) {
1277 d->extraData->objectName.setValueBypassingBindings(name);
1278 d->extraData->objectName.notify(); // also emits a signal
1279 }
1280}
1281
1287{
1288 Q_D(QObject);
1289
1290 d->ensureExtraData();
1291
1292 d->extraData->objectName.removeBindingUnlessInWrapper();
1293
1294 if (d->extraData->objectName != name) {
1295 d->extraData->objectName.setValueBypassingBindings(name.toString());
1296 d->extraData->objectName.notify(); // also emits a signal
1297 }
1298}
1299
1301{
1302 Q_D(QObject);
1303
1304 d->ensureExtraData();
1305
1306 return QBindable<QString>(&d->extraData->objectName);
1307}
1308
1364{
1365 switch (e->type()) {
1366 case QEvent::Timer:
1367 timerEvent((QTimerEvent *)e);
1368 break;
1369
1370 case QEvent::ChildAdded:
1373 childEvent((QChildEvent *)e);
1374 break;
1375
1378 break;
1379
1380 case QEvent::MetaCall:
1381 {
1382 QAbstractMetaCallEvent *mce = static_cast<QAbstractMetaCallEvent*>(e);
1383
1384 if (!d_func()->connections.loadRelaxed()) {
1385 QMutexLocker locker(signalSlotLock(this));
1386 d_func()->ensureConnectionData();
1387 }
1388 QObjectPrivate::Sender sender(this, const_cast<QObject*>(mce->sender()), mce->signalId());
1389
1390 mce->placeMetaCall(this);
1391 break;
1392 }
1393
1394 case QEvent::ThreadChange: {
1395 Q_D(QObject);
1396 QThreadData *threadData = d->threadData.loadRelaxed();
1397 QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
1398 if (eventDispatcher) {
1399 QList<QAbstractEventDispatcher::TimerInfo> timers = eventDispatcher->registeredTimers(this);
1400 if (!timers.isEmpty()) {
1401 // do not to release our timer ids back to the pool (since the timer ids are moving to a new thread).
1402 eventDispatcher->unregisterTimers(this);
1403 QMetaObject::invokeMethod(this, "_q_reregisterTimers", Qt::QueuedConnection,
1405 }
1406 }
1407 break;
1408 }
1409
1410 default:
1411 if (e->type() >= QEvent::User) {
1412 customEvent(e);
1413 break;
1414 }
1415 return false;
1416 }
1417 return true;
1418}
1419
1434{
1435}
1436
1437
1472{
1473}
1474
1475
1485void QObject::customEvent(QEvent * /* event */)
1486{
1487}
1488
1489
1490
1518bool QObject::eventFilter(QObject * /* watched */, QEvent * /* event */)
1519{
1520 return false;
1521}
1522
1548bool QObject::blockSignals(bool block) noexcept
1549{
1550 Q_D(QObject);
1551 bool previous = d->blockSig;
1552 d->blockSig = block;
1553 return previous;
1554}
1555
1562{
1563 return d_func()->threadData.loadRelaxed()->thread.loadAcquire();
1564}
1565
1607{
1608 Q_D(QObject);
1609
1610 if (d->threadData.loadRelaxed()->thread.loadAcquire() == targetThread) {
1611 // object is already in this thread
1612 return;
1613 }
1614
1615 if (d->parent != nullptr) {
1616 qWarning("QObject::moveToThread: Cannot move objects with a parent");
1617 return;
1618 }
1619 if (d->isWidget) {
1620 qWarning("QObject::moveToThread: Widgets cannot be moved to a new thread");
1621 return;
1622 }
1623 if (!d->bindingStorage.isEmpty()) {
1624 qWarning("QObject::moveToThread: Can not move objects that contain bindings or are used in bindings to a new thread.");
1625 return;
1626 }
1627
1628 QThreadData *currentData = QThreadData::current();
1629 QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : nullptr;
1630 QThreadData *thisThreadData = d->threadData.loadAcquire();
1631 if (!thisThreadData->thread.loadRelaxed() && currentData == targetData) {
1632 // one exception to the rule: we allow moving objects with no thread affinity to the current thread
1633 currentData = thisThreadData;
1634 } else if (thisThreadData != currentData) {
1635 qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
1636 "Cannot move to target thread (%p)\n",
1637 currentData->thread.loadRelaxed(), thisThreadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() : nullptr);
1638
1639#ifdef Q_OS_DARWIN
1640 qWarning("You might be loading two sets of Qt binaries into the same process. "
1641 "Check that all plugins are compiled against the right Qt binaries. Export "
1642 "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.");
1643#endif
1644
1645 return;
1646 }
1647
1648 // prepare to move
1649 d->moveToThread_helper();
1650
1651 if (!targetData)
1652 targetData = new QThreadData(0);
1653
1654 // make sure nobody adds/removes connections to this object while we're moving it
1656
1657 QOrderedMutexLocker locker(&currentData->postEventList.mutex,
1658 &targetData->postEventList.mutex);
1659
1660 // keep currentData alive (since we've got it locked)
1661 currentData->ref();
1662
1663 // move the object
1664 auto threadPrivate = targetThread
1665 ? static_cast<QThreadPrivate *>(QThreadPrivate::get(targetThread))
1666 : nullptr;
1667 QBindingStatus *bindingStatus = threadPrivate
1668 ? threadPrivate->bindingStatus()
1669 : nullptr;
1670 if (threadPrivate && !bindingStatus) {
1671 bindingStatus = threadPrivate->addObjectWithPendingBindingStatusChange(this);
1672 }
1673 d_func()->setThreadData_helper(currentData, targetData, bindingStatus);
1674
1675 locker.unlock();
1676
1677 // now currentData can commit suicide if it wants to
1678 currentData->deref();
1679}
1680
1682{
1683 Q_Q(QObject);
1686 bindingStorage.clear();
1687 for (int i = 0; i < children.size(); ++i) {
1689 child->d_func()->moveToThread_helper();
1690 }
1691}
1692
1694{
1695 Q_Q(QObject);
1696
1697 if (status) {
1698 // the new thread is already running
1699 this->bindingStorage.bindingStatus = status;
1700 }
1701
1702 // move posted events
1703 int eventsMoved = 0;
1704 for (int i = 0; i < currentData->postEventList.size(); ++i) {
1705 const QPostEvent &pe = currentData->postEventList.at(i);
1706 if (!pe.event)
1707 continue;
1708 if (pe.receiver == q) {
1709 // move this post event to the targetList
1710 targetData->postEventList.addEvent(pe);
1711 const_cast<QPostEvent &>(pe).event = nullptr;
1712 ++eventsMoved;
1713 }
1714 }
1715 if (eventsMoved > 0 && targetData->hasEventDispatcher()) {
1716 targetData->canWait = false;
1717 targetData->eventDispatcher.loadRelaxed()->wakeUp();
1718 }
1719
1720 // the current emitting thread shouldn't restore currentSender after calling moveToThread()
1721 ConnectionData *cd = connections.loadRelaxed();
1722 if (cd) {
1723 if (cd->currentSender) {
1725 cd->currentSender = nullptr;
1726 }
1727
1728 // adjust the receiverThreadId values in the Connections
1729 if (cd) {
1730 auto *c = cd->senders;
1731 while (c) {
1732 QObject *r = c->receiver.loadRelaxed();
1733 if (r) {
1734 Q_ASSERT(r == q);
1735 targetData->ref();
1736 QThreadData *old = c->receiverThreadData.loadRelaxed();
1737 if (old)
1738 old->deref();
1739 c->receiverThreadData.storeRelaxed(targetData);
1740 }
1741 c = c->next;
1742 }
1743 }
1744
1745 }
1746
1747 // set new thread data
1748 targetData->ref();
1749 threadData.loadRelaxed()->deref();
1750
1751 // synchronizes with loadAcquire e.g. in QCoreApplication::postEvent
1752 threadData.storeRelease(targetData);
1753
1754 for (int i = 0; i < children.size(); ++i) {
1756 child->d_func()->setThreadData_helper(currentData, targetData, status);
1757 }
1758}
1759
1761{
1762 Q_Q(QObject);
1764 QAbstractEventDispatcher *eventDispatcher = threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
1765 for (int i = 0; i < timerList->size(); ++i) {
1766 const QAbstractEventDispatcher::TimerInfo &ti = timerList->at(i);
1767 eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType, q);
1768 }
1769 delete timerList;
1770}
1771
1772
1773//
1774// The timer flag hasTimer is set when startTimer is called.
1775// It is not reset when killing the timer because more than
1776// one timer might be active.
1777//
1778
1792int QObject::startTimer(int interval, Qt::TimerType timerType)
1793{
1794 return startTimer(std::chrono::milliseconds{interval}, timerType);
1795}
1796
1835int QObject::startTimer(std::chrono::milliseconds interval, Qt::TimerType timerType)
1836{
1837 Q_D(QObject);
1838
1839 using namespace std::chrono_literals;
1840
1841 if (Q_UNLIKELY(interval < 0ms)) {
1842 qWarning("QObject::startTimer: Timers cannot have negative intervals");
1843 return 0;
1844 }
1845
1846 auto thisThreadData = d->threadData.loadRelaxed();
1847 if (Q_UNLIKELY(!thisThreadData->hasEventDispatcher())) {
1848 qWarning("QObject::startTimer: Timers can only be used with threads started with QThread");
1849 return 0;
1850 }
1851 if (Q_UNLIKELY(thread() != QThread::currentThread())) {
1852 qWarning("QObject::startTimer: Timers cannot be started from another thread");
1853 return 0;
1854 }
1855
1856 auto dispatcher = thisThreadData->eventDispatcher.loadRelaxed();
1857 int timerId = dispatcher->registerTimer(interval.count(), timerType, this);
1858 d->ensureExtraData();
1859 d->extraData->runningTimers.append(timerId);
1860 return timerId;
1861}
1862
1873{
1874 Q_D(QObject);
1875 if (Q_UNLIKELY(thread() != QThread::currentThread())) {
1876 qWarning("QObject::killTimer: Timers cannot be stopped from another thread");
1877 return;
1878 }
1879 if (id) {
1880 int at = d->extraData ? d->extraData->runningTimers.indexOf(id) : -1;
1881 if (at == -1) {
1882 // timer isn't owned by this object
1883 qWarning("QObject::killTimer(): Error: timer id %d is not valid for object %p (%s, %ls), timer has not been killed",
1884 id,
1885 this,
1886 metaObject()->className(),
1887 qUtf16Printable(objectName()));
1888 return;
1889 }
1890
1891 auto thisThreadData = d->threadData.loadRelaxed();
1892 if (thisThreadData->hasEventDispatcher())
1893 thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimer(id);
1894
1895 d->extraData->runningTimers.remove(at);
1897 }
1898}
1899
1900
2056 Qt::FindChildOptions options)
2057{
2059 Q_ASSERT(list);
2060 Q_ASSERT(!name.isNull());
2061 for (QObject *obj : parent->children()) {
2062 if (mo.cast(obj) && obj->objectName() == name)
2063 list->append(obj);
2064 if (options & Qt::FindChildrenRecursively)
2066 }
2067}
2068
2073 const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
2074{
2075 if (name.isNull())
2076 return qt_qFindChildren_helper(parent, mo, list, options);
2077 else
2078 return qt_qFindChildren_with_name(parent, name, mo, list, options);
2079}
2080
2085 QList<void*> *list, Qt::FindChildOptions options)
2086{
2088 Q_ASSERT(list);
2089 for (QObject *obj : parent->children()) {
2090 if (mo.cast(obj))
2091 list->append(obj);
2092 if (options & Qt::FindChildrenRecursively)
2093 qt_qFindChildren_helper(obj, mo, list, options);
2094 }
2095}
2096
2097#if QT_CONFIG(regularexpression)
2102 const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
2103{
2105 Q_ASSERT(list);
2106 for (QObject *obj : parent->children()) {
2107 if (mo.cast(obj)) {
2108 QRegularExpressionMatch m = re.match(obj->objectName());
2109 if (m.hasMatch())
2110 list->append(obj);
2111 }
2112 if (options & Qt::FindChildrenRecursively)
2113 qt_qFindChildren_helper(obj, re, mo, list, options);
2114 }
2115}
2116#endif // QT_CONFIG(regularexpression)
2117
2121QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options)
2122{
2124 for (QObject *obj : parent->children()) {
2125 if (mo.cast(obj) && (name.isNull() || obj->objectName() == name))
2126 return obj;
2127 }
2128 if (options & Qt::FindChildrenRecursively) {
2129 for (QObject *child : parent->children()) {
2130 if (QObject *obj = qt_qFindChild_helper(child, name, mo, options))
2131 return obj;
2132 }
2133 }
2134 return nullptr;
2135}
2136
2143{
2144 Q_D(QObject);
2145 Q_ASSERT(!d->isWidget);
2146 d->setParent_helper(parent);
2147}
2148
2150{
2151 Q_ASSERT_X(!isDeletingChildren, "QObjectPrivate::deleteChildren()", "isDeletingChildren already set, did this function recurse?");
2152 isDeletingChildren = true;
2153 // delete children objects
2154 // don't use qDeleteAll as the destructor of the child might
2155 // delete siblings
2156 for (int i = 0; i < children.size(); ++i) {
2158 children[i] = nullptr;
2160 }
2161 children.clear();
2162 currentChildBeingDeleted = nullptr;
2163 isDeletingChildren = false;
2164}
2165
2167{
2168 Q_Q(QObject);
2169 Q_ASSERT_X(q != o, Q_FUNC_INFO, "Cannot parent a QObject to itself");
2170#ifdef QT_DEBUG
2171 const auto checkForParentChildLoops = qScopeGuard([&](){
2172 int depth = 0;
2173 auto p = parent;
2174 while (p) {
2175 if (++depth == CheckForParentChildLoopsWarnDepth) {
2176 qWarning("QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
2177 "this is undefined behavior",
2178 q, q->metaObject()->className(), qPrintable(q->objectName()));
2179 }
2180 p = p->parent();
2181 }
2182 });
2183#endif
2184
2185 if (o == parent)
2186 return;
2187
2188 if (parent) {
2189 QObjectPrivate *parentD = parent->d_func();
2190 if (parentD->isDeletingChildren && wasDeleted
2191 && parentD->currentChildBeingDeleted == q) {
2192 // don't do anything since QObjectPrivate::deleteChildren() already
2193 // cleared our entry in parentD->children.
2194 } else {
2195 const int index = parentD->children.indexOf(q);
2196 if (index < 0) {
2197 // we're probably recursing into setParent() from a ChildRemoved event, don't do anything
2198 } else if (parentD->isDeletingChildren) {
2199 parentD->children[index] = nullptr;
2200 } else {
2201 parentD->children.removeAt(index);
2202 if (sendChildEvents && parentD->receiveChildEvents) {
2205 }
2206 }
2207 }
2208 }
2209 parent = o;
2210 if (parent) {
2211 // object hierarchies are constrained to a single thread
2212 if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) {
2213 qWarning("QObject::setParent: Cannot set parent, new parent is in a different thread");
2214 parent = nullptr;
2215 return;
2216 }
2217 parent->d_func()->children.append(q);
2218 if (sendChildEvents && parent->d_func()->receiveChildEvents) {
2219 if (!isWidget) {
2222 }
2223 }
2224 }
2225}
2226
2270{
2271 Q_D(QObject);
2272 if (!obj)
2273 return;
2274 if (d->threadData.loadRelaxed() != obj->d_func()->threadData.loadRelaxed()) {
2275 qWarning("QObject::installEventFilter(): Cannot filter events for objects in a different thread.");
2276 return;
2277 }
2278
2279 d->ensureExtraData();
2280
2281 // clean up unused items in the list
2282 d->extraData->eventFilters.removeAll((QObject *)nullptr);
2283 d->extraData->eventFilters.removeAll(obj);
2284 d->extraData->eventFilters.prepend(obj);
2285}
2286
2301{
2302 Q_D(QObject);
2303 if (d->extraData) {
2304 for (int i = 0; i < d->extraData->eventFilters.size(); ++i) {
2305 if (d->extraData->eventFilters.at(i) == obj)
2306 d->extraData->eventFilters[i] = nullptr;
2307 }
2308 }
2309}
2310
2353{
2354#ifdef QT_DEBUG
2355 if (qApp == this)
2356 qWarning("You are deferring the delete of QCoreApplication, this may not work as expected.");
2357#endif
2359}
2360
2397/*****************************************************************************
2398 Signals and slots
2399 *****************************************************************************/
2400
2401namespace {
2402// This class provides (per-thread) storage for qFlagLocation()
2403class FlaggedDebugSignatures
2404{
2405 uint idx = 0;
2406 std::array<const char *, 2> locations = {}; // one for the SIGNAL, one for the SLOT
2407
2408public:
2409 void store(const char* method) noexcept
2410 { locations[idx++ % locations.size()] = method; }
2411
2412 bool contains(const char *method) const noexcept
2413 { return std::find(locations.begin(), locations.end(), method) != locations.end(); }
2414};
2415
2416Q_CONSTINIT static thread_local FlaggedDebugSignatures flaggedSignatures = {};
2417} // unnamed namespace
2418
2419const char *qFlagLocation(const char *method)
2420{
2421 flaggedSignatures.store(method);
2422 return method;
2423}
2424
2425static int extract_code(const char *member)
2426{
2427 // extract code, ensure QMETHOD_CODE <= code <= QSIGNAL_CODE
2428 return (((int)(*member) - '0') & 0x3);
2429}
2430
2431static const char *extract_location(const char *member)
2432{
2433 if (flaggedSignatures.contains(member)) {
2434 // signature includes location information after the first null-terminator
2435 const char *location = member + qstrlen(member) + 1;
2436 if (*location != '\0')
2437 return location;
2438 }
2439 return nullptr;
2440}
2441
2442static bool check_signal_macro(const QObject *sender, const char *signal,
2443 const char *func, const char *op)
2444{
2445 int sigcode = extract_code(signal);
2446 if (sigcode != QSIGNAL_CODE) {
2447 if (sigcode == QSLOT_CODE)
2448 qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s", func, op,
2449 sender->metaObject()->className(), signal + 1);
2450 else
2451 qCWarning(lcConnect, "QObject::%s: Use the SIGNAL macro to %s %s::%s", func, op,
2452 sender->metaObject()->className(), signal);
2453 return false;
2454 }
2455 return true;
2456}
2457
2458static bool check_method_code(int code, const QObject *object, const char *method, const char *func)
2459{
2460 if (code != QSLOT_CODE && code != QSIGNAL_CODE) {
2461 qCWarning(lcConnect,
2462 "QObject::%s: Use the SLOT or SIGNAL macro to "
2463 "%s %s::%s",
2464 func, func, object->metaObject()->className(), method);
2465 return false;
2466 }
2467 return true;
2468}
2469
2471static void err_method_notfound(const QObject *object,
2472 const char *method, const char *func)
2473{
2474 const char *type = "method";
2475 switch (extract_code(method)) {
2476 case QSLOT_CODE: type = "slot"; break;
2477 case QSIGNAL_CODE: type = "signal"; break;
2478 }
2479 const char *loc = extract_location(method);
2480 if (strchr(method, ')') == nullptr) // common typing mistake
2481 qCWarning(lcConnect, "QObject::%s: Parentheses expected, %s %s::%s%s%s", func, type,
2482 object->metaObject()->className(), method + 1, loc ? " in " : "", loc ? loc : "");
2483 else
2484 qCWarning(lcConnect, "QObject::%s: No such %s %s::%s%s%s", func, type,
2485 object->metaObject()->className(), method + 1, loc ? " in " : "", loc ? loc : "");
2486}
2487
2489static void err_info_about_objects(const char *func, const QObject *sender, const QObject *receiver)
2490{
2491 QString a = sender ? sender->objectName() : QString();
2492 QString b = receiver ? receiver->objectName() : QString();
2493 if (!a.isEmpty())
2494 qCWarning(lcConnect, "QObject::%s: (sender name: '%s')", func, a.toLocal8Bit().data());
2495 if (!b.isEmpty())
2496 qCWarning(lcConnect, "QObject::%s: (receiver name: '%s')", func, b.toLocal8Bit().data());
2497}
2498
2522{
2523 Q_D(const QObject);
2524
2525 QMutexLocker locker(signalSlotLock(this));
2526 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2527 if (!cd || !cd->currentSender)
2528 return nullptr;
2529
2530 for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2531 if (c->sender == cd->currentSender->sender)
2532 return cd->currentSender->sender;
2533 }
2534
2535 return nullptr;
2536}
2537
2564{
2565 Q_D(const QObject);
2566
2567 QMutexLocker locker(signalSlotLock(this));
2568 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2569 if (!cd || !cd->currentSender)
2570 return -1;
2571
2572 for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2573 if (c->sender == cd->currentSender->sender) {
2574 // Convert from signal range to method range
2575 return QMetaObjectPrivate::signal(c->sender->metaObject(), cd->currentSender->signal).methodIndex();
2576 }
2577 }
2578
2579 return -1;
2580}
2581
2603int QObject::receivers(const char *signal) const
2604{
2605 Q_D(const QObject);
2606 int receivers = 0;
2607 if (signal) {
2609 signal = signal_name;
2610#ifndef QT_NO_DEBUG
2611 if (!check_signal_macro(this, signal, "receivers", "bind"))
2612 return 0;
2613#endif
2614 signal++; // skip code
2615 int signal_index = d->signalIndex(signal);
2616 if (signal_index < 0) {
2617#ifndef QT_NO_DEBUG
2618 err_method_notfound(this, signal - 1, "receivers");
2619#endif
2620 return 0;
2621 }
2622
2623 if (!d->isSignalConnected(signal_index))
2624 return receivers;
2625
2626 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::receivers) {
2627 receivers += QAbstractDeclarativeData::receivers(d->declarativeData, this,
2628 signal_index);
2629 }
2630
2631 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2632 QMutexLocker locker(signalSlotLock(this));
2633 if (cd && signal_index < cd->signalVectorCount()) {
2634 const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
2635 while (c) {
2636 receivers += c->receiver.loadRelaxed() ? 1 : 0;
2637 c = c->nextConnectionList.loadRelaxed();
2638 }
2639 }
2640 }
2641 return receivers;
2642}
2643
2665{
2666 Q_D(const QObject);
2667 if (!signal.mobj)
2668 return false;
2669
2670 Q_ASSERT_X(signal.mobj->cast(this) && signal.methodType() == QMetaMethod::Signal,
2671 "QObject::isSignalConnected" , "the parameter must be a signal member of the object");
2672 uint signalIndex = signal.relativeMethodIndex();
2673
2674 if (signal.data.flags() & MethodCloned)
2676
2678
2679 QMutexLocker locker(signalSlotLock(this));
2680 return d->isSignalConnected(signalIndex, true);
2681}
2682
2707 const QMetaMethod &member,
2708 int *signalIndex, int *methodIndex)
2709{
2710 *signalIndex = -1;
2711 *methodIndex = -1;
2712 if (!obj || !member.mobj)
2713 return;
2714 const QMetaObject *m = obj->metaObject();
2715 // Check that member is member of obj class
2716 while (m != nullptr && m != member.mobj)
2717 m = m->d.superdata;
2718 if (!m)
2719 return;
2720 *signalIndex = *methodIndex = member.relativeMethodIndex();
2721
2722 int signalOffset;
2723 int methodOffset;
2724 computeOffsets(m, &signalOffset, &methodOffset);
2725
2726 *methodIndex += methodOffset;
2727 if (member.methodType() == QMetaMethod::Signal) {
2728 *signalIndex = originalClone(m, *signalIndex);
2729 *signalIndex += signalOffset;
2730 } else {
2731 *signalIndex = -1;
2732 }
2733}
2734
2735#ifndef QT_NO_DEBUG
2736static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaMethod &signal,
2737 const QMetaObject *receiver, const QMetaMethod &method)
2738{
2739 if (signal.attributes() & QMetaMethod::Compatibility) {
2740 if (!(method.attributes() & QMetaMethod::Compatibility))
2741 qCWarning(lcConnect, "QObject::connect: Connecting from COMPAT signal (%s::%s)",
2742 sender->className(), signal.methodSignature().constData());
2743 } else if ((method.attributes() & QMetaMethod::Compatibility)
2744 && method.methodType() == QMetaMethod::Signal) {
2745 qCWarning(lcConnect, "QObject::connect: Connecting from %s::%s to COMPAT slot (%s::%s)",
2746 sender->className(), signal.methodSignature().constData(), receiver->className(),
2747 method.methodSignature().constData());
2748 }
2749}
2750#endif
2751
2824 const QObject *receiver, const char *method,
2826{
2827 if (sender == nullptr || receiver == nullptr || signal == nullptr || method == nullptr) {
2828 qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
2829 sender ? sender->metaObject()->className() : "(nullptr)",
2830 (signal && *signal) ? signal + 1 : "(nullptr)",
2831 receiver ? receiver->metaObject()->className() : "(nullptr)",
2832 (method && *method) ? method + 1 : "(nullptr)");
2833 return QMetaObject::Connection(nullptr);
2834 }
2835 QByteArray tmp_signal_name;
2836
2837 if (!check_signal_macro(sender, signal, "connect", "bind"))
2838 return QMetaObject::Connection(nullptr);
2839 const QMetaObject *smeta = sender->metaObject();
2840 const char *signal_arg = signal;
2841 ++signal; // skip code
2842 QArgumentTypeArray signalTypes;
2843 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
2846 &smeta, signalName, signalTypes.size(), signalTypes.constData());
2847 if (signal_index < 0) {
2848 // check for normalized signatures
2849 tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
2850 signal = tmp_signal_name.constData() + 1;
2851
2852 signalTypes.clear();
2853 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
2854 smeta = sender->metaObject();
2856 &smeta, signalName, signalTypes.size(), signalTypes.constData());
2857 }
2858 if (signal_index < 0) {
2859 err_method_notfound(sender, signal_arg, "connect");
2860 err_info_about_objects("connect", sender, receiver);
2861 return QMetaObject::Connection(nullptr);
2862 }
2863 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
2864 signal_index += QMetaObjectPrivate::signalOffset(smeta);
2865
2866 QByteArray tmp_method_name;
2867 int membcode = extract_code(method);
2868
2869 if (!check_method_code(membcode, receiver, method, "connect"))
2870 return QMetaObject::Connection(nullptr);
2871 const char *method_arg = method;
2872 ++method; // skip code
2873
2874 QArgumentTypeArray methodTypes;
2876 const QMetaObject *rmeta = receiver->metaObject();
2877 int method_index_relative = -1;
2878 Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
2879 switch (membcode) {
2880 case QSLOT_CODE:
2881 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
2882 &rmeta, methodName, methodTypes.size(), methodTypes.constData());
2883 break;
2884 case QSIGNAL_CODE:
2885 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
2886 &rmeta, methodName, methodTypes.size(), methodTypes.constData());
2887 break;
2888 }
2889 if (method_index_relative < 0) {
2890 // check for normalized methods
2891 tmp_method_name = QMetaObject::normalizedSignature(method);
2892 method = tmp_method_name.constData();
2893
2894 methodTypes.clear();
2896 // rmeta may have been modified above
2897 rmeta = receiver->metaObject();
2898 switch (membcode) {
2899 case QSLOT_CODE:
2900 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
2901 &rmeta, methodName, methodTypes.size(), methodTypes.constData());
2902 break;
2903 case QSIGNAL_CODE:
2904 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
2905 &rmeta, methodName, methodTypes.size(), methodTypes.constData());
2906 break;
2907 }
2908 }
2909
2910 if (method_index_relative < 0) {
2911 err_method_notfound(receiver, method_arg, "connect");
2912 err_info_about_objects("connect", sender, receiver);
2913 return QMetaObject::Connection(nullptr);
2914 }
2915
2916 if (!QMetaObjectPrivate::checkConnectArgs(signalTypes.size(), signalTypes.constData(),
2917 methodTypes.size(), methodTypes.constData())) {
2918 qCWarning(lcConnect,
2919 "QObject::connect: Incompatible sender/receiver arguments"
2920 "\n %s::%s --> %s::%s",
2921 sender->metaObject()->className(), signal, receiver->metaObject()->className(),
2922 method);
2923 return QMetaObject::Connection(nullptr);
2924 }
2925
2926 int *types = nullptr;
2927 if ((type == Qt::QueuedConnection)
2928 && !(types = queuedConnectionTypes(signalTypes.constData(), signalTypes.size()))) {
2929 return QMetaObject::Connection(nullptr);
2930 }
2931
2932#ifndef QT_NO_DEBUG
2933 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
2934 QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
2935 check_and_warn_compat(smeta, smethod, rmeta, rmethod);
2936#endif
2938 sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
2939 return handle;
2940}
2941
2963 const QObject *receiver, const QMetaMethod &method,
2965{
2966 if (sender == nullptr
2967 || receiver == nullptr
2968 || signal.methodType() != QMetaMethod::Signal
2969 || method.methodType() == QMetaMethod::Constructor) {
2970 qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
2971 sender ? sender->metaObject()->className() : "(nullptr)",
2972 signal.methodSignature().constData(),
2973 receiver ? receiver->metaObject()->className() : "(nullptr)",
2974 method.methodSignature().constData());
2975 return QMetaObject::Connection(nullptr);
2976 }
2977
2978 int signal_index;
2979 int method_index;
2980 {
2981 int dummy;
2982 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
2983 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
2984 }
2985
2986 const QMetaObject *smeta = sender->metaObject();
2987 const QMetaObject *rmeta = receiver->metaObject();
2988 if (signal_index == -1) {
2989 qCWarning(lcConnect, "QObject::connect: Can't find signal %s on instance of class %s",
2990 signal.methodSignature().constData(), smeta->className());
2991 return QMetaObject::Connection(nullptr);
2992 }
2993 if (method_index == -1) {
2994 qCWarning(lcConnect, "QObject::connect: Can't find method %s on instance of class %s",
2995 method.methodSignature().constData(), rmeta->className());
2996 return QMetaObject::Connection(nullptr);
2997 }
2998
2999 if (!QMetaObject::checkConnectArgs(signal.methodSignature().constData(),
3000 method.methodSignature().constData())) {
3001 qCWarning(lcConnect,
3002 "QObject::connect: Incompatible sender/receiver arguments"
3003 "\n %s::%s --> %s::%s",
3004 smeta->className(), signal.methodSignature().constData(), rmeta->className(),
3005 method.methodSignature().constData());
3006 return QMetaObject::Connection(nullptr);
3007 }
3008
3009 int *types = nullptr;
3011 return QMetaObject::Connection(nullptr);
3012
3013#ifndef QT_NO_DEBUG
3014 check_and_warn_compat(smeta, signal, rmeta, method);
3015#endif
3017 sender, signal_index, signal.enclosingMetaObject(), receiver, method_index, nullptr, type, types));
3018 return handle;
3019}
3020
3099bool QObject::disconnect(const QObject *sender, const char *signal,
3100 const QObject *receiver, const char *method)
3101{
3102 if (sender == nullptr || (receiver == nullptr && method != nullptr)) {
3103 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
3104 return false;
3105 }
3106
3107 const char *signal_arg = signal;
3108 QByteArray signal_name;
3109 bool signal_found = false;
3110 if (signal) {
3111 QT_TRY {
3113 signal = signal_name.constData();
3114 } QT_CATCH (const std::bad_alloc &) {
3115 // if the signal is already normalized, we can continue.
3116 if (sender->metaObject()->indexOfSignal(signal + 1) == -1)
3117 QT_RETHROW;
3118 }
3119
3120 if (!check_signal_macro(sender, signal, "disconnect", "unbind"))
3121 return false;
3122 signal++; // skip code
3123 }
3124
3125 QByteArray method_name;
3126 const char *method_arg = method;
3127 int membcode = -1;
3128 bool method_found = false;
3129 if (method) {
3130 QT_TRY {
3132 method = method_name.constData();
3133 } QT_CATCH(const std::bad_alloc &) {
3134 // if the method is already normalized, we can continue.
3135 if (receiver->metaObject()->indexOfMethod(method + 1) == -1)
3136 QT_RETHROW;
3137 }
3138
3139 membcode = extract_code(method);
3140 if (!check_method_code(membcode, receiver, method, "disconnect"))
3141 return false;
3142 method++; // skip code
3143 }
3144
3145 /* We now iterate through all the sender's and receiver's meta
3146 * objects in order to also disconnect possibly shadowed signals
3147 * and slots with the same signature.
3148 */
3149 bool res = false;
3150 const QMetaObject *smeta = sender->metaObject();
3151 QByteArray signalName;
3152 QArgumentTypeArray signalTypes;
3153 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3154 if (signal)
3155 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3157 QArgumentTypeArray methodTypes;
3158 Q_ASSERT(!receiver || QMetaObjectPrivate::get(receiver->metaObject())->revision >= 7);
3159 if (method)
3161 do {
3162 int signal_index = -1;
3163 if (signal) {
3165 &smeta, signalName, signalTypes.size(), signalTypes.constData());
3166 if (signal_index < 0)
3167 break;
3168 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3169 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3170 signal_found = true;
3171 }
3172
3173 if (!method) {
3174 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1, nullptr);
3175 } else {
3176 const QMetaObject *rmeta = receiver->metaObject();
3177 do {
3178 int method_index = QMetaObjectPrivate::indexOfMethod(
3179 rmeta, methodName, methodTypes.size(), methodTypes.constData());
3180 if (method_index >= 0)
3181 while (method_index < rmeta->methodOffset())
3182 rmeta = rmeta->superClass();
3183 if (method_index < 0)
3184 break;
3185 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index, nullptr);
3186 method_found = true;
3187 } while ((rmeta = rmeta->superClass()));
3188 }
3189 } while (signal && (smeta = smeta->superClass()));
3190
3191 if (signal && !signal_found) {
3192 err_method_notfound(sender, signal_arg, "disconnect");
3193 err_info_about_objects("disconnect", sender, receiver);
3194 } else if (method && !method_found) {
3195 err_method_notfound(receiver, method_arg, "disconnect");
3196 err_info_about_objects("disconnect", sender, receiver);
3197 }
3198 if (res) {
3199 if (!signal)
3200 const_cast<QObject *>(sender)->disconnectNotify(QMetaMethod());
3201 }
3202 return res;
3203}
3204
3237 const QObject *receiver, const QMetaMethod &method)
3238{
3239 if (sender == nullptr || (receiver == nullptr && method.mobj != nullptr)) {
3240 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
3241 return false;
3242 }
3243 if (signal.mobj) {
3244 if (signal.methodType() != QMetaMethod::Signal) {
3245 qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s",
3246 "disconnect","unbind",
3247 sender->metaObject()->className(), signal.methodSignature().constData());
3248 return false;
3249 }
3250 }
3251 if (method.mobj) {
3252 if (method.methodType() == QMetaMethod::Constructor) {
3253 qCWarning(lcConnect, "QObject::disconnect: cannot use constructor as argument %s::%s",
3254 receiver->metaObject()->className(), method.methodSignature().constData());
3255 return false;
3256 }
3257 }
3258
3259 int signal_index;
3260 int method_index;
3261 {
3262 int dummy;
3263 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3264 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3265 }
3266 // If we are here sender is not nullptr. If signal is not nullptr while signal_index
3267 // is -1 then this signal is not a member of sender.
3268 if (signal.mobj && signal_index == -1) {
3269 qCWarning(lcConnect, "QObject::disconnect: signal %s not found on class %s",
3270 signal.methodSignature().constData(), sender->metaObject()->className());
3271 return false;
3272 }
3273 // If this condition is true then method is not a member of receiver.
3274 if (receiver && method.mobj && method_index == -1) {
3275 qCWarning(lcConnect, "QObject::disconnect: method %s not found on class %s",
3276 method.methodSignature().constData(), receiver->metaObject()->className());
3277 return false;
3278 }
3279
3280 if (!QMetaObjectPrivate::disconnect(sender, signal_index, signal.mobj, receiver, method_index, nullptr))
3281 return false;
3282
3283 if (!signal.isValid()) {
3284 // The signal is a wildcard, meaning all signals were disconnected.
3285 // QMetaObjectPrivate::disconnect() doesn't call disconnectNotify()
3286 // per connection in this case. Call it once now, with an invalid
3287 // QMetaMethod as argument, as documented.
3288 const_cast<QObject *>(sender)->disconnectNotify(signal);
3289 }
3290 return true;
3291}
3292
3348{
3350}
3351
3383{
3385}
3386
3387/*
3388 \internal
3389 convert a signal index from the method range to the signal range
3390 */
3391static int methodIndexToSignalIndex(const QMetaObject **base, int signal_index)
3392{
3393 if (signal_index < 0)
3394 return signal_index;
3395 const QMetaObject *metaObject = *base;
3396 while (metaObject && metaObject->methodOffset() > signal_index)
3397 metaObject = metaObject->superClass();
3398
3399 if (metaObject) {
3400 int signalOffset, methodOffset;
3401 computeOffsets(metaObject, &signalOffset, &methodOffset);
3402 if (signal_index < metaObject->methodCount())
3403 signal_index = QMetaObjectPrivate::originalClone(metaObject, signal_index - methodOffset) + signalOffset;
3404 else
3405 signal_index = signal_index - methodOffset + signalOffset;
3406 *base = metaObject;
3407 }
3408 return signal_index;
3409}
3410
3420 const QObject *receiver, int method_index, int type,
3421 int *types)
3422{
3423 const QMetaObject *smeta = sender->metaObject();
3424 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3425 return Connection(QMetaObjectPrivate::connect(sender, signal_index, smeta,
3426 receiver, method_index,
3427 nullptr, //FIXME, we could speed this connection up by computing the relative index
3428 type, types));
3429}
3430
3440 int signal_index, const QMetaObject *smeta,
3441 const QObject *receiver, int method_index,
3442 const QMetaObject *rmeta, int type, int *types)
3443{
3444 QObject *s = const_cast<QObject *>(sender);
3445 QObject *r = const_cast<QObject *>(receiver);
3446
3447 int method_offset = rmeta ? rmeta->methodOffset() : 0;
3448 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 6);
3449 QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall : nullptr;
3450
3451 QOrderedMutexLocker locker(signalSlotLock(sender),
3452 signalSlotLock(receiver));
3453
3455 if (type & Qt::UniqueConnection && scd) {
3456 if (scd->signalVectorCount() > signal_index) {
3457 const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
3458
3459 int method_index_absolute = method_index + method_offset;
3460
3461 while (c2) {
3462 if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute)
3463 return nullptr;
3464 c2 = c2->nextConnectionList.loadRelaxed();
3465 }
3466 }
3467 }
3468 type &= ~Qt::UniqueConnection;
3469
3470 const bool isSingleShot = type & Qt::SingleShotConnection;
3471 type &= ~Qt::SingleShotConnection;
3472
3473 Q_ASSERT(type >= 0);
3474 Q_ASSERT(type <= 3);
3475
3476 std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
3477 c->sender = s;
3478 c->signal_index = signal_index;
3479 c->receiver.storeRelaxed(r);
3480 QThreadData *td = r->d_func()->threadData.loadAcquire();
3481 td->ref();
3482 c->receiverThreadData.storeRelaxed(td);
3483 c->method_relative = method_index;
3484 c->method_offset = method_offset;
3485 c->connectionType = type;
3486 c->isSlotObject = false;
3487 c->argumentTypes.storeRelaxed(types);
3488 c->callFunction = callFunction;
3489 c->isSingleShot = isSingleShot;
3490
3491 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
3492
3493 locker.unlock();
3494 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3495 if (smethod.isValid())
3496 s->connectNotify(smethod);
3497
3498 return c.release();
3499}
3500
3504bool QMetaObject::disconnect(const QObject *sender, int signal_index,
3505 const QObject *receiver, int method_index)
3506{
3507 const QMetaObject *smeta = sender->metaObject();
3508 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3509 return QMetaObjectPrivate::disconnect(sender, signal_index, smeta,
3510 receiver, method_index, nullptr);
3511}
3512
3520bool QMetaObject::disconnectOne(const QObject *sender, int signal_index,
3521 const QObject *receiver, int method_index)
3522{
3523 const QMetaObject *smeta = sender->metaObject();
3524 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3525 return QMetaObjectPrivate::disconnect(sender, signal_index, smeta,
3526 receiver, method_index, nullptr,
3528}
3529
3535 const QObject *receiver, int method_index, void **slot,
3536 QBasicMutex *senderMutex, DisconnectType disconnectType)
3537{
3538 bool success = false;
3539
3540 auto &connectionList = connections->connectionsForSignal(signalIndex);
3541 auto *c = connectionList.first.loadRelaxed();
3542 while (c) {
3543 QObject *r = c->receiver.loadRelaxed();
3544 if (r && (receiver == nullptr || (r == receiver
3545 && (method_index < 0 || (!c->isSlotObject && c->method() == method_index))
3546 && (slot == nullptr || (c->isSlotObject && c->slotObj->compare(slot)))))) {
3547 bool needToUnlock = false;
3548 QBasicMutex *receiverMutex = nullptr;
3549 if (r) {
3550 receiverMutex = signalSlotLock(r);
3551 // need to relock this receiver and sender in the correct order
3552 needToUnlock = QOrderedMutexLocker::relock(senderMutex, receiverMutex);
3553 }
3554 if (c->receiver.loadRelaxed())
3555 connections->removeConnection(c);
3556
3557 if (needToUnlock)
3558 receiverMutex->unlock();
3559
3560 success = true;
3561
3562 if (disconnectType == DisconnectOne)
3563 return success;
3564 }
3565 c = c->nextConnectionList.loadRelaxed();
3566 }
3567 return success;
3568}
3569
3575 int signal_index, const QMetaObject *smeta,
3576 const QObject *receiver, int method_index, void **slot,
3577 DisconnectType disconnectType)
3578{
3579 if (!sender)
3580 return false;
3581
3582 QObject *s = const_cast<QObject *>(sender);
3583
3584 QBasicMutex *senderMutex = signalSlotLock(sender);
3585 QMutexLocker locker(senderMutex);
3586
3588 if (!scd)
3589 return false;
3590
3591 bool success = false;
3592 {
3593 // prevent incoming connections changing the connections->receivers while unlocked
3595
3596 if (signal_index < 0) {
3597 // remove from all connection lists
3598 for (int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
3599 if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
3600 success = true;
3601 }
3602 } else if (signal_index < scd->signalVectorCount()) {
3603 if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
3604 success = true;
3605 }
3606 }
3607
3608 locker.unlock();
3609 if (success) {
3611
3612 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3613 if (smethod.isValid())
3614 s->disconnectNotify(smethod);
3615 }
3616
3617 return success;
3618}
3619
3620// Helpers for formatting the connect statements of connectSlotsByName()'s debug mode
3622{
3623 const auto signature = method.methodSignature();
3624 Q_ASSERT(signature.endsWith(')'));
3625 const int openParen = signature.indexOf('(');
3626 const bool hasParameters = openParen >= 0 && openParen < signature.size() - 2;
3628 if (hasParameters) {
3629 result += "qOverload<"
3630 + signature.mid(openParen + 1, signature.size() - openParen - 2) + ">(";
3631 }
3632 result += '&';
3633 result += className + QByteArrayLiteral("::") + method.name();
3634 if (hasParameters)
3635 result += ')';
3636 return result;
3637}
3638
3639static QByteArray msgConnect(const QMetaObject *senderMo, const QByteArray &senderName,
3640 const QMetaMethod &signal, const QObject *receiver, int receiverIndex)
3641{
3642 const auto receiverMo = receiver->metaObject();
3643 const auto slot = receiverMo->method(receiverIndex);
3644 QByteArray message = QByteArrayLiteral("QObject::connect(")
3645 + senderName + ", " + formatConnectionSignature(senderMo->className(), signal)
3646 + ", " + receiver->objectName().toLatin1() + ", "
3647 + formatConnectionSignature(receiverMo->className(), slot) + ");";
3648 return message;
3649}
3650
3671{
3672 if (!o)
3673 return;
3674 const QMetaObject *mo = o->metaObject();
3675 Q_ASSERT(mo);
3676 const QObjectList list = // list of all objects to look for matching signals including...
3677 o->findChildren<QObject *>() // all children of 'o'...
3678 << o; // and the object 'o' itself
3679
3680 // for each method/slot of o ...
3681 for (int i = 0; i < mo->methodCount(); ++i) {
3682 const QByteArray slotSignature = mo->method(i).methodSignature();
3683 const char *slot = slotSignature.constData();
3684 Q_ASSERT(slot);
3685
3686 // ...that starts with "on_", ...
3687 if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
3688 continue;
3689
3690 // ...we check each object in our list, ...
3691 bool foundIt = false;
3692 for (int j = 0; j < list.size(); ++j) {
3693 const QObject *co = list.at(j);
3694 const QByteArray coName = co->objectName().toLatin1();
3695
3696 // ...discarding those whose objectName is not fitting the pattern "on_<objectName>_...", ...
3697 if (coName.isEmpty() || qstrncmp(slot + 3, coName.constData(), coName.size()) || slot[coName.size()+3] != '_')
3698 continue;
3699
3700 const char *signal = slot + coName.size() + 4; // the 'signal' part of the slot name
3701
3702 // ...for the presence of a matching signal "on_<objectName>_<signal>".
3703 const QMetaObject *smeta;
3704 int sigIndex = co->d_func()->signalIndex(signal, &smeta);
3705 if (sigIndex < 0) {
3706 // if no exactly fitting signal (name + complete parameter type list) could be found
3707 // look for just any signal with the correct name and at least the slot's parameter list.
3708 // Note: if more than one of those signals exist, the one that gets connected is
3709 // chosen 'at random' (order of declaration in source file)
3710 QList<QByteArray> compatibleSignals;
3711 const QMetaObject *smo = co->metaObject();
3712 int sigLen = int(qstrlen(signal)) - 1; // ignore the trailing ')'
3713 for (int k = QMetaObjectPrivate::absoluteSignalCount(smo)-1; k >= 0; --k) {
3715 if (!qstrncmp(method.methodSignature().constData(), signal, sigLen)) {
3716 smeta = method.enclosingMetaObject();
3717 sigIndex = k;
3718 compatibleSignals.prepend(method.methodSignature());
3719 }
3720 }
3721 if (compatibleSignals.size() > 1)
3722 qCWarning(lcConnectSlotsByName) << "QMetaObject::connectSlotsByName: Connecting slot" << slot
3723 << "with the first of the following compatible signals:" << compatibleSignals;
3724 }
3725
3726 if (sigIndex < 0)
3727 continue;
3728
3729 // we connect it...
3730 if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) {
3731 foundIt = true;
3732 qCDebug(lcConnectSlotsByName, "%s",
3733 msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData());
3734 // ...and stop looking for further objects with the same name.
3735 // Note: the Designer will make sure each object name is unique in the above
3736 // 'list' but other code may create two child objects with the same name. In
3737 // this case one is chosen 'at random'.
3738 break;
3739 }
3740 }
3741 if (foundIt) {
3742 // we found our slot, now skip all overloads
3743 while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
3744 ++i;
3745 } else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
3746 // check if the slot has the following signature: "on_..._...(..."
3747 int iParen = slotSignature.indexOf('(');
3748 int iLastUnderscore = slotSignature.lastIndexOf('_', iParen - 1);
3749 if (iLastUnderscore > 3)
3750 qCWarning(lcConnectSlotsByName,
3751 "QMetaObject::connectSlotsByName: No matching signal for %s", slot);
3752 }
3753 }
3754}
3755
3763 SlotObjectGuard() = default;
3764 // move would be fine, but we do not need it currently
3765 Q_DISABLE_COPY_MOVE(SlotObjectGuard)
3766 explicit SlotObjectGuard(QtPrivate::QSlotObjectBase *slotObject)
3767 : m_slotObject(slotObject)
3768 {
3769 if (m_slotObject)
3770 m_slotObject->ref();
3771 }
3772
3774 { return m_slotObject; }
3775
3777 { return m_slotObject; }
3778
3780 if (m_slotObject)
3781 m_slotObject->destroyIfLastRef();
3782 }
3783private:
3784 QtPrivate::QSlotObjectBase *m_slotObject = nullptr;
3785};
3786
3792static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv)
3793{
3794 const int *argumentTypes = c->argumentTypes.loadRelaxed();
3795 if (!argumentTypes) {
3796 QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
3797 argumentTypes = queuedConnectionTypes(m);
3798 if (!argumentTypes) // cannot queue arguments
3799 argumentTypes = &DIRECT_CONNECTION_ONLY;
3800 if (!c->argumentTypes.testAndSetOrdered(nullptr, argumentTypes)) {
3801 if (argumentTypes != &DIRECT_CONNECTION_ONLY)
3802 delete[] argumentTypes;
3803 argumentTypes = c->argumentTypes.loadRelaxed();
3804 }
3805 }
3806 if (argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate
3807 return;
3808 int nargs = 1; // include return type
3809 while (argumentTypes[nargs - 1])
3810 ++nargs;
3811
3812 QMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
3813 QObject *receiver = c->receiver.loadRelaxed();
3814 if (!receiver) {
3815 // the connection has been disconnected before we got the lock
3816 return;
3817 }
3818
3819 SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj : nullptr };
3820 locker.unlock();
3821
3822 QMetaCallEvent *ev = c->isSlotObject ?
3823 new QMetaCallEvent(c->slotObj, sender, signal, nargs) :
3824 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs);
3825
3826 void **args = ev->args();
3827 QMetaType *types = ev->types();
3828
3829 types[0] = QMetaType(); // return type
3830 args[0] = nullptr; // return value
3831
3832 if (nargs > 1) {
3833 for (int n = 1; n < nargs; ++n)
3834 types[n] = QMetaType(argumentTypes[n - 1]);
3835
3836 for (int n = 1; n < nargs; ++n)
3837 args[n] = types[n].create(argv[n]);
3838 }
3839
3840 if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) {
3841 delete ev;
3842 return;
3843 }
3844
3845 locker.relock();
3846 if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
3847 // the connection has been disconnected while we were unlocked
3848 locker.unlock();
3849 delete ev;
3850 return;
3851 }
3852
3853 QCoreApplication::postEvent(receiver, ev);
3854}
3855
3856template <bool callbacks_enabled>
3857void doActivate(QObject *sender, int signal_index, void **argv)
3858{
3860
3861 if (sp->blockSig)
3862 return;
3863
3864 Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
3865
3866 if (sp->isDeclarativeSignalConnected(signal_index)
3868 Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
3869 QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
3870 signal_index, argv);
3871 }
3872
3873 const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() : nullptr;
3874
3875 void *empty_argv[] = { nullptr };
3876 if (!argv)
3877 argv = empty_argv;
3878
3879 if (!sp->maybeSignalConnected(signal_index)) {
3880 // The possible declarative connection is done, and nothing else is connected
3881 if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
3882 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
3883 if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
3884 signal_spy_set->signal_end_callback(sender, signal_index);
3885 return;
3886 }
3887
3888 if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
3889 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
3890
3891 bool senderDeleted = false;
3892 {
3893 Q_ASSERT(sp->connections.loadAcquire());
3894 QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadRelaxed());
3895 QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();
3896
3898 if (signal_index < signalVector->count())
3899 list = &signalVector->at(signal_index);
3900 else
3901 list = &signalVector->at(-1);
3902
3903 Qt::HANDLE currentThreadId = QThread::currentThreadId();
3904 bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
3905
3906 // We need to check against the highest connection id to ensure that signals added
3907 // during the signal emission are not emitted in this emission.
3908 uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
3909 do {
3910 QObjectPrivate::Connection *c = list->first.loadRelaxed();
3911 if (!c)
3912 continue;
3913
3914 do {
3915 QObject * const receiver = c->receiver.loadRelaxed();
3916 if (!receiver)
3917 continue;
3918
3919 QThreadData *td = c->receiverThreadData.loadRelaxed();
3920 if (!td)
3921 continue;
3922
3923 bool receiverInSameThread;
3924 if (inSenderThread) {
3925 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
3926 } else {
3927 // need to lock before reading the threadId, because moveToThread() could interfere
3928 QMutexLocker lock(signalSlotLock(receiver));
3929 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
3930 }
3931
3932
3933 // determine if this connection should be sent immediately or
3934 // put into the event queue
3935 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
3936 || (c->connectionType == Qt::QueuedConnection)) {
3937 queued_activate(sender, signal_index, c, argv);
3938 continue;
3939#if QT_CONFIG(thread)
3940 } else if (c->connectionType == Qt::BlockingQueuedConnection) {
3941 if (receiverInSameThread) {
3942 qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
3943 "Sender is %s(%p), receiver is %s(%p)",
3944 sender->metaObject()->className(), sender,
3945 receiver->metaObject()->className(), receiver);
3946 }
3947
3948 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
3949 continue;
3950
3951 QSemaphore semaphore;
3952 {
3953 QMutexLocker locker(signalSlotLock(receiver));
3954 if (!c->isSingleShot && !c->receiver.loadAcquire())
3955 continue;
3956 QMetaCallEvent *ev = c->isSlotObject ?
3957 new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &semaphore) :
3958 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
3959 sender, signal_index, argv, &semaphore);
3960 QCoreApplication::postEvent(receiver, ev);
3961 }
3962 semaphore.acquire();
3963 continue;
3964#endif
3965 }
3966
3967 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
3968 continue;
3969
3970 QObjectPrivate::Sender senderData(receiverInSameThread ? receiver : nullptr, sender, signal_index);
3971
3972 if (c->isSlotObject) {
3973 SlotObjectGuard obj{c->slotObj};
3974
3975 {
3976 Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
3977 obj->call(receiver, argv);
3978 }
3979 } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
3980 //we compare the vtable to make sure we are not in the destructor of the object.
3981 const int method_relative = c->method_relative;
3982 const auto callFunction = c->callFunction;
3983 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
3984 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)
3985 signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
3986
3987 {
3988 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
3989 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
3990 }
3991
3992 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
3993 signal_spy_set->slot_end_callback(receiver, methodIndex);
3994 } else {
3995 const int method = c->method_relative + c->method_offset;
3996
3997 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {
3998 signal_spy_set->slot_begin_callback(receiver, method, argv);
3999 }
4000
4001 {
4002 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
4004 }
4005
4006 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
4007 signal_spy_set->slot_end_callback(receiver, method);
4008 }
4009 } while ((c = c->nextConnectionList.loadRelaxed()) != nullptr && c->id <= highestConnectionId);
4010
4011 } while (list != &signalVector->at(-1) &&
4012 //start over for all signals;
4013 ((list = &signalVector->at(-1)), true));
4014
4015 if (connections->currentConnectionId.loadRelaxed() == 0)
4016 senderDeleted = true;
4017 }
4018 if (!senderDeleted) {
4019 sp->connections.loadRelaxed()->cleanOrphanedConnections(sender);
4020
4021 if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
4022 signal_spy_set->signal_end_callback(sender, signal_index);
4023 }
4024}
4025
4029void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
4030 void **argv)
4031{
4032 int signal_index = local_signal_index + QMetaObjectPrivate::signalOffset(m);
4033
4034 if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
4035 doActivate<true>(sender, signal_index, argv);
4036 else
4037 doActivate<false>(sender, signal_index, argv);
4038}
4039
4043void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
4044{
4045 int signal_index = signalOffset + local_signal_index;
4046
4047 if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
4048 doActivate<true>(sender, signal_index, argv);
4049 else
4050 doActivate<false>(sender, signal_index, argv);
4051}
4052
4057void QMetaObject::activate(QObject *sender, int signal_index, void **argv)
4058{
4059 const QMetaObject *mo = sender->metaObject();
4060 while (mo->methodOffset() > signal_index)
4061 mo = mo->superClass();
4062 activate(sender, mo, signal_index - mo->methodOffset(), argv);
4063}
4064
4074int QObjectPrivate::signalIndex(const char *signalName,
4075 const QMetaObject **meta) const
4076{
4077 Q_Q(const QObject);
4078 const QMetaObject *base = q->metaObject();
4079 Q_ASSERT(QMetaObjectPrivate::get(base)->revision >= 7);
4082 int relative_index = QMetaObjectPrivate::indexOfSignalRelative(
4083 &base, name, types.size(), types.constData());
4084 if (relative_index < 0)
4085 return relative_index;
4086 relative_index = QMetaObjectPrivate::originalClone(base, relative_index);
4087 if (meta)
4088 *meta = base;
4089 return relative_index + QMetaObjectPrivate::signalOffset(base);
4090}
4091
4092/*****************************************************************************
4093 Properties
4094 *****************************************************************************/
4095
4126bool QObject::doSetProperty(const char *name, const QVariant *lvalue, QVariant *rvalue)
4127{
4128 Q_D(QObject);
4129 const auto &value =*lvalue;
4130 const QMetaObject *meta = metaObject();
4131 if (!name || !meta)
4132 return false;
4133
4134 int id = meta->indexOfProperty(name);
4135 if (id < 0) {
4136 d->ensureExtraData();
4137
4138 const int idx = d->extraData->propertyNames.indexOf(name);
4139
4140 if (!value.isValid()) {
4141 if (idx == -1)
4142 return false;
4143 d->extraData->propertyNames.removeAt(idx);
4144 d->extraData->propertyValues.removeAt(idx);
4145 } else {
4146 if (idx == -1) {
4147 d->extraData->propertyNames.append(name);
4148 if (rvalue)
4149 d->extraData->propertyValues.append(std::move(*rvalue));
4150 else
4151 d->extraData->propertyValues.append(*lvalue);
4152 } else {
4153 if (value.userType() == d->extraData->propertyValues.at(idx).userType()
4154 && value == d->extraData->propertyValues.at(idx))
4155 return false;
4156 if (rvalue)
4157 d->extraData->propertyValues[idx] = std::move(*rvalue);
4158 else
4159 d->extraData->propertyValues[idx] = *lvalue;
4160 }
4161 }
4162
4164 QCoreApplication::sendEvent(this, &ev);
4165
4166 return false;
4167 }
4168 QMetaProperty p = meta->property(id);
4169#ifndef QT_NO_DEBUG
4170 if (!p.isWritable())
4171 qWarning("%s::setProperty: Property \"%s\" invalid,"
4172 " read-only or does not exist", metaObject()->className(), name);
4173#endif
4174 return rvalue ? p.write(this, std::move(*rvalue)) : p.write(this, *lvalue);
4175}
4176
4188{
4189 Q_D(const QObject);
4190 const QMetaObject *meta = metaObject();
4191 if (!name || !meta)
4192 return QVariant();
4193
4194 int id = meta->indexOfProperty(name);
4195 if (id < 0) {
4196 if (!d->extraData)
4197 return QVariant();
4198 const int i = d->extraData->propertyNames.indexOf(name);
4199 return d->extraData->propertyValues.value(i);
4200 }
4201 QMetaProperty p = meta->property(id);
4202#ifndef QT_NO_DEBUG
4203 if (!p.isReadable())
4204 qWarning("%s::property: Property \"%s\" invalid or does not exist",
4205 metaObject()->className(), name);
4206#endif
4207 return p.read(this);
4208}
4209
4217{
4218 Q_D(const QObject);
4219 if (d->extraData)
4220 return d->extraData->propertyNames;
4221 return QList<QByteArray>();
4222}
4223
4224/*****************************************************************************
4225 QObject debugging output routines.
4226 *****************************************************************************/
4227
4229{
4230 return {};
4231}
4232
4233static void dumpRecursive(int level, const QObject *object)
4234{
4235 if (object) {
4236 const int indent = level * 4;
4237 qDebug("%*s%s::%ls %s", indent, "", object->metaObject()->className(),
4238 qUtf16Printable(object->objectName()),
4239 QObjectPrivate::get(object)->flagsForDumping().c_str());
4240 for (auto child : object->children())
4242 }
4243}
4244
4245
4255{
4256 dumpRecursive(0, this);
4257}
4258
4269{
4270 qDebug("OBJECT %s::%s", metaObject()->className(),
4271 objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
4272
4273 Q_D(const QObject);
4274 QMutexLocker locker(signalSlotLock(this));
4275
4276 // first, look for connections where this object is the sender
4277 qDebug(" SIGNALS OUT");
4278
4279 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
4280 if (cd && cd->signalVectorCount() > 0) {
4281 QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
4282 for (int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
4283 const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
4284 if (!c)
4285 continue;
4287 qDebug(" signal: %s", signal.methodSignature().constData());
4288
4289 // receivers
4290 while (c) {
4291 if (!c->receiver.loadRelaxed()) {
4292 qDebug(" <Disconnected receiver>");
4293 c = c->nextConnectionList.loadRelaxed();
4294 continue;
4295 }
4296 if (c->isSlotObject) {
4297 qDebug(" <functor or function pointer>");
4298 c = c->nextConnectionList.loadRelaxed();
4299 continue;
4300 }
4301 const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
4302 const QMetaMethod method = receiverMetaObject->method(c->method());
4303 qDebug(" --> %s::%s %s",
4304 receiverMetaObject->className(),
4305 c->receiver.loadRelaxed()->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
4306 method.methodSignature().constData());
4307 c = c->nextConnectionList.loadRelaxed();
4308 }
4309 }
4310 } else {
4311 qDebug( " <None>" );
4312 }
4313
4314 // now look for connections where this object is the receiver
4315 qDebug(" SIGNALS IN");
4316
4317 if (cd && cd->senders) {
4318 for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
4319 QByteArray slotName = QByteArrayLiteral("<unknown>");
4320 if (!s->isSlotObject) {
4321 const QMetaMethod slot = metaObject()->method(s->method());
4322 slotName = slot.methodSignature();
4323 }
4324 qDebug(" <-- %s::%s %s",
4325 s->sender->metaObject()->className(),
4326 s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()),
4327 slotName.constData());
4328 }
4329 } else {
4330 qDebug(" <None>");
4331 }
4332}
4333
4334
4335#ifndef QT_NO_DEBUG_STREAM
4337{
4338 QDebugStateSaver saver(dbg);
4339 if (!o)
4340 return dbg << "QObject(0x0)";
4341 dbg.nospace() << o->metaObject()->className() << '(' << (const void *)o;
4342 if (!o->objectName().isEmpty())
4343 dbg << ", name = " << o->objectName();
4344 dbg << ')';
4345 return dbg;
4346}
4347#endif
4348
4877{
4878 delete o;
4879}
4880
5042QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,
5043 const QObject *receiver, void **slot,
5045 const int *types, const QMetaObject *senderMetaObject)
5046{
5047 if (!signal) {
5048 qCWarning(lcConnect, "QObject::connect: invalid nullptr parameter");
5049 if (slotObj)
5050 slotObj->destroyIfLastRef();
5051 return QMetaObject::Connection();
5052 }
5053
5054 int signal_index = -1;
5055 void *args[] = { &signal_index, signal };
5056 for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
5057 senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
5058 if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
5059 break;
5060 }
5061 if (!senderMetaObject) {
5062 qCWarning(lcConnect, "QObject::connect: signal not found in %s", sender->metaObject()->className());
5063 slotObj->destroyIfLastRef();
5064 return QMetaObject::Connection(nullptr);
5065 }
5066 signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
5067 return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj, type, types, senderMetaObject);
5068}
5069
5070static void connectWarning(const QObject *sender,
5071 const QMetaObject *senderMetaObject,
5072 const QObject *receiver,
5073 const char *message)
5074{
5075 const char *senderString = sender ? sender->metaObject()->className()
5076 : senderMetaObject ? senderMetaObject->className()
5077 : "Unknown";
5078 const char *receiverString = receiver ? receiver->metaObject()->className()
5079 : "Unknown";
5080 qCWarning(lcConnect, "QObject::connect(%s, %s): %s", senderString, receiverString, message);
5081}
5082
5091 const QObject *receiver, void **slot,
5092 QtPrivate::QSlotObjectBase *slotObj, int type,
5093 const int *types, const QMetaObject *senderMetaObject)
5094{
5095 auto connectFailureGuard = qScopeGuard([&]()
5096 {
5097 if (slotObj)
5098 slotObj->destroyIfLastRef();
5099 });
5100
5101 if (!sender || !receiver || !slotObj || !senderMetaObject) {
5102 connectWarning(sender, senderMetaObject, receiver, "invalid nullptr parameter");
5103 return QMetaObject::Connection();
5104 }
5105
5106 if (type & Qt::UniqueConnection && !slot) {
5107 connectWarning(sender, senderMetaObject, receiver, "unique connections require a pointer to member function of a QObject subclass");
5108 return QMetaObject::Connection();
5109 }
5110
5111 connectFailureGuard.dismiss();
5112
5113 QObject *s = const_cast<QObject *>(sender);
5114 QObject *r = const_cast<QObject *>(receiver);
5115
5116 QOrderedMutexLocker locker(signalSlotLock(sender),
5117 signalSlotLock(receiver));
5118
5119 if (type & Qt::UniqueConnection && slot && QObjectPrivate::get(s)->connections.loadRelaxed()) {
5121 if (connections->signalVectorCount() > signal_index) {
5122 const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
5123
5124 while (c2) {
5125 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) {
5126 slotObj->destroyIfLastRef();
5127 return QMetaObject::Connection();
5128 }
5129 c2 = c2->nextConnectionList.loadRelaxed();
5130 }
5131 }
5132 }
5133 type &= ~Qt::UniqueConnection;
5134
5135 const bool isSingleShot = type & Qt::SingleShotConnection;
5136 type &= ~Qt::SingleShotConnection;
5137
5138 Q_ASSERT(type >= 0);
5139 Q_ASSERT(type <= 3);
5140
5141 std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
5142 c->sender = s;
5143 c->signal_index = signal_index;
5144 QThreadData *td = r->d_func()->threadData.loadAcquire();
5145 td->ref();
5146 c->receiverThreadData.storeRelaxed(td);
5147 c->receiver.storeRelaxed(r);
5148 c->slotObj = slotObj;
5149 c->connectionType = type;
5150 c->isSlotObject = true;
5151 if (types) {
5152 c->argumentTypes.storeRelaxed(types);
5153 c->ownArgumentTypes = false;
5154 }
5155 c->isSingleShot = isSingleShot;
5156
5157 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
5158 QMetaObject::Connection ret(c.release());
5159 locker.unlock();
5160
5161 QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
5162 Q_ASSERT(method.isValid());
5163 s->connectNotify(method);
5164
5165 return ret;
5166}
5167
5177{
5179 if (!c)
5180 return false;
5181 const bool disconnected = QObjectPrivate::removeConnection(c);
5182 const_cast<QMetaObject::Connection &>(connection).d_ptr = nullptr;
5183 c->deref(); // has been removed from the QMetaObject::Connection object
5184 return disconnected;
5185}
5186
5248bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot, const QMetaObject *senderMetaObject)
5249{
5250 if (sender == nullptr || (receiver == nullptr && slot != nullptr)) {
5251 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
5252 return false;
5253 }
5254
5255 int signal_index = -1;
5256 if (signal) {
5257 void *args[] = { &signal_index, signal };
5258 for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
5259 senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
5260 if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
5261 break;
5262 }
5263 if (!senderMetaObject) {
5264 qCWarning(lcConnect, "QObject::disconnect: signal not found in %s", sender->metaObject()->className());
5265 return false;
5266 }
5267 signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
5268 }
5269
5270 return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1, slot);
5271}
5272
5283{
5284 return QObjectPrivate::connect(sender, signal_index, sender, slotObj, type);
5285}
5286
5298 const QObject *receiver,
5301{
5302 if (!sender) {
5303 qCWarning(lcConnect, "QObject::connect: invalid nullptr parameter");
5304 if (slotObj)
5305 slotObj->destroyIfLastRef();
5306 return QMetaObject::Connection();
5307 }
5308 const QMetaObject *senderMetaObject = sender->metaObject();
5309 signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
5310
5311 return QObjectPrivate::connectImpl(sender, signal_index, receiver, /*slot*/ nullptr, slotObj,
5312 type, /*types*/ nullptr, senderMetaObject);
5313}
5314
5323bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, void **slot)
5324{
5325 return QObjectPrivate::disconnect(sender, signal_index, sender, slot);
5326}
5327
5340bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, const QObject *receiver,
5341 void **slot)
5342{
5343 const QMetaObject *senderMetaObject = sender->metaObject();
5344 signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
5345
5346 return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1,
5347 slot);
5348}
5349
5355{
5356 if (!c)
5357 return false;
5358 QObject *receiver = c->receiver.loadRelaxed();
5359 if (!receiver)
5360 return false;
5361
5362 QBasicMutex *senderMutex = signalSlotLock(c->sender);
5363 QBasicMutex *receiverMutex = signalSlotLock(receiver);
5364
5366 {
5367 QOrderedMutexLocker locker(senderMutex, receiverMutex);
5368
5369 // load receiver once again and recheck to ensure nobody else has removed the connection in the meantime
5370 receiver = c->receiver.loadRelaxed();
5371 if (!receiver)
5372 return false;
5373
5374 connections = QObjectPrivate::get(c->sender)->connections.loadRelaxed();
5376 connections->removeConnection(c);
5377
5378 c->sender->disconnectNotify(QMetaObjectPrivate::signal(c->sender->metaObject(), c->signal_index));
5379 // We must not hold the receiver mutex, else we risk dead-locking; we also only need the sender mutex
5380 // It is however vital to hold the senderMutex before calling cleanOrphanedConnections, as otherwise
5381 // another thread might modify/delete the connection
5382 if (receiverMutex != senderMutex) {
5383 receiverMutex->unlock();
5384 }
5386 senderMutex->unlock(); // now both sender and receiver mutex have been manually unlocked
5387 locker.dismiss(); // so we dismiss the QOrderedMutexLocker
5388 }
5389
5390 return true;
5391}
5392
5400{
5401 if (auto conns = connections.loadRelaxed()) {
5402 Q_Q(QObject);
5403 const QMetaObject *metaObject = q->metaObject();
5404 int signal_index = methodIndexToSignalIndex(&metaObject, property.notifySignalIndex());
5405 if (signal_index >= conns->signalVectorCount())
5406 return nullptr;
5407 const auto connectionList = conns->connectionsForSignal(signal_index);
5408 for (auto c = connectionList.first.loadRelaxed(); c;
5409 c = c->nextConnectionList.loadRelaxed()) {
5410 if (c->isSlotObject) {
5412 property.propertyIndex()))
5413 return p;
5414 }
5415 }
5416 }
5417 return nullptr;
5418}
5419
5435QMetaObject::Connection::Connection(const QMetaObject::Connection &other) : d_ptr(other.d_ptr)
5436{
5437 if (d_ptr)
5438 static_cast<QObjectPrivate::Connection *>(d_ptr)->ref();
5439}
5440
5444QMetaObject::Connection &QMetaObject::Connection::operator=(const QMetaObject::Connection &other)
5445{
5446 if (other.d_ptr != d_ptr) {
5447 if (d_ptr)
5448 static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
5449 d_ptr = other.d_ptr;
5450 if (other.d_ptr)
5451 static_cast<QObjectPrivate::Connection *>(other.d_ptr)->ref();
5452 }
5453 return *this;
5454}
5455
5460QMetaObject::Connection::Connection() : d_ptr(nullptr) {}
5461
5465QMetaObject::Connection::~Connection()
5466{
5467 if (d_ptr)
5468 static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
5469}
5470
5472bool QMetaObject::Connection::isConnected_helper() const
5473{
5474 Q_ASSERT(d_ptr); // we're only called from operator RestrictedBool() const
5476
5477 return c->receiver.loadRelaxed();
5478}
5479
5480
5492
5493#include "moc_qobject.cpp"
static bool(* isSignalConnected)(QAbstractDeclarativeData *, const QObject *, int)
Definition qobject_p.h:69
static int(* receivers)(QAbstractDeclarativeData *, const QObject *, int)
Definition qobject_p.h:68
static void(* destroyed)(QAbstractDeclarativeData *, QObject *)
Definition qobject_p.h:66
static void(* signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **)
Definition qobject_p.h:67
static void(* setWidgetParent)(QObject *, QObject *)
Definition qobject_p.h:70
virtual QList< TimerInfo > registeredTimers(QObject *object) const =0
Returns a list of registered timers for object.
virtual bool unregisterTimers(QObject *object)=0
Unregisters all the timers associated with the given object.
virtual void placeMetaCall(QObject *object)=0
const QObject * sender() const
Definition qobject_p.h:356
\inmodule QtCore
int type() const
bool ref() noexcept
bool deref() noexcept
void storeRelaxed(T newValue) noexcept
T loadRelaxed() const noexcept
Type loadAcquire() const noexcept
Type loadRelaxed() const noexcept
void storeRelease(Type newValue) noexcept
\inmodule QtCore
Definition qproperty.h:809
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
qsizetype indexOf(char c, qsizetype from=0) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
qsizetype lastIndexOf(char c, qsizetype from=-1) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
\inmodule QtCore
Definition qcoreevent.h:372
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
static void removePostedEvents(QObject *receiver, int eventType=0)
static void postEvent(QObject *receiver, QEvent *event, int priority=Qt::NormalEventPriority)
\inmodule QtCore
\inmodule QtCore
\inmodule QtCore
Definition qcoreevent.h:45
@ MetaCall
Definition qcoreevent.h:97
@ ChildPolished
Definition qcoreevent.h:107
@ ChildRemoved
Definition qcoreevent.h:108
@ DeferredDelete
Definition qcoreevent.h:100
@ ThreadChange
Definition qcoreevent.h:82
@ ChildAdded
Definition qcoreevent.h:106
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
T & first()
Definition qlist.h:628
void removeAt(qsizetype i)
Definition qlist.h:573
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void prepend(rvalue_ref t)
Definition qlist.h:456
void append(parameter_type t)
Definition qlist.h:441
void clear()
Definition qlist.h:417
const void *const * args() const
Definition qobject_p.h:411
QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction, const QObject *sender, int signalId, void **args, QSemaphore *semaphore)
Definition qobject.cpp:535
~QMetaCallEvent() override
Definition qobject.cpp:600
const QMetaType * types() const
Definition qobject_p.h:413
virtual void placeMetaCall(QObject *object) override
Definition qobject.cpp:618
\inmodule QtCore
Definition qmetaobject.h:18
int relativeMethodIndex() const
const QMetaObject * mobj
int methodIndex() const
bool isValid() const
QByteArray methodSignature() const
MethodType methodType() const
Returns the type of this method (signal, slot, or method).
\inmodule QtCore Represents a handle to a signal-slot (or signal-functor) connection.
\inmodule QtCore
\inmodule QtCore
Definition qmetatype.h:320
constexpr TypeFlags flags() const
Definition qmetatype.h:2628
static QMetaType fromName(QByteArrayView name)
Returns a QMetaType matching typeName.
int id(int=0) const
Definition qmetatype.h:454
\inmodule QtCore
Definition qmutex.h:317
void unlock() noexcept
Unlocks this mutex locker.
Definition qmutex.h:323
void relock() noexcept
Relocks an unlocked mutex locker.
Definition qmutex.h:324
\inmodule QtCore
Definition qmutex.h:285
void unlock() noexcept
Unlocks the mutex.
Definition qmutex.h:293
void lock() noexcept
Locks the mutex.
Definition qmutex.h:290
QDynamicMetaObjectData * metaObject
Definition qobject.h:77
uint isDeletingChildren
Definition qobject.h:67
uint isWindow
Definition qobject.h:70
virtual ~QObjectData()=0
Definition qobject.cpp:153
QMetaObject * dynamicMetaObject() const
Definition qobject.cpp:155
uint receiveChildEvents
Definition qobject.h:69
uint wasDeleted
Definition qobject.h:66
QObject * q_ptr
Definition qobject.h:60
uint deleteLaterCalled
Definition qobject.h:71
uint isQuickItem
Definition qobject.h:72
uint isWidget
Definition qobject.h:64
uint sendChildEvents
Definition qobject.h:68
QAtomicInt postedEvents
Definition qobject.h:76
QObjectList children
Definition qobject.h:62
uint blockSig
Definition qobject.h:65
uint wasWidget
Definition qobject.h:74
uint willBeWidget
Definition qobject.h:73
QObject * parent
Definition qobject.h:61
QBindingStorage bindingStorage
Definition qobject.h:78
static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index, const QObject *receiver, void **slot, QtPrivate::QSlotObjectBase *slotObj, int type, const int *types, const QMetaObject *senderMetaObject)
Definition qobject.cpp:5090
ExtraData * extraData
Definition qobject_p.h:196
bool isSignalConnected(uint signalIdx, bool checkDeclarative=true) const
Definition qobject.cpp:450
void ensureConnectionData()
Definition qobject.cpp:284
void moveToThread_helper()
Definition qobject.cpp:1681
void checkForIncompatibleLibraryVersion(int version) const
Definition qobject_p.h:224
void setThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status)
Definition qobject.cpp:1693
QObjectPrivate(int version=QObjectPrivateVersion)
Definition qobject.cpp:160
QAtomicPointer< ConnectionData > connections
Definition qobject_p.h:205
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:153
static QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot, Qt::ConnectionType type=Qt::AutoConnection)
Definition qobject_p.h:298
void(* StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **)
Definition qobject_p.h:108
void addConnection(int signal, Connection *c)
Definition qobject.cpp:303
QObject * currentChildBeingDeleted
Definition qobject_p.h:208
void clearBindingStorage()
Definition qobject.cpp:951
QObjectList receiverList(const char *signal) const
Definition qobject.cpp:251
virtual ~QObjectPrivate()
Definition qobject.cpp:184
void setParent_helper(QObject *)
Definition qobject.cpp:2166
void reinitBindingStorageAfterThreadMove()
Definition qobject.cpp:495
static bool disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot)
Definition qobject_p.h:327
void disconnectNotify(const QMetaMethod &signal)
Definition qobject_p.h:250
void _q_reregisterTimers(void *pointer)
Definition qobject.cpp:1760
virtual std::string flagsForDumping() const
Definition qobject.cpp:4228
bool maybeSignalConnected(uint signalIndex) const
Definition qobject.cpp:476
QtPrivate::QPropertyAdaptorSlotObject * getPropertyAdaptorSlotObject(const QMetaProperty &property)
Definition qobject.cpp:5399
int signalIndex(const char *signalName, const QMetaObject **meta=nullptr) const
Definition qobject.cpp:4074
QObjectList senderList() const
Definition qobject.cpp:272
QAtomicPointer< QThreadData > threadData
Definition qobject_p.h:202
void deleteChildren()
Definition qobject.cpp:2149
static bool removeConnection(Connection *c)
Definition qobject.cpp:5354
bool isSender(const QObject *receiver, const char *signal) const
Definition qobject.cpp:230
bool isDeclarativeSignalConnected(uint signalIdx) const
Definition qobject_p.h:239
\inmodule QtCore
Definition qobject.h:90
int senderSignalIndex() const
Definition qobject.cpp:2563
int startTimer(int interval, Qt::TimerType timerType=Qt::CoarseTimer)
This is an overloaded function that will start a timer of type timerType and a timeout of interval mi...
Definition qobject.cpp:1792
Q_INVOKABLE QObject(QObject *parent=nullptr)
Constructs an object with parent object parent.
Definition qobject.cpp:910
bool isSignalConnected(const QMetaMethod &signal) const
Definition qobject.cpp:2664
virtual ~QObject()
Destroys the object, deleting all its child objects.
Definition qobject.cpp:980
void installEventFilter(QObject *filterObj)
Installs an event filter filterObj on this object.
Definition qobject.cpp:2269
const QObjectList & children() const
Returns a list of child objects.
Definition qobject.h:171
void dumpObjectTree() const
Dumps a tree of children to the debug output.
Definition qobject.cpp:4254
virtual void connectNotify(const QMetaMethod &signal)
Definition qobject.cpp:3347
void dumpObjectInfo() const
Dumps information about signal connections, etc.
Definition qobject.cpp:4268
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:311
void moveToThread(QThread *thread)
Changes the thread affinity for this object and its children.
Definition qobject.cpp:1606
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
QObject * sender() const
Returns a pointer to the object that sent the signal, if called in a slot activated by a signal; othe...
Definition qobject.cpp:2521
virtual void childEvent(QChildEvent *event)
This event handler can be reimplemented in a subclass to receive child events.
Definition qobject.cpp:1471
QString objectName
the name of this object
Definition qobject.h:94
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qobject.cpp:1363
void setParent(QObject *parent)
Makes the object a child of parent.
Definition qobject.cpp:2142
virtual bool eventFilter(QObject *watched, QEvent *event)
Filters events if this object has been installed as an event filter for the watched object.
Definition qobject.cpp:1518
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3099
void removeEventFilter(QObject *obj)
Removes an event filter object obj from this object.
Definition qobject.cpp:2300
virtual void timerEvent(QTimerEvent *event)
This event handler can be reimplemented in a subclass to receive timer events for the object.
Definition qobject.cpp:1433
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1561
QScopedPointer< QObjectData > d_ptr
Definition qobject.h:338
bool blockSignals(bool b) noexcept
If block is true, signals emitted by this object are blocked (i.e., emitting a signal will not invoke...
Definition qobject.cpp:1548
QList< QByteArray > dynamicPropertyNames() const
Definition qobject.cpp:4216
int receivers(const char *signal) const
Returns the number of receivers connected to the signal.
Definition qobject.cpp:2603
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4187
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
Definition qobject.h:114
QBindable< QString > bindableObjectName()
Definition qobject.cpp:1300
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
void killTimer(int id)
Kills the timer with timer identifier, id.
Definition qobject.cpp:1872
void deleteLater()
\threadsafe
Definition qobject.cpp:2352
virtual void disconnectNotify(const QMetaMethod &signal)
Definition qobject.cpp:3382
virtual void customEvent(QEvent *event)
This event handler can be reimplemented in a subclass to receive custom events.
Definition qobject.cpp:1485
void addEvent(const QPostEvent &ev)
Definition qthread.cpp:25
QObject * receiver
Definition qthread_p.h:42
QEvent * event
Definition qthread_p.h:43
\inmodule QtCore \reentrant
\inmodule QtCore \reentrant
QRegularExpressionMatch match(const QString &subject, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
Attempts to match the regular expression against the given subject string, starting at the position o...
\inmodule QtCore
Definition qsemaphore.h:16
void acquire(int n=1)
Tries to acquire n resources guarded by the semaphore.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QByteArray toLatin1() const &
Definition qstring.h:559
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
static Q_AUTOTEST_EXPORT QThreadData * current(bool createIfNecessary=true)
Definition qthread.cpp:1005
QAtomicPointer< QAbstractEventDispatcher > eventDispatcher
Definition qthread_p.h:324
void deref()
Definition qthread.cpp:104
QAtomicPointer< void > threadId
Definition qthread_p.h:323
static QThreadData * get2(QThread *thread)
Definition qthread_p.h:290
QPostEventList postEventList
Definition qthread_p.h:321
bool hasEventDispatcher() const
Definition qthread_p.h:296
void ref()
Definition qthread.cpp:96
QAtomicPointer< QThread > thread
Definition qthread_p.h:322
void removeObjectWithPendingBindingStatusChange(QObject *)
Definition qthread_p.h:269
static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION
Definition qthread.h:154
static QThread * currentThread()
Definition qthread.cpp:966
\inmodule QtCore
Definition qcoreevent.h:359
constexpr size_type size() const noexcept
const T * constData() const
\inmodule QtCore
Definition qvariant.h:64
static QPropertyAdaptorSlotObject * cast(QSlotObjectBase *ptr, int propertyIndex)
double e
auto signalIndex
auto signal
auto mo
[7]
short next
Definition keywords.cpp:445
void(* AddQObjectCallback)(QObject *)
Definition qhooks_p.h:38
void(* RemoveQObjectCallback)(QObject *)
Definition qhooks_p.h:39
@ AddQObject
Definition qhooks_p.h:31
@ RemoveQObject
Definition qhooks_p.h:32
Combined button and popup list for selecting options.
\macro QT_NAMESPACE
bool isAnyBindingEvaluating()
TimerType
@ FindChildrenRecursively
void * HANDLE
ConnectionType
@ SingleShotConnection
@ AutoConnection
@ BlockingQueuedConnection
@ QueuedConnection
@ UniqueConnection
#define Q_BASIC_ATOMIC_INITIALIZER(a)
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
size_t qstrlen(const char *str)
int qstrncmp(const char *str1, const char *str2, size_t len)
#define Q_UNLIKELY(x)
#define Q_LIKELY(x)
#define Q_DECL_COLD_FUNCTION
#define Q_FUNC_INFO
#define qApp
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection * connection
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
static QString methodName(const QDBusIntrospection::Method &method)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define QT_RETHROW
#define QT_CATCH(A)
#define QT_TRY
QT_BEGIN_NAMESPACE quintptr Q_CORE_EXPORT qtHookData[]
Definition qhooks.cpp:9
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
return ret
@ MethodCloned
const char * typeName
static QByteArray msgConnect(const QMetaObject *senderMo, const QByteArray &senderName, const QMetaMethod &signal, const QObject *receiver, int receiverIndex)
Definition qobject.cpp:3639
static void check_and_warn_compat(const QMetaObject *sender, const QMetaMethod &signal, const QMetaObject *receiver, const QMetaMethod &method)
Definition qobject.cpp:2736
void qt_qFindChildren_helper(const QObject *parent, const QString &name, const QMetaObject &mo, QList< void * > *list, Qt::FindChildOptions options)
Definition qobject.cpp:2072
static void dumpRecursive(int level, const QObject *object)
Definition qobject.cpp:4233
static int methodIndexToSignalIndex(const QMetaObject **base, int signal_index)
Definition qobject.cpp:3391
static const char * extract_location(const char *member)
Definition qobject.cpp:2431
Q_CORE_EXPORT QBasicAtomicPointer< QSignalSpyCallbackSet > qt_signal_spy_callback_set
Definition qobject.cpp:62
static bool check_parent_thread(QObject *parent, QThreadData *parentThreadData, QThreadData *currentThreadData)
Definition qobject.cpp:875
static int DIRECT_CONNECTION_ONLY
Definition qobject.cpp:57
static int * queuedConnectionTypes(const QMetaMethod &method)
Definition qobject.cpp:77
static void computeOffsets(const QMetaObject *metaobject, int *signalOffset, int *methodOffset)
Definition qobject.cpp:216
static QBasicMutex * signalSlotLock(const QObject *o)
Definition qobject.cpp:136
void doActivate(QObject *sender, int signal_index, void **argv)
Definition qobject.cpp:3857
static Q_DECL_COLD_FUNCTION void err_method_notfound(const QObject *object, const char *method, const char *func)
Definition qobject.cpp:2471
static bool check_method_code(int code, const QObject *object, const char *method, const char *func)
Definition qobject.cpp:2458
void qt_register_signal_spy_callbacks(QSignalSpyCallbackSet *callback_set)
Definition qobject.cpp:64
static Q_CONSTINIT QBasicMutex _q_ObjectMutexPool[131]
Definition qobject.cpp:130
static int extract_code(const char *member)
Definition qobject.cpp:2425
static QByteArray formatConnectionSignature(const char *className, const QMetaMethod &method)
Definition qobject.cpp:3621
static void connectWarning(const QObject *sender, const QMetaObject *senderMetaObject, const QObject *receiver, const char *message)
Definition qobject.cpp:5070
const char * qFlagLocation(const char *method)
Definition qobject.cpp:2419
static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv)
Definition qobject.cpp:3792
static bool check_signal_macro(const QObject *sender, const char *signal, const char *func, const char *op)
Definition qobject.cpp:2442
QObject * qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options)
Definition qobject.cpp:2121
static Q_DECL_COLD_FUNCTION void err_info_about_objects(const char *func, const QObject *sender, const QObject *receiver)
Definition qobject.cpp:2489
static void qt_qFindChildren_with_name(const QObject *parent, const QString &name, const QMetaObject &mo, QList< void * > *list, Qt::FindChildOptions options)
Definition qobject.cpp:2054
Q_CORE_EXPORT QBasicAtomicPointer< QSignalSpyCallbackSet > qt_signal_spy_callback_set
Definition qobject.cpp:62
void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o)
Definition qobject.cpp:4876
#define QSIGNAL_CODE
Definition qobjectdefs.h:41
#define Q_ARG(Type, data)
Definition qobjectdefs.h:62
#define QSLOT_CODE
Definition qobjectdefs.h:40
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLint location
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLuint64 GLenum void * handle
GLint GLenum GLsizei GLsizei GLsizei depth
const GLfloat * m
GLenum GLuint GLint level
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLboolean r
[2]
GLsizei GLenum GLenum * types
GLenum GLenum GLsizei count
GLuint object
[3]
GLenum type
GLuint GLsizei const GLchar * message
GLint ref
GLuint name
GLfloat n
GLsizei GLenum GLsizei GLsizei GLuint memory
struct _cl_event * event
GLhandleARB obj
[2]
GLenum func
Definition qopenglext.h:663
GLuint res
const GLubyte * c
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const void * pointer
Definition qopenglext.h:384
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLuint const GLint * locations
static Q_CONSTINIT thread_local QBindingStatus bindingStatus
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition qscopeguard.h:60
#define qPrintable(string)
Definition qstring.h:1391
#define qUtf16Printable(string)
Definition qstring.h:1403
#define sp
#define emit
#define Q_UNUSED(x)
#define Q_HAS_TRACEPOINTS
Definition qtrace_p.h:143
#define Q_TRACE_SCOPE(x,...)
Definition qtrace_p.h:146
#define Q_TRACE(x,...)
Definition qtrace_p.h:144
#define Q_TRACE_POINT(provider, tracepoint,...)
Definition qtrace_p.h:232
size_t quintptr
Definition qtypes.h:72
unsigned int uint
Definition qtypes.h:29
unsigned short ushort
Definition qtypes.h:28
const char property[13]
Definition qwizard.cpp:101
const char className[16]
[1]
Definition qwizard.cpp:100
#define explicit
QList< int > list
[14]
Q_CHECK_PTR(a=new int[80])
QRandomGenerator64 rd
[10]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QDataStream & operator<<(QDataStream &out, const MyClass &myObj)
[4]
QObject::connect nullptr
MyCustomStruct c2
QReadWriteLock lock
[0]
QSharedPointer< T > other(t)
[5]
QLayoutItem * child
[0]
QAction * at
view create()
QJSValueList args
virtual QMetaObject * toDynamicMetaObject(QObject *)=0
virtual void objectDestroyed(QObject *)
Definition qobject_p.h:453
virtual ~QDynamicMetaObjectData()
Definition qobject.cpp:69
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition qlist.h:955
static int signalOffset(const QMetaObject *m)
static QObjectPrivate::Connection * connect(const QObject *sender, int signal_index, const QMetaObject *smeta, const QObject *receiver, int method_index_relative, const QMetaObject *rmeta=nullptr, int type=0, int *types=nullptr)
Definition qobject.cpp:3439
static bool disconnect(const QObject *sender, int signal_index, const QMetaObject *smeta, const QObject *receiver, int method_index, void **slot, DisconnectType=DisconnectAll)
Definition qobject.cpp:3574
static Q_CORE_EXPORT QMetaMethod signal(const QMetaObject *m, int signal_index)
static int indexOfMethod(const QMetaObject *m, const QByteArray &name, int argc, const QArgumentType *types)
static void memberIndexes(const QObject *obj, const QMetaMethod &member, int *signalIndex, int *methodIndex)
Definition qobject.cpp:2706
static QByteArray decodeMethodSignature(const char *signature, QArgumentTypeArray &types)
static Q_CORE_EXPORT int absoluteSignalCount(const QMetaObject *m)
static const QMetaObjectPrivate * get(const QMetaObject *metaobject)
static bool disconnectHelper(QObjectPrivate::ConnectionData *connections, int signalIndex, const QObject *receiver, int method_index, void **slot, QBasicMutex *senderMutex, DisconnectType=DisconnectAll)
Definition qobject.cpp:3534
static int indexOfSignalRelative(const QMetaObject **baseObject, const QByteArray &name, int argc, const QArgumentType *types)
static int originalClone(const QMetaObject *obj, int local_method_index)
static bool checkConnectArgs(int signalArgc, const QArgumentType *signalTypes, int methodArgc, const QArgumentType *methodTypes)
static int indexOfSlotRelative(const QMetaObject **m, const QByteArray &name, int argc, const QArgumentType *types)
StaticMetacallFunction static_metacall
SuperData superdata
\inmodule QtCore
QMetaProperty property(int index) const
Returns the meta-data for the property with the given index.
const char * className() const
Returns the class name.
static bool disconnectOne(const QObject *sender, int signal_index, const QObject *receiver, int method_index)
Definition qobject.cpp:3520
static bool disconnect(const QObject *sender, int signal_index, const QObject *receiver, int method_index)
Definition qobject.cpp:3504
static int metacall(QObject *, Call, int, void **)
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...
static QByteArray normalizedSignature(const char *method)
Normalizes the signature of the given method.
static void connectSlotsByName(QObject *o)
Searches recursively for all child objects of the given object, and connects matching signals from th...
Definition qobject.cpp:3670
static Connection connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type=0, int *types=nullptr)
Definition qobject.cpp:3419
int static_metacall(Call, int, void **) const
int indexOfProperty(const char *name) const
Finds property name and returns its index; otherwise returns -1.
int methodOffset() const
Returns the method offset for this class; i.e.
const QMetaObject * superClass() const
Returns the meta-object of the superclass, or \nullptr if there is no such object.
struct QMetaObject::Data d
QMetaMethod method(int index) const
Returns the meta-data for the method with the given index.
static bool checkConnectArgs(const char *signal, const char *method)
Returns true if the signal and method arguments are compatible; otherwise returns false.
static void activate(QObject *sender, int signal_index, void **argv)
Definition qobject.cpp:4057
std::atomic< TaggedSignalVector > orphaned
QAtomicInteger< uint > currentConnectionId
ConnectionList & connectionsForSignal(int signal)
void removeConnection(Connection *c)
Definition qobject.cpp:331
void resizeSignalVector(uint size)
static void deleteOrphaned(TaggedSignalVector o)
Definition qobject.cpp:425
void cleanOrphanedConnections(QObject *sender, LockPolicy lockPolicy=NeedToLock)
void cleanOrphanedConnectionsImpl(QObject *sender, LockPolicy lockPolicy)
Definition qobject.cpp:397
QAtomicPointer< SignalVector > signalVector
QAtomicPointer< Connection > last
Definition qobject_p_p.h:32
QAtomicPointer< Connection > first
Definition qobject_p_p.h:31
QAtomicPointer< const int > argumentTypes
Definition qobject_p_p.h:84
QAtomicPointer< QObject > receiver
Definition qobject_p_p.h:78
QtPrivate::QSlotObjectBase * slotObj
Definition qobject_p_p.h:82
QList< int > runningTimers
Definition qobject_p.h:94
ConnectionList & at(int i)
BeginCallback slot_begin_callback
Definition qobject_p.h:53
EndCallback slot_end_callback
Definition qobject_p.h:55
EndCallback signal_end_callback
Definition qobject_p.h:54
BeginCallback signal_begin_callback
Definition qobject_p.h:52
QtPrivate::QSlotObjectBase * operator->()
Definition qobject.cpp:3776
QtPrivate::QSlotObjectBase const * operator->() const
Definition qobject.cpp:3773
SlotObjectGuard()=default
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent