Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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 <qvarlengtharray.h>
26#include <qscopeguard.h>
27#include <qset.h>
28#if QT_CONFIG(thread)
29#include <qsemaphore.h>
30#endif
31
32#include <private/qorderedmutexlocker_p.h>
33#include <private/qhooks_p.h>
34#include <qtcore_tracepoints_p.h>
35
36#include <new>
37#include <mutex>
38#include <memory>
39
40#include <ctype.h>
41#include <limits.h>
42
44
45Q_TRACE_POINT(qtcore, QObject_ctor, QObject *object);
46Q_TRACE_POINT(qtcore, QObject_dtor, QObject *object);
47Q_TRACE_POINT(qtcore, QMetaObject_activate_entry, QObject *sender, int signalIndex);
48Q_TRACE_POINT(qtcore, QMetaObject_activate_exit);
49Q_TRACE_POINT(qtcore, QMetaObject_activate_slot_entry, QObject *receiver, int slotIndex);
50Q_TRACE_POINT(qtcore, QMetaObject_activate_slot_exit);
51Q_TRACE_POINT(qtcore, QMetaObject_activate_slot_functor_entry, void *slotObject);
52Q_TRACE_POINT(qtcore, QMetaObject_activate_slot_functor_exit);
53Q_TRACE_POINT(qtcore, QMetaObject_activate_declarative_signal_entry, QObject *sender, int signalIndex);
54Q_TRACE_POINT(qtcore, QMetaObject_activate_declarative_signal_exit);
55
57
58Q_LOGGING_CATEGORY(lcConnectSlotsByName, "qt.core.qmetaobject.connectslotsbyname")
59Q_LOGGING_CATEGORY(lcConnect, "qt.core.qobject.connect")
60
62
64{
65 qt_signal_spy_callback_set.storeRelease(callback_set);
66}
67
71
75
77{
78 const auto parameterCount = method.parameterCount();
79 int *typeIds = new int[parameterCount + 1];
80 Q_CHECK_PTR(typeIds);
81 for (int i = 0; i < parameterCount; ++i) {
82 const QMetaType metaType = method.parameterMetaType(i);
83 if (metaType.flags() & QMetaType::IsPointer)
84 typeIds[i] = QMetaType::VoidStar;
85 else
86 typeIds[i] = metaType.id();
87 if (!typeIds[i] && method.parameterTypeName(i).endsWith('*'))
88 typeIds[i] = QMetaType::VoidStar;
89 if (!typeIds[i]) {
90 const QByteArray typeName = method.parameterTypeName(i);
91 qCWarning(lcConnect,
92 "QObject::connect: Cannot queue arguments of type '%s'\n"
93 "(Make sure '%s' is registered using qRegisterMetaType().)",
94 typeName.constData(), typeName.constData());
95 delete[] typeIds;
96 return nullptr;
97 }
98 }
99 typeIds[parameterCount] = 0;
100
101 return typeIds;
102}
103
104static int *queuedConnectionTypes(const QArgumentType *argumentTypes, int argc)
105{
106 auto types = std::make_unique<int[]>(argc + 1);
107 for (int i = 0; i < argc; ++i) {
108 const QArgumentType &type = argumentTypes[i];
109 if (type.type())
110 types[i] = type.type();
111 else if (type.name().endsWith('*'))
112 types[i] = QMetaType::VoidStar;
113 else
114 types[i] = QMetaType::fromName(type.name()).id();
115
116 if (!types[i]) {
117 qCWarning(lcConnect,
118 "QObject::connect: Cannot queue arguments of type '%s'\n"
119 "(Make sure '%s' is registered using qRegisterMetaType().)",
120 type.name().constData(), type.name().constData());
121 return nullptr;
122 }
123 }
124 types[argc] = 0;
125
126 return types.release();
127}
128
129Q_CONSTINIT static QBasicMutex _q_ObjectMutexPool[131];
130
135static inline QBasicMutex *signalSlotLock(const QObject *o)
136{
137 return &_q_ObjectMutexPool[uint(quintptr(o)) % sizeof(_q_ObjectMutexPool)/sizeof(QBasicMutex)];
138}
139
145
153
158
160 : threadData(nullptr), currentChildBeingDeleted(nullptr)
161{
163
164 // QObjectData initialization
165 q_ptr = nullptr;
166 parent = nullptr; // no parent yet. It is set by setParent()
167 isWidget = false; // assume not a widget object
168 blockSig = false; // not blocking signals
169 wasDeleted = false; // double-delete catcher
170 isDeletingChildren = false; // set by deleteChildren()
171 sendChildEvents = true; // if we should send ChildAdded and ChildRemoved events to parent
172 receiveChildEvents = true;
173 postedEvents = 0;
174 extraData = nullptr;
175 metaObject = nullptr;
176 isWindow = false;
177 deleteLaterCalled = false;
178 isQuickItem = false;
179 willBeWidget = false;
180 wasWidget = false;
181 receiveParentEvents = false; // If object wants ParentAboutToChange and ParentChange
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 (auto id : std::as_const(extraData->runningTimers))
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
231{
232 QObjectList returnValue;
233 int signal_index = signalIndex(signal);
234 ConnectionData *cd = connections.loadAcquire();
235 if (signal_index < 0 || !cd)
236 return returnValue;
237 if (signal_index < cd->signalVectorCount()) {
238 const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
239
240 while (c) {
241 QObject *r = c->receiver.loadRelaxed();
242 if (r)
243 returnValue << r;
244 c = c->nextConnectionList.loadRelaxed();
245 }
246 }
247 return returnValue;
248}
249
255{
256 if (connections.loadRelaxed())
257 return;
259 cd->ref.ref();
260 connections.storeRelease(cd);
261}
262
274{
275 Q_ASSERT(c->sender == q_ptr);
277 ConnectionData *cd = connections.loadRelaxed();
278 cd->resizeSignalVector(signal + 1);
279
280 ConnectionList &connectionList = cd->connectionsForSignal(signal);
281 if (connectionList.last.loadRelaxed()) {
282 Q_ASSERT(connectionList.last.loadRelaxed()->receiver.loadRelaxed());
283 connectionList.last.loadRelaxed()->nextConnectionList.storeRelaxed(c);
284 } else {
285 connectionList.first.storeRelaxed(c);
286 }
287 c->id = ++cd->currentConnectionId;
288 c->prevConnectionList = connectionList.last.loadRelaxed();
289 connectionList.last.storeRelaxed(c);
290
291 QObjectPrivate *rd = QObjectPrivate::get(c->receiver.loadRelaxed());
292 rd->ensureConnectionData();
293
294 c->prev = &(rd->connections.loadRelaxed()->senders);
295 c->next = *c->prev;
296 *c->prev = c;
297 if (c->next)
298 c->next->prev = &c->next;
299}
300
302{
303 Q_ASSERT(c->receiver.loadRelaxed());
304 ConnectionList &connections = signalVector.loadRelaxed()->at(c->signal_index);
305 c->receiver.storeRelaxed(nullptr);
306 QThreadData *td = c->receiverThreadData.loadRelaxed();
307 if (td)
308 td->deref();
309 c->receiverThreadData.storeRelaxed(nullptr);
310
311#ifndef QT_NO_DEBUG
312 bool found = false;
313 for (Connection *cc = connections.first.loadRelaxed(); cc; cc = cc->nextConnectionList.loadRelaxed()) {
314 if (cc == c) {
315 found = true;
316 break;
317 }
318 }
319 Q_ASSERT(found);
320#endif
321
322 // remove from the senders linked list
323 *c->prev = c->next;
324 if (c->next)
325 c->next->prev = c->prev;
326 c->prev = nullptr;
327
328 if (connections.first.loadRelaxed() == c)
329 connections.first.storeRelaxed(c->nextConnectionList.loadRelaxed());
330 if (connections.last.loadRelaxed() == c)
331 connections.last.storeRelaxed(c->prevConnectionList);
332 Q_ASSERT(signalVector.loadRelaxed()->at(c->signal_index).first.loadRelaxed() != c);
333 Q_ASSERT(signalVector.loadRelaxed()->at(c->signal_index).last.loadRelaxed() != c);
334
335 // keep c->nextConnectionList intact, as it might still get accessed by activate
336 Connection *n = c->nextConnectionList.loadRelaxed();
337 if (n)
338 n->prevConnectionList = c->prevConnectionList;
339 if (c->prevConnectionList)
340 c->prevConnectionList->nextConnectionList.storeRelaxed(n);
341 c->prevConnectionList = nullptr;
342
343 Q_ASSERT(c != static_cast<Connection *>(orphaned.load(std::memory_order_relaxed)));
344 // add c to orphanedConnections
345 TaggedSignalVector o = nullptr;
346 /* No ABA issue here: When adding a node, we only care about the list head, it doesn't
347 * matter if the tail changes.
348 */
349 o = orphaned.load(std::memory_order_acquire);
350 do {
351 c->nextInOrphanList = o;
352 } while (!orphaned.compare_exchange_strong(o, TaggedSignalVector(c), std::memory_order_release));
353
354#ifndef QT_NO_DEBUG
355 found = false;
356 for (Connection *cc = connections.first.loadRelaxed(); cc; cc = cc->nextConnectionList.loadRelaxed()) {
357 if (cc == c) {
358 found = true;
359 break;
360 }
361 }
362 Q_ASSERT(!found);
363#endif
364
365}
366
368{
369 QBasicMutex *senderMutex = signalSlotLock(sender);
370 TaggedSignalVector c = nullptr;
371 {
372 std::unique_lock<QBasicMutex> lock(*senderMutex, std::defer_lock_t{});
373 if (lockPolicy == NeedToLock)
374 lock.lock();
375 if (ref.loadAcquire() > 1)
376 return;
377
378 // Since ref == 1, no activate() is in process since we locked the mutex. That implies,
379 // that nothing can reference the orphaned connection objects anymore and they can
380 // be safely deleted
381 c = orphaned.exchange(nullptr, std::memory_order_relaxed);
382 }
383 if (c) {
384 // Deleting c might run arbitrary user code, so we must not hold the lock
385 if (lockPolicy == AlreadyLockedAndTemporarilyReleasingLock) {
386 senderMutex->unlock();
387 deleteOrphaned(c);
388 senderMutex->lock();
389 } else {
390 deleteOrphaned(c);
391 }
392 }
393}
394
396{
397 while (o) {
398 TaggedSignalVector next = nullptr;
399 if (SignalVector *v = static_cast<SignalVector *>(o)) {
400 next = v->nextInOrphanList;
401 free(v);
402 } else {
403 QObjectPrivate::Connection *c = static_cast<Connection *>(o);
404 next = c->nextInOrphanList;
405 Q_ASSERT(!c->receiver.loadRelaxed());
406 Q_ASSERT(!c->prev);
407 c->freeSlotObject();
408 c->deref();
409 }
410 o = next;
411 }
412}
413
420bool QObjectPrivate::isSignalConnected(uint signalIndex, bool checkDeclarative) const
421{
422 if (checkDeclarative && isDeclarativeSignalConnected(signalIndex))
423 return true;
424
425 ConnectionData *cd = connections.loadAcquire();
426 if (!cd)
427 return false;
428 SignalVector *signalVector = cd->signalVector.loadRelaxed();
429 if (!signalVector)
430 return false;
431
432 if (signalVector->at(-1).first.loadRelaxed())
433 return true;
434
435 if (signalIndex < uint(cd->signalVectorCount())) {
436 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadRelaxed();
437 while (c) {
438 if (c->receiver.loadRelaxed())
439 return true;
440 c = c->nextConnectionList.loadRelaxed();
441 }
442 }
443 return false;
444}
445
447{
448 ConnectionData *cd = connections.loadAcquire();
449 if (!cd)
450 return false;
451 SignalVector *signalVector = cd->signalVector.loadRelaxed();
452 if (!signalVector)
453 return false;
454
455 if (signalVector->at(-1).first.loadAcquire())
456 return true;
457
458 if (signalIndex < uint(cd->signalVectorCount())) {
459 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadAcquire();
460 return c != nullptr;
461 }
462 return false;
463}
464
466{
467 bindingStorage.reinitAfterThreadMove();
468 for (int i = 0; i < children.size(); ++i)
469 children[i]->d_func()->reinitBindingStorageAfterThreadMove();
470}
471
476{
477#if QT_CONFIG(thread)
478 if (semaphore_)
479 semaphore_->release();
480#endif
481}
482
486inline void QMetaCallEvent::allocArgs()
487{
488 if (!d.nargs_)
489 return;
490
491 constexpr size_t each = sizeof(void*) + sizeof(QMetaType);
492 void *const memory = d.nargs_ * each > sizeof(prealloc_) ?
493 calloc(d.nargs_, each) : prealloc_;
494
496 d.args_ = static_cast<void **>(memory);
497}
498
505QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative,
507 const QObject *sender, int signalId,
508 void **args, QSemaphore *semaphore)
509 : QAbstractMetaCallEvent(sender, signalId, semaphore),
510 d({nullptr, args, callFunction, 0, method_offset, method_relative}),
511 prealloc_()
512{
513}
514
522 const QObject *sender, int signalId,
523 void **args, QSemaphore *semaphore)
524 : QAbstractMetaCallEvent(sender, signalId, semaphore),
525 d({QtPrivate::SlotObjUniquePtr{slotO}, args, nullptr, 0, 0, ushort(-1)}),
526 prealloc_()
527{
528 if (d.slotObj_)
529 d.slotObj_->ref();
530}
531
539 const QObject *sender, int signalId,
540 void **args, QSemaphore *semaphore)
541 : QAbstractMetaCallEvent(sender, signalId, semaphore),
542 d{std::move(slotO), args, nullptr, 0, 0, ushort(-1)},
543 prealloc_()
544{
545}
546
553QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative,
555 const QObject *sender, int signalId,
556 int nargs)
557 : QAbstractMetaCallEvent(sender, signalId),
558 d({nullptr, nullptr, callFunction, nargs, method_offset, method_relative}),
559 prealloc_()
560{
561 allocArgs();
562}
563
571 const QObject *sender, int signalId,
572 int nargs)
573 : QAbstractMetaCallEvent(sender, signalId),
574 d({QtPrivate::SlotObjUniquePtr(slotO), nullptr, nullptr, nargs, 0, ushort(-1)}),
575 prealloc_()
576{
577 if (d.slotObj_)
578 d.slotObj_->ref();
579 allocArgs();
580}
581
589 const QObject *sender, int signalId,
590 int nargs)
591 : QAbstractMetaCallEvent(sender, signalId),
592 d{std::move(slotO), nullptr, nullptr, nargs, 0, ushort(-1)},
593 prealloc_()
594{
595 allocArgs();
596}
597
602{
603 if (d.nargs_) {
604 QMetaType *t = types();
605 for (int i = 0; i < d.nargs_; ++i) {
606 if (t[i].isValid() && d.args_[i])
607 t[i].destroy(d.args_[i]);
608 }
609 if (reinterpret_cast<void *>(d.args_) != reinterpret_cast<void *>(prealloc_))
610 free(d.args_);
611 }
612}
613
618{
619 if (d.slotObj_) {
620 d.slotObj_->call(object, d.args_);
621 } else if (d.callFunction_ && d.method_offset_ <= object->metaObject()->methodOffset()) {
622 d.callFunction_(object, QMetaObject::InvokeMetaMethod, d.method_relative_, d.args_);
623 } else {
625 d.method_offset_ + d.method_relative_, d.args_);
626 }
627}
628
629QMetaCallEvent* QMetaCallEvent::create_impl(QtPrivate::SlotObjUniquePtr slotObj,
630 const QObject *sender, int signal_index,
631 size_t argc, const void* const argp[],
632 const QMetaType metaTypes[])
633{
634 auto metaCallEvent = std::make_unique<QMetaCallEvent>(std::move(slotObj), sender,
635 signal_index, int(argc));
636
637 void **args = metaCallEvent->args();
638 QMetaType *types = metaCallEvent->types();
639 for (size_t i = 0; i < argc; ++i) {
640 types[i] = metaTypes[i];
641 args[i] = types[i].create(argp[i]);
642 Q_CHECK_PTR(!i || args[i]);
643 }
644
645 return metaCallEvent.release();
646}
647
896/*****************************************************************************
897 QObject member functions
898 *****************************************************************************/
899
900// check the constructor's parent thread argument
901static bool check_parent_thread(QObject *parent,
902 QThreadData *parentThreadData,
903 QThreadData *currentThreadData)
904{
905 if (parent && parentThreadData != currentThreadData) {
906 QThread *parentThread = parentThreadData->thread.loadAcquire();
907 QThread *currentThread = currentThreadData->thread.loadAcquire();
908 qWarning("QObject: Cannot create children for a parent that is in a different thread.\n"
909 "(Parent is %s(%p), parent's thread is %s(%p), current thread is %s(%p)",
910 parent->metaObject()->className(),
911 parent,
912 parentThread ? parentThread->metaObject()->className() : "QThread",
913 parentThread,
914 currentThread ? currentThread->metaObject()->className() : "QThread",
915 currentThread);
916 return false;
917 }
918 return true;
919}
920
937 : QObject(*new QObjectPrivate, parent)
938{
939}
940
945 : d_ptr(&dd)
946{
947 Q_ASSERT_X(this != parent, Q_FUNC_INFO, "Cannot parent a QObject to itself");
948
949 Q_D(QObject);
950 d_ptr->q_ptr = this;
951 auto threadData = (parent && !parent->thread()) ? parent->d_func()->threadData.loadRelaxed() : QThreadData::current();
952 threadData->ref();
953 d->threadData.storeRelaxed(threadData);
954 if (parent) {
955 QT_TRY {
956 if (!check_parent_thread(parent, parent ? parent->d_func()->threadData.loadRelaxed() : nullptr, threadData))
957 parent = nullptr;
958 if (d->willBeWidget) {
959 if (parent) {
960 d->parent = parent;
961 d->parent->d_func()->children.append(this);
962 }
963 // no events sent here, this is done at the end of the QWidget constructor
964 } else {
966 }
967 } QT_CATCH(...) {
968 threadData->deref();
970 }
971 }
974 Q_TRACE(QObject_ctor, this);
975}
976
981
1007{
1008 Q_D(QObject);
1009 d->wasDeleted = true;
1010 d->blockSig = 0; // unblock signals so we always emit destroyed()
1011
1012 if (!d->bindingStorage.isValid()) {
1013 // this might be the case after an incomplete thread-move
1014 // remove this object from the pending list in that case
1015 if (QThread *ownThread = thread()) {
1016 auto *privThread = static_cast<QThreadPrivate *>(
1017 QObjectPrivate::get(ownThread));
1019 }
1020 }
1021
1022 // If we reached this point, we need to clear the binding data
1023 // as the corresponding properties are no longer useful
1024 d->clearBindingStorage();
1025
1026 QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.loadRelaxed();
1027 if (sharedRefcount) {
1028 if (sharedRefcount->strongref.loadRelaxed() > 0) {
1029 qWarning("QObject: shared QObject was deleted directly. The program is malformed and may crash.");
1030 // but continue deleting, it's too late to stop anyway
1031 }
1032
1033 // indicate to all QWeakPointers that this QObject has now been deleted
1034 sharedRefcount->strongref.storeRelaxed(0);
1035 if (!sharedRefcount->weakref.deref())
1036 delete sharedRefcount;
1037 }
1038
1039 if (!d->wasWidget && d->isSignalConnected(0)) {
1040 emit destroyed(this);
1041 }
1042
1043 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::destroyed)
1044 QAbstractDeclarativeData::destroyed(d->declarativeData, this);
1045
1046 QObjectPrivate::ConnectionData *cd = d->connections.loadAcquire();
1047 if (cd) {
1048 if (cd->currentSender) {
1050 cd->currentSender = nullptr;
1051 }
1052
1053 QBasicMutex *signalSlotMutex = signalSlotLock(this);
1054 QMutexLocker locker(signalSlotMutex);
1055
1056 // disconnect all receivers
1057 int receiverCount = cd->signalVectorCount();
1058 for (int signal = -1; signal < receiverCount; ++signal) {
1060
1061 while (QObjectPrivate::Connection *c = connectionList.first.loadRelaxed()) {
1062 Q_ASSERT(c->receiver.loadAcquire());
1063
1064 QBasicMutex *m = signalSlotLock(c->receiver.loadRelaxed());
1065 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1066 if (c == connectionList.first.loadAcquire() && c->receiver.loadAcquire()) {
1067 cd->removeConnection(c);
1068 Q_ASSERT(connectionList.first.loadRelaxed() != c);
1069 }
1070 if (needToUnlock)
1071 m->unlock();
1072 }
1073 }
1074
1075 /* Disconnect all senders:
1076 */
1077 while (QObjectPrivate::Connection *node = cd->senders) {
1078 Q_ASSERT(node->receiver.loadAcquire());
1079 QObject *sender = node->sender;
1080 // Send disconnectNotify before removing the connection from sender's connection list.
1081 // This ensures any eventual destructor of sender will block on getting receiver's lock
1082 // and not finish until we release it.
1083 sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), node->signal_index));
1085 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1086 //the node has maybe been removed while the mutex was unlocked in relock?
1087 if (node != cd->senders) {
1088 // We hold the wrong mutex
1089 Q_ASSERT(needToUnlock);
1090 m->unlock();
1091 continue;
1092 }
1093
1094 QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections.loadRelaxed();
1095 Q_ASSERT(senderData);
1096
1097 QtPrivate::QSlotObjectBase *slotObj = nullptr;
1098 if (node->isSlotObject) {
1099 slotObj = node->slotObj;
1100 node->isSlotObject = false;
1101 }
1102
1103 senderData->removeConnection(node);
1104 /*
1105 When we unlock, another thread has the chance to delete/modify sender data.
1106 Thus we need to call cleanOrphanedConnections before unlocking. We use the
1107 variant of the function which assumes that the lock is already held to avoid
1108 a deadlock.
1109 We need to hold m, the sender lock. Considering that we might execute arbitrary user
1110 code, we should already release the signalSlotMutex here – unless they are the same.
1111 */
1112 const bool locksAreTheSame = signalSlotMutex == m;
1113 if (!locksAreTheSame)
1114 locker.unlock();
1115 senderData->cleanOrphanedConnections(
1116 sender,
1118 );
1119 if (needToUnlock)
1120 m->unlock();
1121
1122 if (locksAreTheSame) // otherwise already unlocked
1123 locker.unlock();
1124 if (slotObj)
1125 slotObj->destroyIfLastRef();
1126 locker.relock();
1127 }
1128
1129 // invalidate all connections on the object and make sure
1130 // activate() will skip them
1132 }
1133 if (cd && !cd->ref.deref())
1134 delete cd;
1135 d->connections.storeRelaxed(nullptr);
1136
1137 if (!d->children.isEmpty())
1138 d->deleteChildren();
1139
1142
1143 Q_TRACE(QObject_dtor, this);
1144
1145 if (d->parent) // remove it from parent object
1146 d->setParent_helper(nullptr);
1147}
1148
1150{
1151 if (ownArgumentTypes) {
1152 const int *v = argumentTypes.loadRelaxed();
1153 if (v != &DIRECT_CONNECTION_ONLY)
1154 delete[] v;
1155 }
1156 if (isSlotObject)
1158}
1159
1160
1276{
1277 Q_D(const QObject);
1278#if QT_CONFIG(thread)
1279 if (QThread::currentThreadId() != d->threadData.loadRelaxed()->threadId.loadRelaxed()) // Unsafe code path
1280 return d->extraData ? d->extraData->objectName.valueBypassingBindings() : QString();
1281#endif
1282 if (!d->extraData && QtPrivate::isAnyBindingEvaluating()) {
1283 QObjectPrivate *dd = const_cast<QObjectPrivate *>(d);
1284 // extraData is mutable, so this should be safe
1286 }
1287 return d->extraData ? d->extraData->objectName : QString();
1288}
1289
1294void QObject::doSetObjectName(const QString &name)
1295{
1296 Q_D(QObject);
1297
1298 d->ensureExtraData();
1299
1300 d->extraData->objectName.removeBindingUnlessInWrapper();
1301
1302 if (d->extraData->objectName.valueBypassingBindings() != name) {
1303 d->extraData->objectName.setValueBypassingBindings(name);
1304 d->extraData->objectName.notify(); // also emits a signal
1305 }
1306}
1307
1313{
1314 Q_D(QObject);
1315
1316 d->ensureExtraData();
1317
1318 d->extraData->objectName.removeBindingUnlessInWrapper();
1319
1320 if (d->extraData->objectName.valueBypassingBindings() != name) {
1321 d->extraData->objectName.setValueBypassingBindings(name.toString());
1322 d->extraData->objectName.notify(); // also emits a signal
1323 }
1324}
1325
1327{
1328 Q_D(QObject);
1329
1330 d->ensureExtraData();
1331
1332 return QBindable<QString>(&d->extraData->objectName);
1333}
1334
1390{
1391 switch (e->type()) {
1392 case QEvent::Timer:
1393 timerEvent((QTimerEvent *)e);
1394 break;
1395
1396 case QEvent::ChildAdded:
1399 childEvent((QChildEvent *)e);
1400 break;
1401
1403 qCDebug(lcDeleteLater) << "Deferred deleting" << this;
1404 delete this;
1405 break;
1406
1407 case QEvent::MetaCall:
1408 {
1409 QAbstractMetaCallEvent *mce = static_cast<QAbstractMetaCallEvent*>(e);
1410
1411 QObjectPrivate::ConnectionData *connections = d_func()->connections.loadAcquire();
1412 if (!connections) {
1413 QMutexLocker locker(signalSlotLock(this));
1414 d_func()->ensureConnectionData();
1415 connections = d_func()->connections.loadRelaxed();
1416 }
1417 QObjectPrivate::Sender sender(this, const_cast<QObject*>(mce->sender()), mce->signalId(), connections);
1418
1419 mce->placeMetaCall(this);
1420 break;
1421 }
1422
1423 case QEvent::ThreadChange: {
1424 Q_D(QObject);
1425 QThreadData *threadData = d->threadData.loadRelaxed();
1426 QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
1427 if (eventDispatcher) {
1428 QList<QAbstractEventDispatcher::TimerInfoV2> timers = eventDispatcher->timersForObject(this);
1429 if (!timers.isEmpty()) {
1430 const bool res = eventDispatcher->unregisterTimers(this);
1431 // do not to release our timer ids back to the pool (since the timer ids are moving to a new thread).
1433 "QAbstractEventDispatcher::unregisterTimers() returned false,"
1434 " but there are timers associated with this object.");
1435 auto reRegisterTimers = [this, timers = std::move(timers)]() {
1436 QAbstractEventDispatcher *eventDispatcher =
1437 d_func()->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
1438 for (const auto &ti : timers)
1439 eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType, this);
1440 };
1441 QMetaObject::invokeMethod(this, std::move(reRegisterTimers), Qt::QueuedConnection);
1442 }
1443 }
1444 break;
1445 }
1446
1447 default:
1448 if (e->type() >= QEvent::User) {
1449 customEvent(e);
1450 break;
1451 }
1452 return false;
1453 }
1454 return true;
1455}
1456
1473
1474
1509{
1510}
1511
1512
1522void QObject::customEvent(QEvent * /* event */)
1523{
1524}
1525
1526
1527
1555bool QObject::eventFilter(QObject * /* watched */, QEvent * /* event */)
1556{
1557 return false;
1558}
1559
1585bool QObject::blockSignals(bool block) noexcept
1586{
1587 Q_D(QObject);
1588 bool previous = d->blockSig;
1589 d->blockSig = block;
1590 return previous;
1591}
1592
1599{
1600 return d_func()->threadData.loadRelaxed()->thread.loadAcquire();
1601}
1602
1644{
1645 Q_D(QObject);
1646
1647 if (d->threadData.loadRelaxed()->thread.loadAcquire() == targetThread) {
1648 // object is already in this thread
1649 return true;
1650 }
1651
1652 if (d->parent != nullptr) {
1653 qWarning("QObject::moveToThread: Cannot move objects with a parent");
1654 return false;
1655 }
1656 if (d->isWidget) {
1657 qWarning("QObject::moveToThread: Widgets cannot be moved to a new thread");
1658 return false;
1659 }
1660 if (!d->bindingStorage.isEmpty()) {
1661 qWarning("QObject::moveToThread: Can not move objects that contain bindings or are used in bindings to a new thread.");
1662 return false;
1663 }
1664
1665 QThreadData *currentData = QThreadData::current();
1666 QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : nullptr;
1667 QThreadData *thisThreadData = d->threadData.loadAcquire();
1668 if (!thisThreadData->thread.loadRelaxed() && currentData == targetData) {
1669 // one exception to the rule: we allow moving objects with no thread affinity to the current thread
1670 currentData = thisThreadData;
1671 } else if (thisThreadData != currentData) {
1672 qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
1673 "Cannot move to target thread (%p)\n",
1674 currentData->thread.loadRelaxed(), thisThreadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() : nullptr);
1675
1676#ifdef Q_OS_DARWIN
1677 qWarning("You might be loading two sets of Qt binaries into the same process. "
1678 "Check that all plugins are compiled against the right Qt binaries. Export "
1679 "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.");
1680#endif
1681
1682 return false;
1683 }
1684
1685 // prepare to move
1686 d->moveToThread_helper();
1687
1688 if (!targetData)
1689 targetData = new QThreadData(0);
1690
1691 // make sure nobody adds/removes connections to this object while we're moving it
1693
1694 QOrderedMutexLocker locker(&currentData->postEventList.mutex,
1695 &targetData->postEventList.mutex);
1696
1697 // keep currentData alive (since we've got it locked)
1698 currentData->ref();
1699
1700 // move the object
1701 auto threadPrivate = targetThread
1702 ? static_cast<QThreadPrivate *>(QThreadPrivate::get(targetThread))
1703 : nullptr;
1704 QBindingStatus *bindingStatus = threadPrivate
1705 ? threadPrivate->bindingStatus()
1706 : nullptr;
1707 if (threadPrivate && !bindingStatus) {
1708 bindingStatus = threadPrivate->addObjectWithPendingBindingStatusChange(this);
1709 }
1710 d_func()->setThreadData_helper(currentData, targetData, bindingStatus);
1711
1712 locker.unlock();
1713
1714 // now currentData can commit suicide if it wants to
1715 currentData->deref();
1716 return true;
1717}
1718
1720{
1721 Q_Q(QObject);
1724 bindingStorage.clear();
1725 for (int i = 0; i < children.size(); ++i) {
1727 child->d_func()->moveToThread_helper();
1728 }
1729}
1730
1732{
1733 Q_Q(QObject);
1734
1735 if (status) {
1736 // the new thread is already running
1737 this->bindingStorage.bindingStatus = status;
1738 }
1739
1740 // move posted events
1741 int eventsMoved = 0;
1742 for (int i = 0; i < currentData->postEventList.size(); ++i) {
1743 const QPostEvent &pe = currentData->postEventList.at(i);
1744 if (!pe.event)
1745 continue;
1746 if (pe.receiver == q) {
1747 // move this post event to the targetList
1748 targetData->postEventList.addEvent(pe);
1749 const_cast<QPostEvent &>(pe).event = nullptr;
1750 ++eventsMoved;
1751 }
1752 }
1753 if (eventsMoved > 0 && targetData->hasEventDispatcher()) {
1754 targetData->canWait = false;
1755 targetData->eventDispatcher.loadRelaxed()->wakeUp();
1756 }
1757
1758 // the current emitting thread shouldn't restore currentSender after calling moveToThread()
1759 ConnectionData *cd = connections.loadAcquire();
1760 if (cd) {
1761 if (cd->currentSender) {
1763 cd->currentSender = nullptr;
1764 }
1765
1766 // adjust the receiverThreadId values in the Connections
1767 if (cd) {
1768 auto *c = cd->senders;
1769 while (c) {
1770 QObject *r = c->receiver.loadRelaxed();
1771 if (r) {
1772 Q_ASSERT(r == q);
1773 targetData->ref();
1774 QThreadData *old = c->receiverThreadData.loadRelaxed();
1775 if (old)
1776 old->deref();
1777 c->receiverThreadData.storeRelaxed(targetData);
1778 }
1779 c = c->next;
1780 }
1781 }
1782
1783 }
1784
1785 // set new thread data
1786 targetData->ref();
1787 threadData.loadRelaxed()->deref();
1788
1789 // synchronizes with loadAcquire e.g. in QCoreApplication::postEvent
1790 threadData.storeRelease(targetData);
1791
1792 for (int i = 0; i < children.size(); ++i) {
1794 child->d_func()->setThreadData_helper(currentData, targetData, status);
1795 }
1796}
1797
1798//
1799// The timer flag hasTimer is set when startTimer is called.
1800// It is not reset when killing the timer because more than
1801// one timer might be active.
1802//
1803
1817int QObject::startTimer(int interval, Qt::TimerType timerType)
1818{
1819 // no overflow can happen here:
1820 // 2^31 ms * 1,000,000 always fits a 64-bit signed integer type
1821 return startTimer(std::chrono::milliseconds{interval}, timerType);
1822}
1823
1875int QObject::startTimer(std::chrono::nanoseconds interval, Qt::TimerType timerType)
1876{
1877 Q_D(QObject);
1878
1879 using namespace std::chrono_literals;
1880
1881 if (Q_UNLIKELY(interval < 0ns)) {
1882 qWarning("QObject::startTimer: Timers cannot have negative intervals");
1883 return 0;
1884 }
1885
1886 auto thisThreadData = d->threadData.loadRelaxed();
1887 if (Q_UNLIKELY(!thisThreadData->hasEventDispatcher())) {
1888 qWarning("QObject::startTimer: Timers can only be used with threads started with QThread");
1889 return 0;
1890 }
1891 if (Q_UNLIKELY(thread() != QThread::currentThread())) {
1892 qWarning("QObject::startTimer: Timers cannot be started from another thread");
1893 return 0;
1894 }
1895
1896 auto dispatcher = thisThreadData->eventDispatcher.loadRelaxed();
1897 Qt::TimerId timerId = dispatcher->registerTimer(interval, timerType, this);
1898 d->ensureExtraData();
1899 d->extraData->runningTimers.append(timerId);
1900 return int(timerId);
1901}
1902
1913{
1914 killTimer(Qt::TimerId{id});
1915}
1916
1922{
1923 Q_D(QObject);
1924 if (Q_UNLIKELY(thread() != QThread::currentThread())) {
1925 qWarning("QObject::killTimer: Timers cannot be stopped from another thread");
1926 return;
1927 }
1928 if (id > Qt::TimerId::Invalid) {
1929 int at = d->extraData ? d->extraData->runningTimers.indexOf(id) : -1;
1930 if (at == -1) {
1931 // timer isn't owned by this object
1932 qWarning("QObject::killTimer(): Error: timer id %d is not valid for object %p (%s, %ls), timer has not been killed",
1933 qToUnderlying(id),
1934 this,
1935 metaObject()->className(),
1936 qUtf16Printable(objectName()));
1937 return;
1938 }
1939
1940 auto thisThreadData = d->threadData.loadRelaxed();
1941 if (thisThreadData->hasEventDispatcher())
1942 thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimer(id);
1943
1944 d->extraData->runningTimers.remove(at);
1946 }
1947}
1948
2128{
2129 if (auto ext = QObjectPrivate::get(obj)->extraData)
2130 return ext ->objectName.valueBypassingBindings() == name;
2131 return name.isEmpty();
2132}
2133
2138 const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
2139{
2141 Q_ASSERT(list);
2142 for (QObject *obj : parent->children()) {
2143 if (mo.cast(obj) && (name.isNull() || matches_objectName_non_null(obj, name)))
2144 list->append(obj);
2145 if (options & Qt::FindChildrenRecursively)
2146 qt_qFindChildren_helper(obj, name, mo, list, options);
2147 }
2148}
2149
2150#if QT_CONFIG(regularexpression)
2155 const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
2156{
2158 Q_ASSERT(list);
2159 for (QObject *obj : parent->children()) {
2160 if (mo.cast(obj)) {
2161 QRegularExpressionMatch m = re.match(obj->objectName());
2162 if (m.hasMatch())
2163 list->append(obj);
2164 }
2165 if (options & Qt::FindChildrenRecursively)
2166 qt_qFindChildren_helper(obj, re, mo, list, options);
2167 }
2168}
2169#endif // QT_CONFIG(regularexpression)
2170
2174QObject *qt_qFindChild_helper(const QObject *parent, QAnyStringView name, const QMetaObject &mo, Qt::FindChildOptions options)
2175{
2177 for (QObject *obj : parent->children()) {
2178 if (mo.cast(obj) && (name.isNull() || matches_objectName_non_null(obj, name)))
2179 return obj;
2180 }
2181 if (options & Qt::FindChildrenRecursively) {
2182 for (QObject *child : parent->children()) {
2183 if (QObject *obj = qt_qFindChild_helper(child, name, mo, options))
2184 return obj;
2185 }
2186 }
2187 return nullptr;
2188}
2189
2196{
2197 Q_D(QObject);
2198 Q_ASSERT(!d->isWidget);
2199 d->setParent_helper(parent);
2200}
2201
2203{
2204 Q_ASSERT_X(!isDeletingChildren, "QObjectPrivate::deleteChildren()", "isDeletingChildren already set, did this function recurse?");
2205 isDeletingChildren = true;
2206 // delete children objects
2207 // don't use qDeleteAll as the destructor of the child might
2208 // delete siblings
2209 for (int i = 0; i < children.size(); ++i) {
2211 children[i] = nullptr;
2213 }
2214 children.clear();
2215 currentChildBeingDeleted = nullptr;
2216 isDeletingChildren = false;
2217}
2218
2220{
2221 Q_Q(QObject);
2222 Q_ASSERT_X(q != o, Q_FUNC_INFO, "Cannot parent a QObject to itself");
2223#ifdef QT_DEBUG
2224 const auto checkForParentChildLoops = qScopeGuard([&](){
2225 int depth = 0;
2226 auto p = parent;
2227 while (p) {
2228 if (++depth == CheckForParentChildLoopsWarnDepth) {
2229 qWarning("QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
2230 "this is undefined behavior",
2231 q, q->metaObject()->className(), qPrintable(q->objectName()));
2232 }
2233 p = p->parent();
2234 }
2235 });
2236#endif
2237
2238 if (o == parent)
2239 return;
2240
2241 if (parent) {
2242 QObjectPrivate *parentD = parent->d_func();
2243 if (parentD->isDeletingChildren && wasDeleted
2244 && parentD->currentChildBeingDeleted == q) {
2245 // don't do anything since QObjectPrivate::deleteChildren() already
2246 // cleared our entry in parentD->children.
2247 } else {
2248 const int index = parentD->children.indexOf(q);
2249 if (index < 0) {
2250 // we're probably recursing into setParent() from a ChildRemoved event, don't do anything
2251 } else if (parentD->isDeletingChildren) {
2252 parentD->children[index] = nullptr;
2253 } else {
2254 parentD->children.removeAt(index);
2255 if (sendChildEvents && parentD->receiveChildEvents) {
2258 }
2259 }
2260 }
2261 }
2262
2263 if (receiveParentEvents) {
2264 Q_ASSERT(!isWidget); // Handled in QWidget
2267 }
2268
2269 parent = o;
2270
2271 if (parent) {
2272 // object hierarchies are constrained to a single thread
2273 if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) {
2274 qWarning("QObject::setParent: Cannot set parent, new parent is in a different thread");
2275 parent = nullptr;
2276 return;
2277 }
2278 parent->d_func()->children.append(q);
2279 if (sendChildEvents && parent->d_func()->receiveChildEvents) {
2280 if (!isWidget) {
2283 }
2284 }
2285 }
2286
2287 if (receiveParentEvents) {
2288 Q_ASSERT(!isWidget); // Handled in QWidget
2291 }
2292}
2293
2340{
2341 Q_D(QObject);
2342 if (!obj)
2343 return;
2344 if (d->threadData.loadRelaxed() != obj->d_func()->threadData.loadRelaxed()) {
2345 qWarning("QObject::installEventFilter(): Cannot filter events for objects in a different thread.");
2346 return;
2347 }
2348
2349 d->ensureExtraData();
2350
2351 // clean up unused items in the list along the way:
2352 auto isNullOrEquals = [](auto obj) { return [obj](const auto &p) { return !p || p == obj; }; };
2353 d->extraData->eventFilters.removeIf(isNullOrEquals(obj));
2354 d->extraData->eventFilters.prepend(obj);
2355}
2356
2371{
2372 Q_D(QObject);
2373 if (d->extraData) {
2374 for (auto &filter : d->extraData->eventFilters) {
2375 if (filter == obj) {
2376 filter = nullptr;
2377 break;
2378 }
2379 }
2380 }
2381}
2382
2436{
2437#ifdef QT_DEBUG
2438 if (qApp == this)
2439 qWarning("You are deferring the delete of QCoreApplication, this may not work as expected.");
2440#endif
2441
2442
2443 // De-bounce QDeferredDeleteEvents. Use the post event list mutex
2444 // to guard access to deleteLaterCalled, so we don't need a separate
2445 // mutex in QObjectData.
2446 auto eventListLocker = QCoreApplicationPrivate::lockThreadPostEventList(this);
2447 if (!eventListLocker.threadData)
2448 return;
2449
2450 // FIXME: The deleteLaterCalled flag is part of a bit field,
2451 // so we likely have data races here, even with the mutex above,
2452 // as long as we're not guarding every access to the bit field.
2453
2454 Q_D(QObject);
2455 if (d->deleteLaterCalled) {
2456 qCDebug(lcDeleteLater) << "Skipping deleteLater for already deferred object" << this;
2457 return;
2458 }
2459
2460 d->deleteLaterCalled = true;
2461
2462 int loopLevel = 0;
2463 int scopeLevel = 0;
2464
2465 auto *objectThreadData = eventListLocker.threadData;
2466 if (objectThreadData == QThreadData::current()) {
2467 // Remember the current running eventloop for deleteLater
2468 // calls in the object's own thread.
2469
2470 // Events sent by non-Qt event handlers (such as glib) may not
2471 // have the scopeLevel set correctly. The scope level makes sure that
2472 // code like this:
2473 // foo->deleteLater();
2474 // qApp->processEvents(); // without passing QEvent::DeferredDelete
2475 // will not cause "foo" to be deleted before returning to the event loop.
2476
2477 loopLevel = objectThreadData->loopLevel;
2478 scopeLevel = objectThreadData->scopeLevel;
2479
2480 // If the scope level is 0 while loopLevel != 0, we are called from a
2481 // non-conformant code path, and our best guess is that the scope level
2482 // should be 1. (Loop level 0 is special: it means that no event loops
2483 // are running.)
2484 if (scopeLevel == 0 && loopLevel != 0) {
2485 qCDebug(lcDeleteLater) << "Delete later called with scope level 0"
2486 << "but loop level is > 0. Assuming scope is 1";
2487 scopeLevel = 1;
2488 }
2489 }
2490
2491 qCDebug(lcDeleteLater) << "Posting deferred delete for" << this
2492 << "with loop level" << loopLevel << "and scope level" << scopeLevel;
2493
2494 eventListLocker.unlock();
2496 new QDeferredDeleteEvent(loopLevel, scopeLevel));
2497}
2498
2534/*****************************************************************************
2535 Signals and slots
2536 *****************************************************************************/
2537
2538namespace {
2539// This class provides (per-thread) storage for qFlagLocation()
2540class FlaggedDebugSignatures
2541{
2542 uint idx = 0;
2543 std::array<const char *, 2> locations = {}; // one for the SIGNAL, one for the SLOT
2544
2545public:
2546 void store(const char* method) noexcept
2547 { locations[idx++ % locations.size()] = method; }
2548
2549 bool contains(const char *method) const noexcept
2550 { return std::find(locations.begin(), locations.end(), method) != locations.end(); }
2551};
2552
2553Q_CONSTINIT static thread_local FlaggedDebugSignatures flaggedSignatures = {};
2554} // unnamed namespace
2555
2556const char *qFlagLocation(const char *method)
2557{
2558 flaggedSignatures.store(method);
2559 return method;
2560}
2561
2562static int extract_code(const char *member)
2563{
2564 // extract code, ensure QMETHOD_CODE <= code <= QSIGNAL_CODE
2565 return (((int)(*member) - '0') & 0x3);
2566}
2567
2568static const char *extract_location(const char *member)
2569{
2570 if (flaggedSignatures.contains(member)) {
2571 // signature includes location information after the first null-terminator
2572 const char *location = member + qstrlen(member) + 1;
2573 if (*location != '\0')
2574 return location;
2575 }
2576 return nullptr;
2577}
2578
2579static bool check_signal_macro(const QObject *sender, const char *signal,
2580 const char *func, const char *op)
2581{
2582 int sigcode = extract_code(signal);
2583 if (sigcode != QSIGNAL_CODE) {
2584 if (sigcode == QSLOT_CODE)
2585 qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s", func, op,
2586 sender->metaObject()->className(), signal + 1);
2587 else
2588 qCWarning(lcConnect, "QObject::%s: Use the SIGNAL macro to %s %s::%s", func, op,
2589 sender->metaObject()->className(), signal);
2590 return false;
2591 }
2592 return true;
2593}
2594
2595static bool check_method_code(int code, const QObject *object, const char *method, const char *func)
2596{
2597 if (code != QSLOT_CODE && code != QSIGNAL_CODE) {
2598 qCWarning(lcConnect,
2599 "QObject::%s: Use the SLOT or SIGNAL macro to "
2600 "%s %s::%s",
2601 func, func, object->metaObject()->className(), method);
2602 return false;
2603 }
2604 return true;
2605}
2606
2608static void err_method_notfound(const QObject *object,
2609 const char *method, const char *func)
2610{
2611 const char *type = "method";
2612 switch (extract_code(method)) {
2613 case QSLOT_CODE: type = "slot"; break;
2614 case QSIGNAL_CODE: type = "signal"; break;
2615 }
2616 const char *loc = extract_location(method);
2617 if (strchr(method, ')') == nullptr) // common typing mistake
2618 qCWarning(lcConnect, "QObject::%s: Parentheses expected, %s %s::%s%s%s", func, type,
2619 object->metaObject()->className(), method + 1, loc ? " in " : "", loc ? loc : "");
2620 else
2621 qCWarning(lcConnect, "QObject::%s: No such %s %s::%s%s%s", func, type,
2622 object->metaObject()->className(), method + 1, loc ? " in " : "", loc ? loc : "");
2623}
2624
2626static void err_info_about_objects(const char *func, const QObject *sender, const QObject *receiver)
2627{
2628 QString a = sender ? sender->objectName() : QString();
2629 QString b = receiver ? receiver->objectName() : QString();
2630 if (!a.isEmpty())
2631 qCWarning(lcConnect, "QObject::%s: (sender name: '%s')", func, a.toLocal8Bit().data());
2632 if (!b.isEmpty())
2633 qCWarning(lcConnect, "QObject::%s: (receiver name: '%s')", func, b.toLocal8Bit().data());
2634}
2635
2659{
2660 Q_D(const QObject);
2661
2662 QMutexLocker locker(signalSlotLock(this));
2663 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2664 if (!cd || !cd->currentSender)
2665 return nullptr;
2666
2667 for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2668 if (c->sender == cd->currentSender->sender)
2669 return cd->currentSender->sender;
2670 }
2671
2672 return nullptr;
2673}
2674
2701{
2702 Q_D(const QObject);
2703
2704 QMutexLocker locker(signalSlotLock(this));
2705 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2706 if (!cd || !cd->currentSender)
2707 return -1;
2708
2709 for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2710 if (c->sender == cd->currentSender->sender) {
2711 // Convert from signal range to method range
2712 return QMetaObjectPrivate::signal(c->sender->metaObject(), cd->currentSender->signal).methodIndex();
2713 }
2714 }
2715
2716 return -1;
2717}
2718
2740int QObject::receivers(const char *signal) const
2741{
2742 Q_D(const QObject);
2743 int receivers = 0;
2744 if (signal) {
2746 signal = signal_name;
2747#ifndef QT_NO_DEBUG
2748 if (!check_signal_macro(this, signal, "receivers", "bind"))
2749 return 0;
2750#endif
2751 signal++; // skip code
2752 int signal_index = d->signalIndex(signal);
2753 if (signal_index < 0) {
2754#ifndef QT_NO_DEBUG
2755 err_method_notfound(this, signal - 1, "receivers");
2756#endif
2757 return 0;
2758 }
2759
2760 if (!d->isSignalConnected(signal_index))
2761 return receivers;
2762
2763 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::receivers) {
2764 receivers += QAbstractDeclarativeData::receivers(d->declarativeData, this,
2765 signal_index);
2766 }
2767
2768 QMutexLocker locker(signalSlotLock(this));
2769 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2770 if (cd && signal_index < cd->signalVectorCount()) {
2771 const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
2772 while (c) {
2773 receivers += c->receiver.loadRelaxed() ? 1 : 0;
2774 c = c->nextConnectionList.loadRelaxed();
2775 }
2776 }
2777 }
2778 return receivers;
2779}
2780
2802{
2803 Q_D(const QObject);
2804 if (!signal.mobj)
2805 return false;
2806
2807 Q_ASSERT_X(signal.mobj->cast(this) && signal.methodType() == QMetaMethod::Signal,
2808 "QObject::isSignalConnected" , "the parameter must be a signal member of the object");
2809 uint signalIndex = signal.relativeMethodIndex();
2810
2811 if (signal.data.flags() & MethodCloned)
2813
2815
2816 QMutexLocker locker(signalSlotLock(this));
2817 return d->isSignalConnected(signalIndex, true);
2818}
2819
2844 const QMetaMethod &member,
2845 int *signalIndex, int *methodIndex)
2846{
2847 *signalIndex = -1;
2848 *methodIndex = -1;
2849 if (!obj || !member.mobj)
2850 return;
2851 const QMetaObject *m = obj->metaObject();
2852 // Check that member is member of obj class
2853 while (m != nullptr && m != member.mobj)
2854 m = m->d.superdata;
2855 if (!m)
2856 return;
2857 *signalIndex = *methodIndex = member.relativeMethodIndex();
2858
2859 int signalOffset;
2860 int methodOffset;
2861 computeOffsets(m, &signalOffset, &methodOffset);
2862
2863 *methodIndex += methodOffset;
2864 if (member.methodType() == QMetaMethod::Signal) {
2865 *signalIndex = originalClone(m, *signalIndex);
2866 *signalIndex += signalOffset;
2867 } else {
2868 *signalIndex = -1;
2869 }
2870}
2871
2872#ifndef QT_NO_DEBUG
2873static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaMethod &signal,
2874 const QMetaObject *receiver, const QMetaMethod &method)
2875{
2876 if (signal.attributes() & QMetaMethod::Compatibility) {
2877 if (!(method.attributes() & QMetaMethod::Compatibility))
2878 qCWarning(lcConnect, "QObject::connect: Connecting from COMPAT signal (%s::%s)",
2879 sender->className(), signal.methodSignature().constData());
2880 } else if ((method.attributes() & QMetaMethod::Compatibility)
2881 && method.methodType() == QMetaMethod::Signal) {
2882 qCWarning(lcConnect, "QObject::connect: Connecting from %s::%s to COMPAT slot (%s::%s)",
2883 sender->className(), signal.methodSignature().constData(), receiver->className(),
2884 method.methodSignature().constData());
2885 }
2886}
2887#endif
2888
2961 const QObject *receiver, const char *method,
2963{
2964 if (sender == nullptr || receiver == nullptr || signal == nullptr || method == nullptr) {
2965 qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
2966 sender ? sender->metaObject()->className() : "(nullptr)",
2967 (signal && *signal) ? signal + 1 : "(nullptr)",
2968 receiver ? receiver->metaObject()->className() : "(nullptr)",
2969 (method && *method) ? method + 1 : "(nullptr)");
2970 return QMetaObject::Connection(nullptr);
2971 }
2972 QByteArray tmp_signal_name;
2973
2974 if (!check_signal_macro(sender, signal, "connect", "bind"))
2975 return QMetaObject::Connection(nullptr);
2976 const QMetaObject *smeta = sender->metaObject();
2977 const char *signal_arg = signal;
2978 ++signal; // skip code
2979 QArgumentTypeArray signalTypes;
2980 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
2983 &smeta, signalName, signalTypes.size(), signalTypes.constData());
2984 if (signal_index < 0) {
2985 // check for normalized signatures
2986 tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
2987 signal = tmp_signal_name.constData() + 1;
2988
2989 signalTypes.clear();
2990 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
2991 smeta = sender->metaObject();
2993 &smeta, signalName, signalTypes.size(), signalTypes.constData());
2994 }
2995 if (signal_index < 0) {
2996 err_method_notfound(sender, signal_arg, "connect");
2997 err_info_about_objects("connect", sender, receiver);
2998 return QMetaObject::Connection(nullptr);
2999 }
3000 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3001 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3002
3003 QByteArray tmp_method_name;
3004 int membcode = extract_code(method);
3005
3006 if (!check_method_code(membcode, receiver, method, "connect"))
3007 return QMetaObject::Connection(nullptr);
3008 const char *method_arg = method;
3009 ++method; // skip code
3010
3011 QArgumentTypeArray methodTypes;
3013 const QMetaObject *rmeta = receiver->metaObject();
3014 int method_index_relative = -1;
3015 Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
3016 switch (membcode) {
3017 case QSLOT_CODE:
3018 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3019 &rmeta, methodName, methodTypes.size(), methodTypes.constData());
3020 break;
3021 case QSIGNAL_CODE:
3022 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3023 &rmeta, methodName, methodTypes.size(), methodTypes.constData());
3024 break;
3025 }
3026 if (method_index_relative < 0) {
3027 // check for normalized methods
3028 tmp_method_name = QMetaObject::normalizedSignature(method);
3029 method = tmp_method_name.constData();
3030
3031 methodTypes.clear();
3033 // rmeta may have been modified above
3034 rmeta = receiver->metaObject();
3035 switch (membcode) {
3036 case QSLOT_CODE:
3037 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3038 &rmeta, methodName, methodTypes.size(), methodTypes.constData());
3039 break;
3040 case QSIGNAL_CODE:
3041 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3042 &rmeta, methodName, methodTypes.size(), methodTypes.constData());
3043 break;
3044 }
3045 }
3046
3047 if (method_index_relative < 0) {
3048 err_method_notfound(receiver, method_arg, "connect");
3049 err_info_about_objects("connect", sender, receiver);
3050 return QMetaObject::Connection(nullptr);
3051 }
3052
3053 if (!QMetaObjectPrivate::checkConnectArgs(signalTypes.size(), signalTypes.constData(),
3054 methodTypes.size(), methodTypes.constData())) {
3055 qCWarning(lcConnect,
3056 "QObject::connect: Incompatible sender/receiver arguments"
3057 "\n %s::%s --> %s::%s",
3058 sender->metaObject()->className(), signal, receiver->metaObject()->className(),
3059 method);
3060 return QMetaObject::Connection(nullptr);
3061 }
3062
3063 int *types = nullptr;
3064 if ((type == Qt::QueuedConnection)
3065 && !(types = queuedConnectionTypes(signalTypes.constData(), signalTypes.size()))) {
3066 return QMetaObject::Connection(nullptr);
3067 }
3068
3069#ifndef QT_NO_DEBUG
3070 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3071 QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
3072 check_and_warn_compat(smeta, smethod, rmeta, rmethod);
3073#endif
3075 sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
3076 return handle;
3077}
3078
3100 const QObject *receiver, const QMetaMethod &method,
3102{
3103 if (sender == nullptr
3104 || receiver == nullptr
3105 || signal.methodType() != QMetaMethod::Signal
3106 || method.methodType() == QMetaMethod::Constructor) {
3107 qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
3108 sender ? sender->metaObject()->className() : "(nullptr)",
3109 signal.methodSignature().constData(),
3110 receiver ? receiver->metaObject()->className() : "(nullptr)",
3111 method.methodSignature().constData());
3112 return QMetaObject::Connection(nullptr);
3113 }
3114
3115 int signal_index;
3116 int method_index;
3117 {
3118 int dummy;
3119 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3120 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3121 }
3122
3123 const QMetaObject *smeta = sender->metaObject();
3124 const QMetaObject *rmeta = receiver->metaObject();
3125 if (signal_index == -1) {
3126 qCWarning(lcConnect, "QObject::connect: Can't find signal %s on instance of class %s",
3127 signal.methodSignature().constData(), smeta->className());
3128 return QMetaObject::Connection(nullptr);
3129 }
3130 if (method_index == -1) {
3131 qCWarning(lcConnect, "QObject::connect: Can't find method %s on instance of class %s",
3132 method.methodSignature().constData(), rmeta->className());
3133 return QMetaObject::Connection(nullptr);
3134 }
3135
3136 if (!QMetaObject::checkConnectArgs(signal.methodSignature().constData(),
3137 method.methodSignature().constData())) {
3138 qCWarning(lcConnect,
3139 "QObject::connect: Incompatible sender/receiver arguments"
3140 "\n %s::%s --> %s::%s",
3141 smeta->className(), signal.methodSignature().constData(), rmeta->className(),
3142 method.methodSignature().constData());
3143 return QMetaObject::Connection(nullptr);
3144 }
3145
3146 int *types = nullptr;
3148 return QMetaObject::Connection(nullptr);
3149
3150#ifndef QT_NO_DEBUG
3151 check_and_warn_compat(smeta, signal, rmeta, method);
3152#endif
3154 sender, signal_index, signal.enclosingMetaObject(), receiver, method_index, nullptr, type, types));
3155 return handle;
3156}
3157
3236bool QObject::disconnect(const QObject *sender, const char *signal,
3237 const QObject *receiver, const char *method)
3238{
3239 if (sender == nullptr || (receiver == nullptr && method != nullptr)) {
3240 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
3241 return false;
3242 }
3243
3244 const char *signal_arg = signal;
3245 QByteArray signal_name;
3246 bool signal_found = false;
3247 if (signal) {
3248 QT_TRY {
3250 signal = signal_name.constData();
3251 } QT_CATCH (const std::bad_alloc &) {
3252 // if the signal is already normalized, we can continue.
3253 if (sender->metaObject()->indexOfSignal(signal + 1) == -1)
3254 QT_RETHROW;
3255 }
3256
3257 if (!check_signal_macro(sender, signal, "disconnect", "unbind"))
3258 return false;
3259 signal++; // skip code
3260 }
3261
3262 QByteArray method_name;
3263 const char *method_arg = method;
3264 int membcode = -1;
3265 bool method_found = false;
3266 if (method) {
3267 QT_TRY {
3269 method = method_name.constData();
3270 } QT_CATCH(const std::bad_alloc &) {
3271 // if the method is already normalized, we can continue.
3272 if (receiver->metaObject()->indexOfMethod(method + 1) == -1)
3273 QT_RETHROW;
3274 }
3275
3276 membcode = extract_code(method);
3277 if (!check_method_code(membcode, receiver, method, "disconnect"))
3278 return false;
3279 method++; // skip code
3280 }
3281
3282 /* We now iterate through all the sender's and receiver's meta
3283 * objects in order to also disconnect possibly shadowed signals
3284 * and slots with the same signature.
3285 */
3286 bool res = false;
3287 const QMetaObject *smeta = sender->metaObject();
3288 QByteArray signalName;
3289 QArgumentTypeArray signalTypes;
3290 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3291 if (signal)
3292 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3294 QArgumentTypeArray methodTypes;
3295 Q_ASSERT(!receiver || QMetaObjectPrivate::get(receiver->metaObject())->revision >= 7);
3296 if (method)
3298 do {
3299 int signal_index = -1;
3300 if (signal) {
3302 &smeta, signalName, signalTypes.size(), signalTypes.constData());
3303 if (signal_index < 0)
3304 break;
3305 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3306 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3307 signal_found = true;
3308 }
3309
3310 if (!method) {
3311 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1, nullptr);
3312 } else {
3313 const QMetaObject *rmeta = receiver->metaObject();
3314 do {
3315 int method_index = QMetaObjectPrivate::indexOfMethod(
3316 rmeta, methodName, methodTypes.size(), methodTypes.constData());
3317 if (method_index >= 0)
3318 while (method_index < rmeta->methodOffset())
3319 rmeta = rmeta->superClass();
3320 if (method_index < 0)
3321 break;
3322 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index, nullptr);
3323 method_found = true;
3324 } while ((rmeta = rmeta->superClass()));
3325 }
3326 } while (signal && (smeta = smeta->superClass()));
3327
3328 if (signal && !signal_found) {
3329 err_method_notfound(sender, signal_arg, "disconnect");
3330 err_info_about_objects("disconnect", sender, receiver);
3331 } else if (method && !method_found) {
3332 err_method_notfound(receiver, method_arg, "disconnect");
3333 err_info_about_objects("disconnect", sender, receiver);
3334 }
3335 if (res) {
3336 if (!signal)
3337 const_cast<QObject *>(sender)->disconnectNotify(QMetaMethod());
3338 }
3339 return res;
3340}
3341
3374 const QObject *receiver, const QMetaMethod &method)
3375{
3376 if (sender == nullptr || (receiver == nullptr && method.mobj != nullptr)) {
3377 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
3378 return false;
3379 }
3380 if (signal.mobj) {
3381 if (signal.methodType() != QMetaMethod::Signal) {
3382 qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s",
3383 "disconnect","unbind",
3384 sender->metaObject()->className(), signal.methodSignature().constData());
3385 return false;
3386 }
3387 }
3388 if (method.mobj) {
3389 if (method.methodType() == QMetaMethod::Constructor) {
3390 qCWarning(lcConnect, "QObject::disconnect: cannot use constructor as argument %s::%s",
3391 receiver->metaObject()->className(), method.methodSignature().constData());
3392 return false;
3393 }
3394 }
3395
3396 int signal_index;
3397 int method_index;
3398 {
3399 int dummy;
3400 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3401 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3402 }
3403 // If we are here sender is not nullptr. If signal is not nullptr while signal_index
3404 // is -1 then this signal is not a member of sender.
3405 if (signal.mobj && signal_index == -1) {
3406 qCWarning(lcConnect, "QObject::disconnect: signal %s not found on class %s",
3407 signal.methodSignature().constData(), sender->metaObject()->className());
3408 return false;
3409 }
3410 // If this condition is true then method is not a member of receiver.
3411 if (receiver && method.mobj && method_index == -1) {
3412 qCWarning(lcConnect, "QObject::disconnect: method %s not found on class %s",
3413 method.methodSignature().constData(), receiver->metaObject()->className());
3414 return false;
3415 }
3416
3417 if (!QMetaObjectPrivate::disconnect(sender, signal_index, signal.mobj, receiver, method_index, nullptr))
3418 return false;
3419
3420 if (!signal.isValid()) {
3421 // The signal is a wildcard, meaning all signals were disconnected.
3422 // QMetaObjectPrivate::disconnect() doesn't call disconnectNotify()
3423 // per connection in this case. Call it once now, with an invalid
3424 // QMetaMethod as argument, as documented.
3425 const_cast<QObject *>(sender)->disconnectNotify(signal);
3426 }
3427 return true;
3428}
3429
3488
3523
3524/*
3525 \internal
3526 convert a signal index from the method range to the signal range
3527 */
3528static int methodIndexToSignalIndex(const QMetaObject **base, int signal_index)
3529{
3530 if (signal_index < 0)
3531 return signal_index;
3532 const QMetaObject *metaObject = *base;
3533 while (metaObject && metaObject->methodOffset() > signal_index)
3534 metaObject = metaObject->superClass();
3535
3536 if (metaObject) {
3537 int signalOffset, methodOffset;
3538 computeOffsets(metaObject, &signalOffset, &methodOffset);
3539 if (signal_index < metaObject->methodCount())
3540 signal_index = QMetaObjectPrivate::originalClone(metaObject, signal_index - methodOffset) + signalOffset;
3541 else
3542 signal_index = signal_index - methodOffset + signalOffset;
3543 *base = metaObject;
3544 }
3545 return signal_index;
3546}
3547
3557 const QObject *receiver, int method_index, int type,
3558 int *types)
3559{
3560 const QMetaObject *smeta = sender->metaObject();
3561 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3562 return Connection(QMetaObjectPrivate::connect(sender, signal_index, smeta,
3563 receiver, method_index,
3564 nullptr, //FIXME, we could speed this connection up by computing the relative index
3565 type, types));
3566}
3567
3577 int signal_index, const QMetaObject *smeta,
3578 const QObject *receiver, int method_index,
3579 const QMetaObject *rmeta, int type, int *types)
3580{
3581 QObject *s = const_cast<QObject *>(sender);
3582 QObject *r = const_cast<QObject *>(receiver);
3583
3584 int method_offset = rmeta ? rmeta->methodOffset() : 0;
3585 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 6);
3586 QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall : nullptr;
3587
3588 QOrderedMutexLocker locker(signalSlotLock(sender),
3589 signalSlotLock(receiver));
3590
3591 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3592 if (type & Qt::UniqueConnection && scd) {
3593 if (scd->signalVectorCount() > signal_index) {
3594 const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
3595
3596 int method_index_absolute = method_index + method_offset;
3597
3598 while (c2) {
3599 if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute)
3600 return nullptr;
3601 c2 = c2->nextConnectionList.loadRelaxed();
3602 }
3603 }
3604 }
3605 type &= ~Qt::UniqueConnection;
3606
3607 const bool isSingleShot = type & Qt::SingleShotConnection;
3608 type &= ~Qt::SingleShotConnection;
3609
3610 Q_ASSERT(type >= 0);
3611 Q_ASSERT(type <= 3);
3612
3613 std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
3614 c->sender = s;
3615 c->signal_index = signal_index;
3616 c->receiver.storeRelaxed(r);
3617 QThreadData *td = r->d_func()->threadData.loadAcquire();
3618 td->ref();
3619 c->receiverThreadData.storeRelaxed(td);
3620 c->method_relative = method_index;
3621 c->method_offset = method_offset;
3622 c->connectionType = type;
3623 c->isSlotObject = false;
3624 c->argumentTypes.storeRelaxed(types);
3625 c->callFunction = callFunction;
3626 c->isSingleShot = isSingleShot;
3627
3628 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
3629
3630 locker.unlock();
3631 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3632 if (smethod.isValid())
3633 s->connectNotify(smethod);
3634
3635 return c.release();
3636}
3637
3641bool QMetaObject::disconnect(const QObject *sender, int signal_index,
3642 const QObject *receiver, int method_index)
3643{
3644 const QMetaObject *smeta = sender->metaObject();
3645 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3646 return QMetaObjectPrivate::disconnect(sender, signal_index, smeta,
3647 receiver, method_index, nullptr);
3648}
3649
3657bool QMetaObject::disconnectOne(const QObject *sender, int signal_index,
3658 const QObject *receiver, int method_index)
3659{
3660 const QMetaObject *smeta = sender->metaObject();
3661 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3662 return QMetaObjectPrivate::disconnect(sender, signal_index, smeta,
3663 receiver, method_index, nullptr,
3665}
3666
3672 const QObject *receiver, int method_index, void **slot,
3673 QBasicMutex *senderMutex, DisconnectType disconnectType)
3674{
3675 bool success = false;
3676
3677 auto &connectionList = connections->connectionsForSignal(signalIndex);
3678 auto *c = connectionList.first.loadRelaxed();
3679 while (c) {
3680 QObject *r = c->receiver.loadRelaxed();
3681 if (r && (receiver == nullptr || (r == receiver
3682 && (method_index < 0 || (!c->isSlotObject && c->method() == method_index))
3683 && (slot == nullptr || (c->isSlotObject && c->slotObj->compare(slot)))))) {
3684 bool needToUnlock = false;
3685 QBasicMutex *receiverMutex = nullptr;
3686 if (r) {
3687 receiverMutex = signalSlotLock(r);
3688 // need to relock this receiver and sender in the correct order
3689 needToUnlock = QOrderedMutexLocker::relock(senderMutex, receiverMutex);
3690 }
3691 if (c->receiver.loadRelaxed())
3692 connections->removeConnection(c);
3693
3694 if (needToUnlock)
3695 receiverMutex->unlock();
3696
3697 success = true;
3698
3699 if (disconnectType == DisconnectOne)
3700 return success;
3701 }
3702 c = c->nextConnectionList.loadRelaxed();
3703 }
3704 return success;
3705}
3706
3712 int signal_index, const QMetaObject *smeta,
3713 const QObject *receiver, int method_index, void **slot,
3714 DisconnectType disconnectType)
3715{
3716 if (!sender)
3717 return false;
3718
3719 QObject *s = const_cast<QObject *>(sender);
3720
3721 QBasicMutex *senderMutex = signalSlotLock(sender);
3722 QMutexLocker locker(senderMutex);
3723
3724 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3725 if (!scd)
3726 return false;
3727
3728 bool success = false;
3729 {
3730 // prevent incoming connections changing the connections->receivers while unlocked
3732
3733 if (signal_index < 0) {
3734 // remove from all connection lists
3735 for (int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
3736 if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
3737 success = true;
3738 }
3739 } else if (signal_index < scd->signalVectorCount()) {
3740 if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
3741 success = true;
3742 }
3743 }
3744
3745 locker.unlock();
3746 if (success) {
3747 scd->cleanOrphanedConnections(s);
3748
3749 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3750 if (smethod.isValid())
3751 s->disconnectNotify(smethod);
3752 }
3753
3754 return success;
3755}
3756
3757// Helpers for formatting the connect statements of connectSlotsByName()'s debug mode
3759{
3760 const auto signature = method.methodSignature();
3761 Q_ASSERT(signature.endsWith(')'));
3762 const int openParen = signature.indexOf('(');
3763 const bool hasParameters = openParen >= 0 && openParen < signature.size() - 2;
3765 if (hasParameters) {
3766 result += "qOverload<"
3767 + signature.mid(openParen + 1, signature.size() - openParen - 2) + ">(";
3768 }
3769 result += '&';
3770 result += className + QByteArrayLiteral("::") + method.name();
3771 if (hasParameters)
3772 result += ')';
3773 return result;
3774}
3775
3776static QByteArray msgConnect(const QMetaObject *senderMo, const QByteArray &senderName,
3777 const QMetaMethod &signal, const QObject *receiver, int receiverIndex)
3778{
3779 const auto receiverMo = receiver->metaObject();
3780 const auto slot = receiverMo->method(receiverIndex);
3781 QByteArray message = QByteArrayLiteral("QObject::connect(")
3782 + senderName + ", " + formatConnectionSignature(senderMo->className(), signal)
3783 + ", " + receiver->objectName().toLatin1() + ", "
3784 + formatConnectionSignature(receiverMo->className(), slot) + ");";
3785 return message;
3786}
3787
3808{
3809 if (!o)
3810 return;
3811 const QMetaObject *mo = o->metaObject();
3812 Q_ASSERT(mo);
3813 const QObjectList list = // list of all objects to look for matching signals including...
3814 o->findChildren<QObject *>() // all children of 'o'...
3815 << o; // and the object 'o' itself
3816
3817 // for each method/slot of o ...
3818 for (int i = 0; i < mo->methodCount(); ++i) {
3819 const QByteArray slotSignature = mo->method(i).methodSignature();
3820 const char *slot = slotSignature.constData();
3821 Q_ASSERT(slot);
3822
3823 // ...that starts with "on_", ...
3824 if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
3825 continue;
3826
3827 // ...we check each object in our list, ...
3828 bool foundIt = false;
3829 for (int j = 0; j < list.size(); ++j) {
3830 const QObject *co = list.at(j);
3831 const QByteArray coName = co->objectName().toLatin1();
3832
3833 // ...discarding those whose objectName is not fitting the pattern "on_<objectName>_...", ...
3834 if (coName.isEmpty() || qstrncmp(slot + 3, coName.constData(), coName.size()) || slot[coName.size()+3] != '_')
3835 continue;
3836
3837 const char *signal = slot + coName.size() + 4; // the 'signal' part of the slot name
3838
3839 // ...for the presence of a matching signal "on_<objectName>_<signal>".
3840 const QMetaObject *smeta;
3841 int sigIndex = co->d_func()->signalIndex(signal, &smeta);
3842 if (sigIndex < 0) {
3843 // if no exactly fitting signal (name + complete parameter type list) could be found
3844 // look for just any signal with the correct name and at least the slot's parameter list.
3845 // Note: if more than one of those signals exist, the one that gets connected is
3846 // chosen 'at random' (order of declaration in source file)
3847 QList<QByteArray> compatibleSignals;
3848 const QMetaObject *smo = co->metaObject();
3849 int sigLen = int(qstrlen(signal)) - 1; // ignore the trailing ')'
3850 for (int k = QMetaObjectPrivate::absoluteSignalCount(smo)-1; k >= 0; --k) {
3852 if (!qstrncmp(method.methodSignature().constData(), signal, sigLen)) {
3853 smeta = method.enclosingMetaObject();
3854 sigIndex = k;
3855 compatibleSignals.prepend(method.methodSignature());
3856 }
3857 }
3858 if (compatibleSignals.size() > 1)
3859 qCWarning(lcConnectSlotsByName) << "QMetaObject::connectSlotsByName: Connecting slot" << slot
3860 << "with the first of the following compatible signals:" << compatibleSignals;
3861 }
3862
3863 if (sigIndex < 0)
3864 continue;
3865
3866 // we connect it...
3867 if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) {
3868 foundIt = true;
3869 qCDebug(lcConnectSlotsByName, "%s",
3870 msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData());
3871 // ...and stop looking for further objects with the same name.
3872 // Note: the Designer will make sure each object name is unique in the above
3873 // 'list' but other code may create two child objects with the same name. In
3874 // this case one is chosen 'at random'.
3875 break;
3876 }
3877 }
3878 if (foundIt) {
3879 // we found our slot, now skip all overloads
3880 while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
3881 ++i;
3882 } else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
3883 // check if the slot has the following signature: "on_..._...(..."
3884 int iParen = slotSignature.indexOf('(');
3885 int iLastUnderscore = slotSignature.lastIndexOf('_', iParen - 1);
3886 if (iLastUnderscore > 3)
3887 qCWarning(lcConnectSlotsByName,
3888 "QMetaObject::connectSlotsByName: No matching signal for %s", slot);
3889 }
3890 }
3891}
3892
3900 SlotObjectGuard() = default;
3901 // move would be fine, but we do not need it currently
3902 Q_DISABLE_COPY_MOVE(SlotObjectGuard)
3904 : m_slotObject(slotObject)
3905 {
3906 if (m_slotObject)
3907 m_slotObject->ref();
3908 }
3909
3911 { return m_slotObject.get(); }
3912
3914 { return m_slotObject.get(); }
3915
3916 ~SlotObjectGuard() = default;
3917private:
3918 QtPrivate::SlotObjUniquePtr m_slotObject;
3919};
3920
3926static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv)
3927{
3928 const int *argumentTypes = c->argumentTypes.loadRelaxed();
3929 if (!argumentTypes) {
3930 QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
3931 argumentTypes = queuedConnectionTypes(m);
3932 if (!argumentTypes) // cannot queue arguments
3933 argumentTypes = &DIRECT_CONNECTION_ONLY;
3934 if (!c->argumentTypes.testAndSetOrdered(nullptr, argumentTypes)) {
3935 if (argumentTypes != &DIRECT_CONNECTION_ONLY)
3936 delete[] argumentTypes;
3937 argumentTypes = c->argumentTypes.loadRelaxed();
3938 }
3939 }
3940 if (argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate
3941 return;
3942 int nargs = 1; // include return type
3943 while (argumentTypes[nargs - 1])
3944 ++nargs;
3945
3946 QMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
3947 QObject *receiver = c->receiver.loadRelaxed();
3948 if (!receiver) {
3949 // the connection has been disconnected before we got the lock
3950 return;
3951 }
3952
3953 SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj : nullptr };
3954 locker.unlock();
3955
3956 QMetaCallEvent *ev = c->isSlotObject ?
3957 new QMetaCallEvent(c->slotObj, sender, signal, nargs) :
3958 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs);
3959
3960 void **args = ev->args();
3961 QMetaType *types = ev->types();
3962
3963 types[0] = QMetaType(); // return type
3964 args[0] = nullptr; // return value
3965
3966 if (nargs > 1) {
3967 for (int n = 1; n < nargs; ++n)
3968 types[n] = QMetaType(argumentTypes[n - 1]);
3969
3970 for (int n = 1; n < nargs; ++n)
3971 args[n] = types[n].create(argv[n]);
3972 }
3973
3974 if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) {
3975 delete ev;
3976 return;
3977 }
3978
3979 locker.relock();
3980 if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
3981 // the connection has been disconnected while we were unlocked
3982 locker.unlock();
3983 delete ev;
3984 return;
3985 }
3986
3987 QCoreApplication::postEvent(receiver, ev);
3988}
3989
3990template <bool callbacks_enabled>
3991void doActivate(QObject *sender, int signal_index, void **argv)
3992{
3994
3995 if (sp->blockSig)
3996 return;
3997
3998 Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
3999
4000 if (sp->isDeclarativeSignalConnected(signal_index)
4002 Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
4003 QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
4004 signal_index, argv);
4005 }
4006
4007 const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() : nullptr;
4008
4009 void *empty_argv[] = { nullptr };
4010 if (!argv)
4011 argv = empty_argv;
4012
4013 if (!sp->maybeSignalConnected(signal_index)) {
4014 // The possible declarative connection is done, and nothing else is connected
4015 if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
4016 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4017 if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
4018 signal_spy_set->signal_end_callback(sender, signal_index);
4019 return;
4020 }
4021
4022 if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
4023 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4024
4025 bool senderDeleted = false;
4026 {
4027 Q_ASSERT(sp->connections.loadRelaxed());
4028 QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadAcquire());
4029 QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();
4030
4032 if (signal_index < signalVector->count())
4033 list = &signalVector->at(signal_index);
4034 else
4035 list = &signalVector->at(-1);
4036
4037 Qt::HANDLE currentThreadId = QThread::currentThreadId();
4038 bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
4039
4040 // We need to check against the highest connection id to ensure that signals added
4041 // during the signal emission are not emitted in this emission.
4042 uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
4043 do {
4044 QObjectPrivate::Connection *c = list->first.loadRelaxed();
4045 if (!c)
4046 continue;
4047
4048 do {
4049 QObject * const receiver = c->receiver.loadRelaxed();
4050 if (!receiver)
4051 continue;
4052
4053 QThreadData *td = c->receiverThreadData.loadRelaxed();
4054 if (!td)
4055 continue;
4056
4057 bool receiverInSameThread;
4058 if (inSenderThread) {
4059 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4060 } else {
4061 // need to lock before reading the threadId, because moveToThread() could interfere
4062 QMutexLocker lock(signalSlotLock(receiver));
4063 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4064 }
4065
4066
4067 // determine if this connection should be sent immediately or
4068 // put into the event queue
4069 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
4070 || (c->connectionType == Qt::QueuedConnection)) {
4071 queued_activate(sender, signal_index, c, argv);
4072 continue;
4073#if QT_CONFIG(thread)
4074 } else if (c->connectionType == Qt::BlockingQueuedConnection) {
4075 if (receiverInSameThread) {
4076 qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
4077 "Sender is %s(%p), receiver is %s(%p)",
4078 sender->metaObject()->className(), sender,
4079 receiver->metaObject()->className(), receiver);
4080 }
4081
4082 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4083 continue;
4084
4085 QSemaphore semaphore;
4086 {
4087 QMutexLocker locker(signalSlotLock(receiver));
4088 if (!c->isSingleShot && !c->receiver.loadAcquire())
4089 continue;
4090 QMetaCallEvent *ev = c->isSlotObject ?
4091 new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &semaphore) :
4092 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
4093 sender, signal_index, argv, &semaphore);
4094 QCoreApplication::postEvent(receiver, ev);
4095 }
4096 semaphore.acquire();
4097 continue;
4098#endif
4099 }
4100
4101 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4102 continue;
4103
4104 QObjectPrivate::Sender senderData(
4105 receiverInSameThread ? receiver : nullptr, sender, signal_index,
4106 receiverInSameThread ? QObjectPrivate::get(receiver)->connections.loadAcquire() : nullptr);
4107
4108 if (c->isSlotObject) {
4109 SlotObjectGuard obj{c->slotObj};
4110
4111 {
4112 Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
4113 obj->call(receiver, argv);
4114 }
4115 } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
4116 //we compare the vtable to make sure we are not in the destructor of the object.
4117 const int method_relative = c->method_relative;
4118 const auto callFunction = c->callFunction;
4119 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
4120 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)
4121 signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
4122
4123 {
4124 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
4125 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
4126 }
4127
4128 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
4129 signal_spy_set->slot_end_callback(receiver, methodIndex);
4130 } else {
4131 const int method = c->method_relative + c->method_offset;
4132
4133 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {
4134 signal_spy_set->slot_begin_callback(receiver, method, argv);
4135 }
4136
4137 {
4138 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
4140 }
4141
4142 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
4143 signal_spy_set->slot_end_callback(receiver, method);
4144 }
4145 } while ((c = c->nextConnectionList.loadRelaxed()) != nullptr && c->id <= highestConnectionId);
4146
4147 } while (list != &signalVector->at(-1) &&
4148 //start over for all signals;
4149 ((list = &signalVector->at(-1)), true));
4150
4151 if (connections->currentConnectionId.loadRelaxed() == 0)
4152 senderDeleted = true;
4153 }
4154 if (!senderDeleted) {
4155 sp->connections.loadAcquire()->cleanOrphanedConnections(sender);
4156
4157 if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
4158 signal_spy_set->signal_end_callback(sender, signal_index);
4159 }
4160}
4161
4165void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
4166 void **argv)
4167{
4168 int signal_index = local_signal_index + QMetaObjectPrivate::signalOffset(m);
4169
4170 if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
4171 doActivate<true>(sender, signal_index, argv);
4172 else
4173 doActivate<false>(sender, signal_index, argv);
4174}
4175
4179void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
4180{
4181 int signal_index = signalOffset + local_signal_index;
4182
4183 if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
4184 doActivate<true>(sender, signal_index, argv);
4185 else
4186 doActivate<false>(sender, signal_index, argv);
4187}
4188
4193void QMetaObject::activate(QObject *sender, int signal_index, void **argv)
4194{
4195 const QMetaObject *mo = sender->metaObject();
4196 while (mo->methodOffset() > signal_index)
4197 mo = mo->superClass();
4198 activate(sender, mo, signal_index - mo->methodOffset(), argv);
4199}
4200
4210int QObjectPrivate::signalIndex(const char *signalName,
4211 const QMetaObject **meta) const
4212{
4213 Q_Q(const QObject);
4214 const QMetaObject *base = q->metaObject();
4215 Q_ASSERT(QMetaObjectPrivate::get(base)->revision >= 7);
4218 int relative_index = QMetaObjectPrivate::indexOfSignalRelative(
4219 &base, name, types.size(), types.constData());
4220 if (relative_index < 0)
4221 return relative_index;
4222 relative_index = QMetaObjectPrivate::originalClone(base, relative_index);
4223 if (meta)
4224 *meta = base;
4225 return relative_index + QMetaObjectPrivate::signalOffset(base);
4226}
4227
4228/*****************************************************************************
4229 Properties
4230 *****************************************************************************/
4231
4262bool QObject::doSetProperty(const char *name, const QVariant *lvalue, QVariant *rvalue)
4263{
4264 Q_D(QObject);
4265 const auto &value =*lvalue;
4266 const QMetaObject *meta = metaObject();
4267 if (!name || !meta)
4268 return false;
4269
4270 int id = meta->indexOfProperty(name);
4271 if (id < 0) {
4272 d->ensureExtraData();
4273
4274 const int idx = d->extraData->propertyNames.indexOf(name);
4275
4276 if (!value.isValid()) {
4277 if (idx == -1)
4278 return false;
4279 d->extraData->propertyNames.removeAt(idx);
4280 d->extraData->propertyValues.removeAt(idx);
4281 } else {
4282 if (idx == -1) {
4283 d->extraData->propertyNames.append(name);
4284 if (rvalue)
4285 d->extraData->propertyValues.append(std::move(*rvalue));
4286 else
4287 d->extraData->propertyValues.append(*lvalue);
4288 } else {
4289 if (value.userType() == d->extraData->propertyValues.at(idx).userType()
4290 && value == d->extraData->propertyValues.at(idx))
4291 return false;
4292 if (rvalue)
4293 d->extraData->propertyValues[idx] = std::move(*rvalue);
4294 else
4295 d->extraData->propertyValues[idx] = *lvalue;
4296 }
4297 }
4298
4300 QCoreApplication::sendEvent(this, &ev);
4301
4302 return false;
4303 }
4304 QMetaProperty p = meta->property(id);
4305#ifndef QT_NO_DEBUG
4306 if (!p.isWritable())
4307 qWarning("%s::setProperty: Property \"%s\" invalid,"
4308 " read-only or does not exist", metaObject()->className(), name);
4309#endif
4310 return rvalue ? p.write(this, std::move(*rvalue)) : p.write(this, *lvalue);
4311}
4312
4324{
4325 Q_D(const QObject);
4326 const QMetaObject *meta = metaObject();
4327 if (!name || !meta)
4328 return QVariant();
4329
4330 int id = meta->indexOfProperty(name);
4331 if (id < 0) {
4332 if (!d->extraData)
4333 return QVariant();
4334 const int i = d->extraData->propertyNames.indexOf(name);
4335 return d->extraData->propertyValues.value(i);
4336 }
4337 QMetaProperty p = meta->property(id);
4338#ifndef QT_NO_DEBUG
4339 if (!p.isReadable())
4340 qWarning("%s::property: Property \"%s\" invalid or does not exist",
4341 metaObject()->className(), name);
4342#endif
4343 return p.read(this);
4344}
4345
4352QList<QByteArray> QObject::dynamicPropertyNames() const
4353{
4354 Q_D(const QObject);
4355 if (d->extraData)
4356 return d->extraData->propertyNames;
4357 return QList<QByteArray>();
4358}
4359
4360/*****************************************************************************
4361 QObject debugging output routines.
4362 *****************************************************************************/
4363
4365{
4366 return {};
4367}
4368
4369static void dumpRecursive(int level, const QObject *object)
4370{
4371 if (object) {
4372 const int indent = level * 4;
4373 qDebug("%*s%s::%ls %s", indent, "", object->metaObject()->className(),
4374 qUtf16Printable(object->objectName()),
4375 QObjectPrivate::get(object)->flagsForDumping().c_str());
4376 for (auto child : object->children())
4378 }
4379}
4380
4381
4391{
4392 dumpRecursive(0, this);
4393}
4394
4405{
4406 qDebug("OBJECT %s::%s", metaObject()->className(),
4407 objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
4408
4409 Q_D(const QObject);
4410 QMutexLocker locker(signalSlotLock(this));
4411
4412 // first, look for connections where this object is the sender
4413 qDebug(" SIGNALS OUT");
4414
4415 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
4416 if (cd && cd->signalVectorCount() > 0) {
4417 QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
4418 for (int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
4419 const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
4420 if (!c)
4421 continue;
4423 qDebug(" signal: %s", signal.methodSignature().constData());
4424
4425 // receivers
4426 while (c) {
4427 if (!c->receiver.loadRelaxed()) {
4428 qDebug(" <Disconnected receiver>");
4429 c = c->nextConnectionList.loadRelaxed();
4430 continue;
4431 }
4432 if (c->isSlotObject) {
4433 qDebug(" <functor or function pointer>");
4434 c = c->nextConnectionList.loadRelaxed();
4435 continue;
4436 }
4437 const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
4438 const QMetaMethod method = receiverMetaObject->method(c->method());
4439 qDebug(" --> %s::%s %s",
4440 receiverMetaObject->className(),
4441 c->receiver.loadRelaxed()->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
4442 method.methodSignature().constData());
4443 c = c->nextConnectionList.loadRelaxed();
4444 }
4445 }
4446 } else {
4447 qDebug( " <None>" );
4448 }
4449
4450 // now look for connections where this object is the receiver
4451 qDebug(" SIGNALS IN");
4452
4453 if (cd && cd->senders) {
4454 for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
4455 QByteArray slotName = QByteArrayLiteral("<unknown>");
4456 if (!s->isSlotObject) {
4457 const QMetaMethod slot = metaObject()->method(s->method());
4458 slotName = slot.methodSignature();
4459 }
4460 qDebug(" <-- %s::%s %s",
4461 s->sender->metaObject()->className(),
4462 s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()),
4463 slotName.constData());
4464 }
4465 } else {
4466 qDebug(" <None>");
4467 }
4468}
4469
4470
4471#ifndef QT_NO_DEBUG_STREAM
4473{
4474 Q_Q(const QObject);
4475 dbg.nospace() << q->metaObject()->className() << '(' << (const void *)q;
4476 if (!q->objectName().isEmpty())
4477 dbg << ", name = " << q->objectName();
4478 dbg << ')';
4479}
4480
4482{
4483 QDebugStateSaver saver(dbg);
4484 if (!o)
4485 return dbg << "QObject(0x0)";
4486
4488 d->writeToDebugStream(dbg);
4489 return dbg;
4490}
4491#endif
4492
4722
4727
5195QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,
5196 const QObject *receiver, void **slot,
5198 const int *types, const QMetaObject *senderMetaObject)
5199{
5200 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5201 if (!signal) {
5202 qCWarning(lcConnect, "QObject::connect: invalid nullptr parameter");
5203 return QMetaObject::Connection();
5204 }
5205
5206 int signal_index = -1;
5207 void *args[] = { &signal_index, signal };
5208 for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
5209 senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
5210 if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
5211 break;
5212 }
5213 if (!senderMetaObject) {
5214 qCWarning(lcConnect, "QObject::connect: signal not found in %s", sender->metaObject()->className());
5215 return QMetaObject::Connection(nullptr);
5216 }
5217 signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
5218 return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj.release(), type, types, senderMetaObject);
5219}
5220
5221static void connectWarning(const QObject *sender,
5222 const QMetaObject *senderMetaObject,
5223 const QObject *receiver,
5224 const char *message)
5225{
5226 const char *senderString = sender ? sender->metaObject()->className()
5227 : senderMetaObject ? senderMetaObject->className()
5228 : "Unknown";
5229 const char *receiverString = receiver ? receiver->metaObject()->className()
5230 : "Unknown";
5231 qCWarning(lcConnect, "QObject::connect(%s, %s): %s", senderString, receiverString, message);
5232}
5233
5242 const QObject *receiver, void **slot,
5243 QtPrivate::QSlotObjectBase *slotObjRaw, int type,
5244 const int *types, const QMetaObject *senderMetaObject)
5245{
5246 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5247
5248 if (!sender || !receiver || !slotObj || !senderMetaObject) {
5249 connectWarning(sender, senderMetaObject, receiver, "invalid nullptr parameter");
5250 return QMetaObject::Connection();
5251 }
5252
5253 if (type & Qt::UniqueConnection && !slot) {
5254 connectWarning(sender, senderMetaObject, receiver, "unique connections require a pointer to member function of a QObject subclass");
5255 return QMetaObject::Connection();
5256 }
5257
5258 QObject *s = const_cast<QObject *>(sender);
5259 QObject *r = const_cast<QObject *>(receiver);
5260
5261 QOrderedMutexLocker locker(signalSlotLock(sender),
5262 signalSlotLock(receiver));
5263
5264 if (type & Qt::UniqueConnection && slot) {
5265 QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
5266 if (connections && connections->signalVectorCount() > signal_index) {
5267 const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
5268
5269 while (c2) {
5270 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot))
5271 return QMetaObject::Connection();
5272 c2 = c2->nextConnectionList.loadRelaxed();
5273 }
5274 }
5275 }
5276 type &= ~Qt::UniqueConnection;
5277
5278 const bool isSingleShot = type & Qt::SingleShotConnection;
5279 type &= ~Qt::SingleShotConnection;
5280
5281 Q_ASSERT(type >= 0);
5282 Q_ASSERT(type <= 3);
5283
5284 std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
5285 c->sender = s;
5286 c->signal_index = signal_index;
5287 QThreadData *td = r->d_func()->threadData.loadAcquire();
5288 td->ref();
5289 c->receiverThreadData.storeRelaxed(td);
5290 c->receiver.storeRelaxed(r);
5291 c->connectionType = type;
5292 c->isSlotObject = true;
5293 c->slotObj = slotObj.release();
5294 if (types) {
5295 c->argumentTypes.storeRelaxed(types);
5296 c->ownArgumentTypes = false;
5297 }
5298 c->isSingleShot = isSingleShot;
5299
5300 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
5301 QMetaObject::Connection ret(c.release());
5302 locker.unlock();
5303
5304 QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
5305 Q_ASSERT(method.isValid());
5306 s->connectNotify(method);
5307
5308 return ret;
5309}
5310
5320{
5322 if (!c)
5323 return false;
5324 const bool disconnected = QObjectPrivate::removeConnection(c);
5325 const_cast<QMetaObject::Connection &>(connection).d_ptr = nullptr;
5326 c->deref(); // has been removed from the QMetaObject::Connection object
5327 return disconnected;
5328}
5329
5391bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot, const QMetaObject *senderMetaObject)
5392{
5393 if (sender == nullptr || (receiver == nullptr && slot != nullptr)) {
5394 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
5395 return false;
5396 }
5397
5398 int signal_index = -1;
5399 if (signal) {
5400 void *args[] = { &signal_index, signal };
5401 for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
5402 senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
5403 if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
5404 break;
5405 }
5406 if (!senderMetaObject) {
5407 qCWarning(lcConnect, "QObject::disconnect: signal not found in %s", sender->metaObject()->className());
5408 return false;
5409 }
5410 signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
5411 }
5412
5413 return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1, slot);
5414}
5415
5426{
5427 return QObjectPrivate::connect(sender, signal_index, sender, slotObj, type);
5428}
5429
5441 const QObject *receiver,
5442 QtPrivate::QSlotObjectBase *slotObjRaw,
5444{
5445 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5446 if (!sender) {
5447 qCWarning(lcConnect, "QObject::connect: invalid nullptr parameter");
5448 return QMetaObject::Connection();
5449 }
5450 const QMetaObject *senderMetaObject = sender->metaObject();
5451 signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
5452
5453 return connectImpl(sender, signal_index, receiver, /*slot*/ nullptr, slotObj.release(),
5454 type, /*types*/ nullptr, senderMetaObject);
5455}
5456
5465bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, void **slot)
5466{
5467 return QObjectPrivate::disconnect(sender, signal_index, sender, slot);
5468}
5469
5482bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, const QObject *receiver,
5483 void **slot)
5484{
5485 const QMetaObject *senderMetaObject = sender->metaObject();
5486 signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
5487
5488 return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1,
5489 slot);
5490}
5491
5497{
5498 if (!c)
5499 return false;
5500 QObject *receiver = c->receiver.loadRelaxed();
5501 if (!receiver)
5502 return false;
5503
5504 QBasicMutex *senderMutex = signalSlotLock(c->sender);
5505 QBasicMutex *receiverMutex = signalSlotLock(receiver);
5506
5508 {
5509 QOrderedMutexLocker locker(senderMutex, receiverMutex);
5510
5511 // load receiver once again and recheck to ensure nobody else has removed the connection in the meantime
5512 receiver = c->receiver.loadRelaxed();
5513 if (!receiver)
5514 return false;
5515
5516 connections = QObjectPrivate::get(c->sender)->connections.loadRelaxed();
5518 connections->removeConnection(c);
5519
5520 c->sender->disconnectNotify(QMetaObjectPrivate::signal(c->sender->metaObject(), c->signal_index));
5521 // We must not hold the receiver mutex, else we risk dead-locking; we also only need the sender mutex
5522 // It is however vital to hold the senderMutex before calling cleanOrphanedConnections, as otherwise
5523 // another thread might modify/delete the connection
5524 if (receiverMutex != senderMutex) {
5525 receiverMutex->unlock();
5526 }
5528 senderMutex->unlock(); // now both sender and receiver mutex have been manually unlocked
5529 locker.dismiss(); // so we dismiss the QOrderedMutexLocker
5530 }
5531
5532 return true;
5533}
5534
5542{
5543 if (auto conns = connections.loadAcquire()) {
5544 Q_Q(QObject);
5545 const QMetaObject *metaObject = q->metaObject();
5546 int signal_index = methodIndexToSignalIndex(&metaObject, property.notifySignalIndex());
5547 if (signal_index >= conns->signalVectorCount())
5548 return nullptr;
5549 const auto &connectionList = conns->connectionsForSignal(signal_index);
5550 for (auto c = connectionList.first.loadRelaxed(); c;
5551 c = c->nextConnectionList.loadRelaxed()) {
5552 if (c->isSlotObject) {
5554 property.propertyIndex()))
5555 return p;
5556 }
5557 }
5558 }
5559 return nullptr;
5560}
5561
5577QMetaObject::Connection::Connection(const QMetaObject::Connection &other) : d_ptr(other.d_ptr)
5578{
5579 if (d_ptr)
5580 static_cast<QObjectPrivate::Connection *>(d_ptr)->ref();
5581}
5582
5586QMetaObject::Connection &QMetaObject::Connection::operator=(const QMetaObject::Connection &other)
5587{
5588 if (other.d_ptr != d_ptr) {
5589 if (d_ptr)
5590 static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
5591 d_ptr = other.d_ptr;
5592 if (other.d_ptr)
5593 static_cast<QObjectPrivate::Connection *>(other.d_ptr)->ref();
5594 }
5595 return *this;
5596}
5597
5602QMetaObject::Connection::Connection() : d_ptr(nullptr) {}
5603
5607QMetaObject::Connection::~Connection()
5608{
5609 if (d_ptr)
5610 static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
5611}
5612
5614bool QMetaObject::Connection::isConnected_helper() const
5615{
5616 Q_ASSERT(d_ptr); // we're only called from operator RestrictedBool() const
5618
5619 return c->receiver.loadRelaxed();
5620}
5621
5622
5634
5635#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< TimerInfoV2 > timersForObject(QObject *object) const =0
virtual bool unregisterTimers(QObject *object)=0
Unregisters all the timers associated with the given object.
Qt::TimerId registerTimer(Duration interval, Qt::TimerType timerType, QObject *object)
const QObject * sender() const
Definition qobject_p.h:357
\inmodule QtCore
int type() const
bool ref() noexcept
bool deref() noexcept
void storeRelaxed(T newValue) noexcept
T loadRelaxed() const noexcept
Type loadRelaxed() const noexcept
void storeRelease(Type newValue) noexcept
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
\inmodule QtCore
Definition qcoreevent.h:379
static QPostEventListLocker lockThreadPostEventList(QObject *object)
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
@ ParentChange
Definition qcoreevent.h:80
@ ChildPolished
Definition qcoreevent.h:107
@ ChildRemoved
Definition qcoreevent.h:108
@ DeferredDelete
Definition qcoreevent.h:100
@ ThreadChange
Definition qcoreevent.h:82
@ ParentAboutToChange
Definition qcoreevent.h:81
@ ChildAdded
Definition qcoreevent.h:106
Type type() const
Returns the event type.
Definition qcoreevent.h:304
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
T & first()
Definition qlist.h:645
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
const void *const * args() const
Definition qobject_p.h:417
QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction, const QObject *sender, int signalId, void **args, QSemaphore *semaphore)
Definition qobject.cpp:505
~QMetaCallEvent() override
Definition qobject.cpp:601
const QMetaType * types() const
Definition qobject_p.h:419
virtual void placeMetaCall(QObject *object) override
Definition qobject.cpp:617
\inmodule QtCore
Definition qmetaobject.h:19
int relativeMethodIndex() const
const QMetaObject * mobj
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:341
constexpr TypeFlags flags() const
Definition qmetatype.h:2658
static QMetaType fromName(QByteArrayView name)
Returns a QMetaType matching typeName.
int id(int=0) const
Definition qmetatype.h:475
void * create(const void *copy=nullptr) const
\inmodule QtCore
Definition qmutex.h:313
void unlock() noexcept
Unlocks this mutex locker.
Definition qmutex.h:319
void relock() noexcept
Relocks an unlocked mutex locker.
Definition qmutex.h:320
\inmodule QtCore
Definition qmutex.h:281
QDynamicMetaObjectData * metaObject
Definition qobject.h:90
uint isDeletingChildren
Definition qobject.h:79
uint isWindow
Definition qobject.h:82
virtual ~QObjectData()=0
Definition qobject.cpp:152
QMetaObject * dynamicMetaObject() const
Definition qobject.cpp:154
uint receiveChildEvents
Definition qobject.h:81
uint wasDeleted
Definition qobject.h:78
QObject * q_ptr
Definition qobject.h:72
uint deleteLaterCalled
Definition qobject.h:83
uint receiveParentEvents
Definition qobject.h:87
uint isQuickItem
Definition qobject.h:84
uint isWidget
Definition qobject.h:76
uint sendChildEvents
Definition qobject.h:80
QAtomicInt postedEvents
Definition qobject.h:89
QObjectList children
Definition qobject.h:74
uint blockSig
Definition qobject.h:77
uint wasWidget
Definition qobject.h:86
uint willBeWidget
Definition qobject.h:85
QObject * parent
Definition qobject.h:73
QBindingStorage bindingStorage
Definition qobject.h:91
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:5241
ExtraData * extraData
Definition qobject_p.h:197
bool isSignalConnected(uint signalIdx, bool checkDeclarative=true) const
Definition qobject.cpp:420
void ensureConnectionData()
Definition qobject.cpp:254
void moveToThread_helper()
Definition qobject.cpp:1719
void checkForIncompatibleLibraryVersion(int version) const
Definition qobject_p.h:225
void setThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status)
Definition qobject.cpp:1731
QObjectPrivate(int version=QObjectPrivateVersion)
Definition qobject.cpp:159
QAtomicPointer< ConnectionData > connections
Definition qobject_p.h:206
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
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:299
void(* StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **)
Definition qobject_p.h:108
void addConnection(int signal, Connection *c)
Definition qobject.cpp:273
QObject * currentChildBeingDeleted
Definition qobject_p.h:209
void clearBindingStorage()
Definition qobject.cpp:977
virtual void writeToDebugStream(QDebug &) const
Definition qobject.cpp:4472
QObjectList receiverList(const char *signal) const
Definition qobject.cpp:230
virtual ~QObjectPrivate()
Definition qobject.cpp:184
void setParent_helper(QObject *)
Definition qobject.cpp:2219
void reinitBindingStorageAfterThreadMove()
Definition qobject.cpp:465
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:328
void disconnectNotify(const QMetaMethod &signal)
Definition qobject_p.h:251
virtual std::string flagsForDumping() const
Definition qobject.cpp:4364
bool maybeSignalConnected(uint signalIndex) const
Definition qobject.cpp:446
QExplicitlySharedDataPointer< ConnectionData > ConnectionDataPointer
Definition qobject_p.h:205
QtPrivate::QPropertyAdaptorSlotObject * getPropertyAdaptorSlotObject(const QMetaProperty &property)
Definition qobject.cpp:5541
int signalIndex(const char *signalName, const QMetaObject **meta=nullptr) const
Definition qobject.cpp:4210
QAtomicPointer< QThreadData > threadData
Definition qobject_p.h:203
void deleteChildren()
Definition qobject.cpp:2202
static bool removeConnection(Connection *c)
Definition qobject.cpp:5496
bool isDeclarativeSignalConnected(uint signalIdx) const
Definition qobject_p.h:240
\inmodule QtCore
Definition qobject.h:103
int senderSignalIndex() const
Definition qobject.cpp:2700
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:1817
Q_INVOKABLE QObject(QObject *parent=nullptr)
Constructs an object with parent object parent.
Definition qobject.cpp:936
bool isSignalConnected(const QMetaMethod &signal) const
Definition qobject.cpp:2801
virtual ~QObject()
Destroys the object, deleting all its child objects.
Definition qobject.cpp:1006
void installEventFilter(QObject *filterObj)
Installs an event filter filterObj on this object.
Definition qobject.cpp:2339
const QObjectList & children() const
Returns a list of child objects.
Definition qobject.h:201
void dumpObjectTree() const
Dumps a tree of children to the debug output.
Definition qobject.cpp:4390
virtual void connectNotify(const QMetaMethod &signal)
Definition qobject.cpp:3484
void dumpObjectInfo() const
Dumps information about signal connections, etc.
Definition qobject.cpp:4404
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
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:2658
virtual void childEvent(QChildEvent *event)
This event handler can be reimplemented in a subclass to receive child events.
Definition qobject.cpp:1508
QString objectName
the name of this object
Definition qobject.h:107
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:1389
void setParent(QObject *parent)
Makes the object a child of parent.
Definition qobject.cpp:2195
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:1555
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
void removeEventFilter(QObject *obj)
Removes an event filter object obj from this object.
Definition qobject.cpp:2370
virtual void timerEvent(QTimerEvent *event)
This event handler can be reimplemented in a subclass to receive timer events for the object.
Definition qobject.cpp:1470
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1598
QScopedPointer< QObjectData > d_ptr
Definition qobject.h:373
bool moveToThread(QThread *thread QT6_DECL_NEW_OVERLOAD_TAIL)
Changes the thread affinity for this object and its children and returns true on success.
Definition qobject.cpp:1643
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:1585
QList< QByteArray > dynamicPropertyNames() const
Definition qobject.cpp:4352
int receivers(const char *signal) const
Returns the number of receivers connected to the signal.
Definition qobject.cpp:2740
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4323
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
Definition qobject.h:127
QBindable< QString > bindableObjectName()
Definition qobject.cpp:1326
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:1912
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
virtual void disconnectNotify(const QMetaMethod &signal)
Definition qobject.cpp:3519
virtual void customEvent(QEvent *event)
This event handler can be reimplemented in a subclass to receive custom events.
Definition qobject.cpp:1522
\inmodule QtCore \reentrant
\inmodule QtCore \reentrant
\inmodule QtCore
Definition qsemaphore.h:18
void acquire(int n=1)
Tries to acquire n resources guarded by the semaphore.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QByteArray toLatin1() const &
Definition qstring.h:630
static Q_AUTOTEST_EXPORT QThreadData * current(bool createIfNecessary=true)
Definition qthread.cpp:1087
void deref()
Definition qthread.cpp:105
QAtomicPointer< void > threadId
Definition qthread_p.h:324
static QThreadData * get2(QThread *thread)
Definition qthread_p.h:291
QPostEventList postEventList
Definition qthread_p.h:322
void ref()
Definition qthread.cpp:97
QAtomicPointer< QThread > thread
Definition qthread_p.h:323
void removeObjectWithPendingBindingStatusChange(QObject *)
Definition qthread_p.h:270
static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION
Definition qthread.h:149
static QThread * currentThread()
Definition qthread.cpp:1039
\inmodule QtCore
Definition qcoreevent.h:366
\inmodule QtCore
Definition qvariant.h:65
static QPropertyAdaptorSlotObject * cast(QSlotObjectBase *ptr, int propertyIndex)
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_NO_KEYWORDS >
bool isAnyBindingEvaluating()
std::unique_ptr< QSlotObjectBase, QSlotObjectBase::Deleter > SlotObjUniquePtr
Definition qcompare.h:63
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_NODISCARD_CTOR
#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:164
#define qWarning
Definition qlogging.h:166
#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:3776
static void check_and_warn_compat(const QMetaObject *sender, const QMetaMethod &signal, const QMetaObject *receiver, const QMetaMethod &method)
Definition qobject.cpp:2873
void qt_qFindChildren_helper(const QObject *parent, QAnyStringView name, const QMetaObject &mo, QList< void * > *list, Qt::FindChildOptions options)
Definition qobject.cpp:2137
static void dumpRecursive(int level, const QObject *object)
Definition qobject.cpp:4369
static int methodIndexToSignalIndex(const QMetaObject **base, int signal_index)
Definition qobject.cpp:3528
QObject * qt_qFindChild_helper(const QObject *parent, QAnyStringView name, const QMetaObject &mo, Qt::FindChildOptions options)
Definition qobject.cpp:2174
static const char * extract_location(const char *member)
Definition qobject.cpp:2568
Q_CORE_EXPORT QBasicAtomicPointer< QSignalSpyCallbackSet > qt_signal_spy_callback_set
Definition qobject.cpp:61
static bool check_parent_thread(QObject *parent, QThreadData *parentThreadData, QThreadData *currentThreadData)
Definition qobject.cpp:901
static int DIRECT_CONNECTION_ONLY
Definition qobject.cpp:56
static int * queuedConnectionTypes(const QMetaMethod &method)
Definition qobject.cpp:76
static void computeOffsets(const QMetaObject *metaobject, int *signalOffset, int *methodOffset)
Definition qobject.cpp:216
static QBasicMutex * signalSlotLock(const QObject *o)
Definition qobject.cpp:135
void doActivate(QObject *sender, int signal_index, void **argv)
Definition qobject.cpp:3991
static Q_DECL_COLD_FUNCTION void err_method_notfound(const QObject *object, const char *method, const char *func)
Definition qobject.cpp:2608
static bool check_method_code(int code, const QObject *object, const char *method, const char *func)
Definition qobject.cpp:2595
void qt_register_signal_spy_callbacks(QSignalSpyCallbackSet *callback_set)
Definition qobject.cpp:63
static Q_CONSTINIT QBasicMutex _q_ObjectMutexPool[131]
Definition qobject.cpp:129
static bool matches_objectName_non_null(QObject *obj, QAnyStringView name)
Definition qobject.cpp:2127
static int extract_code(const char *member)
Definition qobject.cpp:2562
static QByteArray formatConnectionSignature(const char *className, const QMetaMethod &method)
Definition qobject.cpp:3758
static void connectWarning(const QObject *sender, const QMetaObject *senderMetaObject, const QObject *receiver, const char *message)
Definition qobject.cpp:5221
const char * qFlagLocation(const char *method)
Definition qobject.cpp:2556
static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv)
Definition qobject.cpp:3926
static bool check_signal_macro(const QObject *sender, const char *signal, const char *func, const char *op)
Definition qobject.cpp:2579
static Q_DECL_COLD_FUNCTION void err_info_about_objects(const char *func, const QObject *sender, const QObject *receiver)
Definition qobject.cpp:2626
Q_CORE_EXPORT QBasicAtomicPointer< QSignalSpyCallbackSet > qt_signal_spy_callback_set
Definition qobject.cpp:61
#define QSIGNAL_CODE
Definition qobjectdefs.h:42
#define QSLOT_CODE
Definition qobjectdefs.h:41
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
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLuint GLsizei const GLchar * message
GLint ref
GLuint name
GLfloat n
GLsizei GLenum GLsizei GLsizei GLuint memory
struct _cl_event * event
GLhandleARB obj
[2]
GLdouble s
[6]
Definition qopenglext.h:235
GLenum func
Definition qopenglext.h:663
GLuint res
const GLubyte * c
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
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:1531
#define qUtf16Printable(string)
Definition qstring.h:1543
#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
QT_BEGIN_NAMESPACE constexpr std::underlying_type_t< Enum > qToUnderlying(Enum e) noexcept
#define QT6_IMPL_NEW_OVERLOAD_TAIL
size_t quintptr
Definition qtypes.h:167
unsigned int uint
Definition qtypes.h:34
unsigned short ushort
Definition qtypes.h:33
static const uint base
Definition qurlidna.cpp:20
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:469
virtual ~QDynamicMetaObjectData()
Definition qobject.cpp:68
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition qlist.h:962
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:3576
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:3711
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:2843
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:3671
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)
\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:3657
static bool disconnect(const QObject *sender, int signal_index, const QObject *receiver, int method_index)
Definition qobject.cpp:3641
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:3807
static Connection connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type=0, int *types=nullptr)
Definition qobject.cpp:3556
int indexOfProperty(const char *name) const
Finds property name and returns its index; otherwise returns -1.
struct QMetaObject::Data d
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:4193
std::atomic< TaggedSignalVector > orphaned
QAtomicInteger< uint > currentConnectionId
ConnectionList & connectionsForSignal(int signal)
void removeConnection(Connection *c)
Definition qobject.cpp:301
void resizeSignalVector(uint size)
static void deleteOrphaned(TaggedSignalVector o)
Definition qobject.cpp:395
void cleanOrphanedConnectionsImpl(QObject *sender, LockPolicy lockPolicy)
Definition qobject.cpp:367
QAtomicPointer< SignalVector > signalVector
QAtomicPointer< Connection > first
Definition qobject_p_p.h:31
QAtomicPointer< const int > argumentTypes
Definition qobject_p_p.h:84
QAtomicPointer< Connection > nextConnectionList
Definition qobject_p_p.h:74
QAtomicPointer< QObject > receiver
Definition qobject_p_p.h:78
QtPrivate::QSlotObjectBase * slotObj
Definition qobject_p_p.h:82
QList< Qt::TimerId > runningTimers
Definition qobject_p.h:94
ConnectionList & at(int i)
QtPrivate::QSlotObjectBase * operator->()
Definition qobject.cpp:3913
~SlotObjectGuard()=default
QtPrivate::QSlotObjectBase const * operator->() const
Definition qobject.cpp:3910
SlotObjectGuard()=default