Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
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// Qt-Security score:significant reason:default
6
7#include <QtCore/qtconfigmacros.h>
8
9#ifdef QT_NO_DISCONNECT_CONST_CONNECTION
10# undef QT_NO_DISCONNECT_CONST_CONNECTION
11#endif
12
13#include "qobject.h"
14#include "qobject_p.h"
15#include "qobject_p_p.h"
16#include "qmetaobject_p.h"
17
18#include <QtCore/private/qtclasshelper_p.h>
19#include <QtCore/qspan.h>
24#include "qcoreevent_p.h"
26#include "qvariant.h"
27#include "qmetaobject.h"
28#if QT_CONFIG(regularexpression)
29# include <qregularexpression.h>
30#endif
31#include <qthread.h>
32#include <private/qthread_p.h>
33#include <qdebug.h>
34#include <qvarlengtharray.h>
35#include <qscopeguard.h>
36#include <qset.h>
37#if QT_CONFIG(thread)
38#include <private/qlatch_p.h>
39#endif
40
41#include <private/qorderedmutexlocker_p.h>
42#include <private/qhooks_p.h>
43#include <qtcore_tracepoints_p.h>
44
45#include <new>
46#include <mutex>
47#include <memory>
48#include <optional>
49#include <iterator>
50
51#include <ctype.h>
52#include <limits.h>
53
55
56Q_TRACE_POINT(qtcore, QObject_ctor, QObject *object);
58Q_TRACE_POINT(qtcore, QMetaObject_activate_entry, QObject *sender, int signalIndex);
60Q_TRACE_POINT(qtcore, QMetaObject_activate_slot_entry, QObject *receiver, int slotIndex);
66
68
69Q_STATIC_LOGGING_CATEGORY(lcConnectSlotsByName, "qt.core.qmetaobject.connectslotsbyname")
70Q_STATIC_LOGGING_CATEGORY(lcConnect, "qt.core.qobject.connect")
71
72Q_CORE_EXPORT QBasicAtomicPointer<QSignalSpyCallbackSet> qt_signal_spy_callback_set = Q_BASIC_ATOMIC_INITIALIZER(nullptr);
73
75{
76 qt_signal_spy_callback_set.storeRelease(callback_set);
77}
78
79QDynamicMetaObjectData::~QDynamicMetaObjectData()
80{
81}
82
83QAbstractDynamicMetaObject::~QAbstractDynamicMetaObject()
84{
85}
86
87static int *queuedConnectionTypes(const QMetaMethod &method)
88{
89 const auto parameterCount = method.parameterCount();
90 int *typeIds = new int[parameterCount + 1];
91 Q_CHECK_PTR(typeIds);
92 for (int i = 0; i < parameterCount; ++i) {
93 const QMetaType metaType = method.parameterMetaType(i);
94 if (metaType.flags() & QMetaType::IsPointer)
95 typeIds[i] = QMetaType::VoidStar;
96 else
97 typeIds[i] = metaType.id();
98 if (!typeIds[i] && method.parameterTypeName(i).endsWith('*'))
99 typeIds[i] = QMetaType::VoidStar;
100 if (!typeIds[i]) {
101 const QByteArray typeName = method.parameterTypeName(i);
102 qCWarning(lcConnect,
103 "QObject::connect: Cannot queue arguments of type '%s'\n"
104 "(Make sure '%s' is registered using qRegisterMetaType().)",
105 typeName.constData(), typeName.constData());
106 delete[] typeIds;
107 return nullptr;
108 }
109 }
110 typeIds[parameterCount] = 0;
111
112 return typeIds;
113}
115// ### Future work: replace with an array of QMetaType or QtPrivate::QMetaTypeInterface *
116static int *queuedConnectionTypes(QSpan<const QArgumentType> argumentTypes)
117{
118 const int argc = int(argumentTypes.size());
119 auto types = std::make_unique<int[]>(argc + 1);
120 for (int i = 0; i < argc; ++i) {
121 const QArgumentType &type = argumentTypes[i];
122 if (type.metaType().isValid())
123 types[i] = type.metaType().id();
124 else if (type.name().endsWith('*'))
125 types[i] = QMetaType::VoidStar;
126 else
127 types[i] = QMetaType::fromName(type.name()).rawId();
128
129 if (!types[i]) {
130 qCWarning(lcConnect,
131 "QObject::connect: Cannot queue arguments of type '%s'\n"
132 "(Make sure '%s' is registered using qRegisterMetaType().)",
133 type.name().constData(), type.name().constData());
134 return nullptr;
135 }
136 }
137 types[argc] = 0;
138
139 return types.release();
140}
141
142Q_CONSTINIT static QBasicMutex _q_ObjectMutexPool[131];
143
144/**
145 * \internal
146 * mutex to be locked when accessing the connection lists or the senders list
147 */
148static inline QBasicMutex *signalSlotLock(const QObject *o)
149{
150 return &_q_ObjectMutexPool[quintptr(o) % std::size(_q_ObjectMutexPool)];
151}
152
153/**
154 * \internal
155 * Tells \a sender that the connection for \a signalIndex is gone, because its receiver is being
156 * destroyed.
157 *
158 * The caller holds the receiver's signalSlotLock, which \a sender's destructor must also take to
159 * tear down this (still-present) connection. So \a sender cannot get past ~QObject(), and reading
160 * its QObjectPrivate here is safe. That lock does not, however, hold back \a sender's
161 * further-derived destructors: those run before ~QObject() takes any lock, and rewrite the vptr as
162 * they go. Resolving the signal and calling disconnectNotify() are therefore virtual calls that
163 * may only be made from the thread that owns \a sender. Post them to that thread otherwise, unless
164 * it can no longer deliver events (e.g. it has finished), where the event would leak.
165 */
166static void disconnectNotifySender(QObject *sender, int signalIndex, Qt::HANDLE currentThreadId)
167{
168 QObjectPrivate *senderPriv = QObjectPrivate::get(sender);
169 QThreadData *senderThread = senderPriv->threadData.loadRelaxed();
170 if (senderThread->threadId.loadRelaxed() == currentThreadId)
171 senderPriv->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), signalIndex));
172 else if (senderThread->hasEventDispatcher())
173 QCoreApplication::postEvent(sender, new QDisconnectNotifyEvent(signalIndex));
174}
175
176void (*QAbstractDeclarativeData::destroyed)(QAbstractDeclarativeData *, QObject *) = nullptr;
177void (*QAbstractDeclarativeData::signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **) = nullptr;
178int (*QAbstractDeclarativeData::receivers)(QAbstractDeclarativeData *, const QObject *, int) = nullptr;
179bool (*QAbstractDeclarativeData::isSignalConnected)(QAbstractDeclarativeData *, const QObject *, int) = nullptr;
180void (*QAbstractDeclarativeData::setWidgetParent)(QObject *, QObject *) = nullptr;
181
182/*!
183 \fn QObjectData::QObjectData()
184 \internal
185 */
186
187
188QObjectData::~QObjectData() {}
189
190const QMetaObject *QObjectData::dynamicMetaObject() const
191{
192 // ### keep in sync with removed_api.cpp version
193 return metaObject->toDynamicMetaObject(q_ptr);
194}
195
196QObjectPrivate::QObjectPrivate(decltype(QObjectPrivateVersion))
197 : threadData(nullptr), currentChildBeingDeleted(nullptr)
198{
199 // QObjectData initialization
200 q_ptr = nullptr;
201 parent = nullptr; // no parent yet. It is set by setParent()
202 isWidget = false; // assume not a widget object
203 blockSig = false; // not blocking signals
204 wasDeleted = false; // double-delete catcher
205 isDeletingChildren = false; // set by deleteChildren()
206 sendChildEvents = true; // if we should send ChildAdded and ChildRemoved events to parent
207 receiveChildEvents = true;
208 postedEvents.storeRelaxed(0);
209 extraData = nullptr;
210 metaObject = nullptr;
211 isWindow = false;
212 deleteLaterCalled = false;
213 isQuickItem = false;
214 willBeWidget = false;
215 wasWidget = false;
216 receiveParentEvents = false; // If object wants ParentAboutToChange and ParentChange
217}
218
219QObjectPrivate::~QObjectPrivate()
220{
221 auto thisThreadData = threadData.loadRelaxed();
222 if (extraData && !extraData->runningTimers.isEmpty()) {
223 if (thisThreadData->threadId.loadRelaxed() == QThread::currentThreadId()) {
224 // unregister pending timers
225 if (thisThreadData->hasEventDispatcher())
226 thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimers(q_ptr);
227
228 // release the timer ids back to the pool
229 for (auto id : std::as_const(extraData->runningTimers))
230 QAbstractEventDispatcherPrivate::releaseTimerId(id);
231 } else {
232 qWarning("QObject::~QObject: Timers cannot be stopped from another thread");
233 }
234 }
235
236 if (postedEvents.loadRelaxed())
237 QCoreApplication::removePostedEvents(q_ptr, 0);
238
239 thisThreadData->deref();
240
241 if (metaObject)
242 metaObject->objectDestroyed(q_ptr);
243
244 delete extraData;
245}
246
247/*!
248 \internal
249 For a given metaobject, compute the signal offset, and the method offset (including signals)
250*/
251static void computeOffsets(const QMetaObject *metaobject, int *signalOffset, int *methodOffset)
252{
253 *signalOffset = *methodOffset = 0;
254 const QMetaObject *m = metaobject->d.superdata;
255 while (m) {
256 const QMetaObjectPrivate *d = QMetaObjectPrivate::get(m);
257 *methodOffset += d->methodCount;
258 Q_ASSERT(d->revision >= 4);
259 *signalOffset += d->signalCount;
260 m = m->d.superdata;
261 }
262}
263
264// Used by QAccessibleWidget
265QObjectList QObjectPrivate::receiverList(const char *signal) const
266{
267 QObjectList returnValue;
268 int signal_index = signalIndex(signal);
269 ConnectionData *cd = connections.loadAcquire();
270 if (signal_index < 0 || !cd)
271 return returnValue;
272 if (signal_index < cd->signalVectorCount()) {
273 const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
274
275 while (c) {
276 QObject *r = c->receiver.loadRelaxed();
277 if (r)
278 returnValue << r;
279 c = c->nextConnectionList.loadRelaxed();
280 }
281 }
282 return returnValue;
283}
284
285/*!
286 \internal
287 The signalSlotLock() of the sender must be locked while calling this function
288*/
289inline void QObjectPrivate::ensureConnectionData()
290{
291 if (connections.loadRelaxed())
292 return;
293 ConnectionData *cd = new ConnectionData;
294 cd->ref.ref();
295 connections.storeRelease(cd);
296}
297
298/*!
299 \internal
300 Add the connection \a c to the list of connections of the sender's object
301 for the specified \a signal
302
303 The signalSlotLock() of the sender and receiver must be locked while calling
304 this function
305
306 Will also add the connection in the sender's list of the receiver.
307 */
308inline void QObjectPrivate::addConnection(int signal, Connection *c)
309{
310 Q_ASSERT(c->sender == q_ptr);
311 ensureConnectionData();
312 ConnectionData *cd = connections.loadRelaxed();
313 cd->resizeSignalVector(signal + 1);
314
315 ConnectionList &connectionList = cd->connectionsForSignal(signal);
316 Connection *lastConnection = connectionList.last.loadRelaxed();
317 if (lastConnection) {
318 Q_ASSERT(lastConnection->receiver.loadRelaxed());
319 lastConnection->nextConnectionList.storeRelease(c);
320 } else {
321 connectionList.first.storeRelease(c);
322 }
323 c->id.storeRelease(++cd->currentConnectionId);
324 c->prevConnectionList = lastConnection;
325 connectionList.last.storeRelaxed(c);
326
327 QObjectPrivate *rd = QObjectPrivate::get(c->receiver.loadRelaxed());
328 rd->ensureConnectionData();
329
330 c->prev = &(rd->connections.loadRelaxed()->senders);
331 c->next = *c->prev;
332 *c->prev = c;
333 if (c->next)
334 c->next->prev = &c->next;
335}
336
337void QObjectPrivate::ConnectionData::removeConnection(QObjectPrivate::Connection *c)
338{
339 Q_ASSERT(c->receiver.loadRelaxed());
340 ConnectionList &connections = signalVector.loadRelaxed()->at(c->signal_index);
341 c->receiver.storeRelaxed(nullptr);
342 QThreadData *td = c->receiverThreadData.loadRelaxed();
343 if (td)
344 td->deref();
345 c->receiverThreadData.storeRelaxed(nullptr);
346
347#ifndef QT_NO_DEBUG
348 bool found = false;
349 for (Connection *cc = connections.first.loadRelaxed(); cc; cc = cc->nextConnectionList.loadRelaxed()) {
350 if (cc == c) {
351 found = true;
352 break;
353 }
354 }
355 Q_ASSERT(found);
356#endif
357
358 // remove from the senders linked list
359 *c->prev = c->next;
360 if (c->next)
361 c->next->prev = c->prev;
362 c->prev = nullptr;
363
364 Connection *n = c->nextConnectionList.loadRelaxed();
365 if (connections.first.loadRelaxed() == c)
366 connections.first.storeRelaxed(n);
367 if (connections.last.loadRelaxed() == c)
368 connections.last.storeRelaxed(c->prevConnectionList);
369 Q_ASSERT(signalVector.loadRelaxed()->at(c->signal_index).first.loadRelaxed() != c);
370 Q_ASSERT(signalVector.loadRelaxed()->at(c->signal_index).last.loadRelaxed() != c);
371
372 // keep c->nextConnectionList intact, as it might still get accessed by activate
373 if (n)
374 n->prevConnectionList = c->prevConnectionList;
375 if (c->prevConnectionList)
376 c->prevConnectionList->nextConnectionList.storeRelaxed(n);
377 c->prevConnectionList = nullptr;
378
379 Q_ASSERT(c != static_cast<Connection *>(orphaned.load(std::memory_order_relaxed)));
380 // add c to orphanedConnections
381 TaggedSignalVector o = nullptr;
382 /* No ABA issue here: When adding a node, we only care about the list head, it doesn't
383 * matter if the tail changes.
384 */
385 o = orphaned.load(std::memory_order_acquire);
386 do {
387 c->nextInOrphanList = o;
388 } while (!orphaned.compare_exchange_strong(o, TaggedSignalVector(c), std::memory_order_release));
389
390#ifndef QT_NO_DEBUG
391 found = false;
392 for (Connection *cc = connections.first.loadRelaxed(); cc; cc = cc->nextConnectionList.loadRelaxed()) {
393 if (cc == c) {
394 found = true;
395 break;
396 }
397 }
398 Q_ASSERT(!found);
399#endif
400
401}
402
403void QObjectPrivate::ConnectionData::cleanOrphanedConnectionsImpl(QObject *sender, LockPolicy lockPolicy)
404{
405 QBasicMutex *senderMutex = signalSlotLock(sender);
406 TaggedSignalVector c = nullptr;
407 {
408 std::unique_lock<QBasicMutex> lock(*senderMutex, std::defer_lock_t{});
409 if (lockPolicy == NeedToLock)
410 lock.lock();
411 if (ref.loadAcquire() > 1)
412 return;
413
414 // Since ref == 1, no activate() is in process since we locked the mutex. That implies,
415 // that nothing can reference the orphaned connection objects anymore and they can
416 // be safely deleted
417 c = orphaned.exchange(nullptr, std::memory_order_relaxed);
418 }
419 if (c) {
420 // Deleting c might run arbitrary user code, so we must not hold the lock
421 if (lockPolicy == AlreadyLockedAndTemporarilyReleasingLock) {
422 senderMutex->unlock();
423 deleteOrphaned(c);
424 senderMutex->lock();
425 } else {
426 deleteOrphaned(c);
427 }
428 }
429}
430
431inline void QObjectPrivate::ConnectionData::deleteOrphaned(TaggedSignalVector o)
432{
433 while (o) {
434 TaggedSignalVector next = nullptr;
435 if (SignalVector *v = static_cast<SignalVector *>(o)) {
436 next = v->nextInOrphanList;
437 free(v);
438 } else {
439 QObjectPrivate::Connection *c = static_cast<Connection *>(o);
440 next = c->nextInOrphanList;
441 Q_ASSERT(!c->receiver.loadRelaxed());
442 Q_ASSERT(!c->prev);
443 c->freeSlotObject();
444 c->deref();
445 }
446 o = next;
447 }
448}
449
450/*! \internal
451
452 Returns \c true if the signal with index \a signal_index from object \a sender is connected.
453
454 \a signal_index must be the index returned by QObjectPrivate::signalIndex;
455*/
456bool QObjectPrivate::isSignalConnected(uint signalIndex, bool checkDeclarative) const
457{
458 if (checkDeclarative && isDeclarativeSignalConnected(signalIndex))
459 return true;
460
461 ConnectionData *cd = connections.loadAcquire();
462 if (!cd)
463 return false;
464 SignalVector *signalVector = cd->signalVector.loadRelaxed();
465 if (!signalVector)
466 return false;
467
468 if (signalVector->at(-1).first.loadRelaxed())
469 return true;
470
471 if (signalIndex < uint(cd->signalVectorCount())) {
472 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadRelaxed();
473 while (c) {
474 if (c->receiver.loadRelaxed())
475 return true;
476 c = c->nextConnectionList.loadRelaxed();
477 }
478 }
479 return false;
480}
481
482bool QObjectPrivate::maybeSignalConnected(uint signalIndex) const
483{
484 ConnectionData *cd = connections.loadAcquire();
485 if (!cd)
486 return false;
487 SignalVector *signalVector = cd->signalVector.loadAcquire();
488 if (!signalVector)
489 return false;
490
491 if (signalVector->at(-1).first.loadAcquire())
492 return true;
493
494 if (signalIndex < uint(cd->signalVectorCount())) {
495 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadAcquire();
496 return c != nullptr;
497 }
498 return false;
499}
500
501void QObjectPrivate::reinitBindingStorageAfterThreadMove()
502{
503 bindingStorage.reinitAfterThreadMove();
504 for (int i = 0; i < children.size(); ++i)
505 children[i]->d_func()->reinitBindingStorageAfterThreadMove();
506}
507
508/*!
509 \internal
510 */
511QAbstractMetaCallEvent::~QAbstractMetaCallEvent()
512{
513#if QT_CONFIG(thread)
514 if (latch)
515 latch->countDown();
516#endif
517}
518
519/*!
520 \internal
521
522 Used for blocking queued connections, just passes \a args through without
523 allocating any memory.
524 */
525QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative,
526 QObjectPrivate::StaticMetaCallFunction callFunction,
527 const QObject *sender, int signalId,
528 void **args, QLatch *latch)
529 : QAbstractMetaCallEvent(sender, signalId, latch),
530 d{nullptr, args, callFunction, 0, method_offset, method_relative}
531{
532}
533
534/*!
535 \internal
536
537 Used for blocking queued connections, just passes \a args through without
538 allocating any memory.
539 */
540QMetaCallEvent::QMetaCallEvent(QtPrivate::QSlotObjectBase *slotO,
541 const QObject *sender, int signalId,
542 void **args, QLatch *latch)
543 : QAbstractMetaCallEvent(sender, signalId, latch),
544 d{QtPrivate::SlotObjUniquePtr{slotO}, args, nullptr, 0, 0, ushort(-1)}
545{
546 if (d.slotObj_)
547 d.slotObj_->ref();
548}
549
550/*!
551 \internal
552
553 Used for blocking queued connections, just passes \a args through without
554 allocating any memory.
555 */
556QMetaCallEvent::QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotO,
557 const QObject *sender, int signalId,
558 void **args, QLatch *latch)
559 : QAbstractMetaCallEvent(sender, signalId, latch),
560 d{std::move(slotO), args, nullptr, 0, 0, ushort(-1)}
561{
562}
563
564/*!
565 \internal
566 */
567QMetaCallEvent::QMetaCallEvent(const QObject *sender, int signalId, Data &&data)
568 : QAbstractMetaCallEvent(sender, signalId),
569 d(std::move(data))
570{
571}
572
573/*!
574 \internal
575 */
576void QMetaCallEvent::placeMetaCall(QObject *object)
577{
578 if (d.slotObj_) {
579 d.slotObj_->call(object, d.args_);
580 } else if (d.callFunction_ && d.method_offset_ <= object->metaObject()->methodOffset()) {
581 d.callFunction_(object, QMetaObject::InvokeMetaMethod, d.method_relative_, d.args_);
582 } else {
583 QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod,
584 d.method_offset_ + d.method_relative_, d.args_);
585 }
586}
587
588/*!
589 \internal
590
591 Constructs a QQueuedMetaCallEvent by copying the argument values using their meta-types.
592 */
593QQueuedMetaCallEvent::QQueuedMetaCallEvent(ushort method_offset, ushort method_relative,
594 QObjectPrivate::StaticMetaCallFunction callFunction,
595 const QObject *sender, int signalId, int argCount,
596 const QtPrivate::QMetaTypeInterface * const *argTypes,
597 const void * const *argValues)
598 : QMetaCallEvent(sender, signalId, {nullptr, nullptr, callFunction, argCount,
599 method_offset, method_relative}),
600 prealloc_()
601{
602 copyArgValues(argCount, argTypes, argValues);
603}
604
605/*!
606 \internal
607
608 Constructs a QQueuedMetaCallEvent by copying the argument values using their meta-types.
609 */
610QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
611 const QObject *sender, int signalId, int argCount,
612 const QtPrivate::QMetaTypeInterface * const *argTypes,
613 const void * const *argValues)
614 : QMetaCallEvent(sender, signalId, {QtPrivate::SlotObjUniquePtr(slotObj), nullptr, nullptr, argCount,
615 0, ushort(-1)}),
616 prealloc_()
617{
618 if (d.slotObj_)
619 d.slotObj_->ref();
620 copyArgValues(argCount, argTypes, argValues);
621}
622
623/*!
624 \internal
625
626 Constructs a QQueuedMetaCallEvent by copying the argument values using their meta-types.
627 */
628QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,
629 const QObject *sender, int signalId, int argCount,
630 const QtPrivate::QMetaTypeInterface * const *argTypes,
631 const void * const *argValues)
632 : QMetaCallEvent(sender, signalId, {std::move(slotObj), nullptr, nullptr, argCount,
633 0, ushort(-1)}),
634 prealloc_()
635{
636 copyArgValues(argCount, argTypes, argValues);
637}
638
639/*!
640 \internal
641 */
642QQueuedMetaCallEvent::~QQueuedMetaCallEvent()
643{
644 const QMetaType *t = reinterpret_cast<QMetaType *>(d.args_ + d.nargs_);
645 int inplaceIndex = 0;
646 for (int i = 0; i < d.nargs_; ++i) {
647 if (t[i].isValid() && d.args_[i]) {
648 if (typeFitsInPlace(t[i]) && inplaceIndex < InplaceValuesCapacity) {
649 // Only destruct
650 void *where = &valuesPrealloc_[inplaceIndex++].storage;
651 t[i].destruct(where);
652 } else {
653 // Destruct and deallocate
654 t[i].destroy(d.args_[i]);
655 }
656 }
657 }
658 if (d.nargs_) {
659 if (static_cast<void *>(d.args_) != prealloc_)
660 QtPrivate::sizedFree(d.args_, d.nargs_, PtrAndTypeSize);
661 }
662}
663
664/*!
665 \internal
666 */
667inline void QQueuedMetaCallEvent::allocArgs()
668{
669 if (!d.nargs_)
670 return;
671
672 void *const memory = d.nargs_ * PtrAndTypeSize > sizeof(prealloc_) ?
673 calloc(d.nargs_, PtrAndTypeSize) : prealloc_;
674
675 Q_CHECK_PTR(memory);
676 d.args_ = static_cast<void **>(memory);
677}
678
679/*!
680 \internal
681 */
682inline void QQueuedMetaCallEvent::copyArgValues(int argCount, const QtPrivate::QMetaTypeInterface * const *argTypes,
683 const void * const *argValues)
684{
685 allocArgs();
686 void **args = d.args_;
687 QMetaType *types = reinterpret_cast<QMetaType *>(d.args_ + d.nargs_);
688 int inplaceIndex = 0;
689
690 if (argCount) {
691 types[0] = QMetaType(); // return type
692 args[0] = nullptr; // return value pointer
693 }
694 // no return value
695
696 for (int n = 1; n < argCount; ++n) {
697 types[n] = QMetaType(argTypes[n]);
698 if (typeFitsInPlace(types[n]) && inplaceIndex < InplaceValuesCapacity) {
699 // Copy-construct in place
700 void *where = &valuesPrealloc_[inplaceIndex++].storage;
701 types[n].construct(where, argValues[n]);
702 args[n] = where;
703 } else {
704 // Allocate and copy-construct
705 args[n] = types[n].create(argValues[n]);
706 }
707 }
708}
709
710/*!
711 \internal
712 */
713inline bool QQueuedMetaCallEvent::typeFitsInPlace(const QMetaType type)
714{
715 return (q20::cmp_less_equal(type.sizeOf(), sizeof(ArgValueStorage)) &&
716 q20::cmp_less_equal(type.alignOf(), alignof(ArgValueStorage)));
717}
718
719/*!
720 \class QSignalBlocker
721 \brief Exception-safe wrapper around QObject::blockSignals().
722 \since 5.3
723 \ingroup objectmodel
724 \inmodule QtCore
725
726 \reentrant
727
728 QSignalBlocker can be used wherever you would otherwise use a
729 pair of calls to QObject::blockSignals(). It blocks signals in its
730 constructor and in the destructor it resets the state to what
731 it was before the constructor ran.
732
733 \snippet code/src_corelib_kernel_qobject.cpp 53
734 is thus equivalent to
735 \snippet code/src_corelib_kernel_qobject.cpp 54
736
737 except the code using QSignalBlocker is safe in the face of
738 exceptions.
739
740 \sa QMutexLocker, QEventLoopLocker
741*/
742
743/*!
744 \fn QSignalBlocker::QSignalBlocker(QObject *object)
745
746 Constructor. Calls \a{object}->blockSignals(true).
747*/
748
749/*!
750 \fn QSignalBlocker::QSignalBlocker(QObject &object)
751 \overload
752
753 Calls \a{object}.blockSignals(true).
754*/
755
756/*!
757 \fn QSignalBlocker::QSignalBlocker(QSignalBlocker &&other)
758
759 Move-constructs a signal blocker from \a other. \a other will have
760 a no-op destructor, while responsibility for restoring the
761 QObject::signalsBlocked() state is transferred to the new object.
762*/
763
764/*!
765 \fn QSignalBlocker &QSignalBlocker::operator=(QSignalBlocker &&other)
766
767 Move-assigns this signal blocker from \a other. \a other will have
768 a no-op destructor, while responsibility for restoring the
769 QObject::signalsBlocked() state is transferred to this object.
770
771 The object's signals this signal blocker was blocking prior to
772 being moved to, if any, are unblocked \e except in the case where
773 both instances block the same object's signals and \c *this is
774 unblocked while \a other is not, at the time of the move.
775*/
776
777/*!
778 \fn QSignalBlocker::~QSignalBlocker()
779
780 Destructor. Restores the QObject::signalsBlocked() state to what it
781 was before the constructor ran, unless unblock() has been called
782 without a following reblock(), in which case it does nothing.
783*/
784
785/*!
786 \fn void QSignalBlocker::reblock()
787
788 Re-blocks signals after a previous unblock().
789
790 The numbers of reblock() and unblock() calls are not counted, so
791 every reblock() undoes any number of unblock() calls.
792*/
793
794/*!
795 \fn void QSignalBlocker::unblock()
796
797 Temporarily restores the QObject::signalsBlocked() state to what
798 it was before this QSignalBlocker's constructor ran. To undo, use
799 reblock().
800
801 The numbers of reblock() and unblock() calls are not counted, so
802 every unblock() undoes any number of reblock() calls.
803*/
804
805/*!
806 \fn void QSignalBlocker::dismiss()
807 \since 6.7
808 Dismisses the QSignalBlocker. It will no longer access the QObject
809 passed to its constructor. unblock(), reblock(), as well as
810 ~QSignalBlocker() will have no effect.
811*/
812
813/*!
814 \class QObject
815 \inmodule QtCore
816 \brief The QObject class is the base class of all Qt objects.
817
818 \ingroup objectmodel
819
820 \reentrant
821
822 QObject is the heart of the Qt \l{Object Model}. The central
823 feature in this model is a very powerful mechanism for seamless
824 object communication called \l{signals and slots}. You can
825 connect a signal to a slot with connect() and destroy the
826 connection with disconnect(). To avoid never ending notification
827 loops you can temporarily block signals with blockSignals(). The
828 protected functions connectNotify() and disconnectNotify() make
829 it possible to track connections.
830
831 QObjects organize themselves in \l {Object Trees & Ownership}
832 {object trees}. When you create a QObject with another object as
833 parent, the object will automatically add itself to the parent's
834 children() list. The parent takes ownership of the object; i.e.,
835 it will automatically delete its children in its destructor. You
836 can look for an object by name and optionally type using
837 findChild() or findChildren().
838
839 Every object has an objectName() and its class name can be found
840 via the corresponding metaObject() (see QMetaObject::className()).
841 You can determine whether the object's class inherits another
842 class in the QObject inheritance hierarchy by using the
843 inherits() function.
844
845 When an object is deleted, it emits a destroyed() signal. You can
846 catch this signal to avoid dangling references to QObjects.
847
848 QObjects can receive events through event() and filter the events
849 of other objects. See installEventFilter() and eventFilter() for
850 details. A convenience handler, childEvent(), can be reimplemented
851 to catch child events.
852
853 Last but not least, QObject provides the basic timer support in
854 Qt; see QChronoTimer for high-level support for timers.
855
856 Notice that the Q_OBJECT macro is mandatory for any object that
857 implements signals, slots or properties. You also need to run the
858 \l{moc}{Meta Object Compiler} on the source file. We strongly
859 recommend the use of this macro in all subclasses of QObject
860 regardless of whether or not they actually use signals, slots and
861 properties, since failure to do so may lead certain functions to
862 exhibit strange behavior.
863
864 All Qt widgets inherit QObject. The convenience function
865 isWidgetType() returns whether an object is actually a widget. It
866 is much faster than
867 \l{qobject_cast()}{qobject_cast}<QWidget *>(\e{obj}) or
868 \e{obj}->\l{inherits()}{inherits}("QWidget").
869
870 Some QObject functions, e.g. children(), return a QObjectList.
871 QObjectList is a typedef for QList<QObject *>.
872
873 \section1 Thread Affinity
874
875 A QObject instance is said to have a \e{thread affinity}, or that
876 it \e{lives} in a certain thread. When a QObject receives a
877 \l{Qt::QueuedConnection}{queued signal} or a \l{The Event
878 System#Sending Events}{posted event}, the slot or event handler
879 will run in the thread that the object lives in.
880
881 \note If a QObject has no thread affinity (that is, if thread()
882 returns zero), or if it lives in a thread that has no running event
883 loop, then it cannot receive queued signals or posted events.
884
885 By default, a QObject lives in the thread in which it is created.
886 An object's thread affinity can be queried using thread() and
887 changed using moveToThread().
888
889 All QObjects must live in the same thread as their parent. Consequently:
890
891 \list
892 \li setParent() will fail if the two QObjects involved live in
893 different threads.
894 \li When a QObject is moved to another thread, all its children
895 will be automatically moved too.
896 \li moveToThread() will fail if the QObject has a parent.
897 \li If QObjects are created within QThread::run(), they cannot
898 become children of the QThread object because the QThread does
899 not live in the thread that calls QThread::run().
900 \endlist
901
902 \note A QObject's member variables \e{do not} automatically become
903 its children. The parent-child relationship must be set by either
904 passing a pointer to the child's \l{QObject()}{constructor}, or by
905 calling setParent(). Without this step, the object's member variables
906 will remain in the old thread when moveToThread() is called.
907
908 \target No copy constructor
909 \section1 No Copy Constructor or Assignment Operator
910
911 QObject has neither a copy constructor nor an assignment operator.
912 This is by design. Actually, they are declared, but in a
913 \c{private} section with the macro Q_DISABLE_COPY(). In fact, all
914 Qt classes derived from QObject (direct or indirect) use this
915 macro to declare their copy constructor and assignment operator to
916 be private. The reasoning is found in the discussion on
917 \l{Identity vs Value} {Identity vs Value} on the Qt \l{Object
918 Model} page.
919
920 The main consequence is that you should use pointers to QObject
921 (or to your QObject subclass) where you might otherwise be tempted
922 to use your QObject subclass as a value. For example, without a
923 copy constructor, you can't use a subclass of QObject as the value
924 to be stored in one of the container classes. You must store
925 pointers.
926
927 \section1 Auto-Connection
928
929 Qt's meta-object system provides a mechanism to automatically connect
930 signals and slots between QObject subclasses and their children. As long
931 as objects are defined with suitable object names, and slots follow a
932 simple naming convention, this connection can be performed at run-time
933 by the QMetaObject::connectSlotsByName() function.
934
935 \l uic generates code that invokes this function to enable
936 auto-connection to be performed between widgets on forms created
937 with \e{\QD}. More information about using auto-connection with \e{\QD} is
938 given in the \l{Using a Qt Widgets Designer UI File in Your Application} section of
939 the \l{Qt Widgets Designer Manual}{\QD} manual.
940
941 \section1 Dynamic Properties
942
943 Dynamic properties can be added to and removed from QObject
944 instances at run-time. Dynamic properties do not need to be declared at
945 compile-time, yet they provide the same advantages as static properties
946 and are manipulated using the same API - using property() to read them
947 and setProperty() to write them.
948
949 Dynamic properties are supported by
950 \l{Qt Widgets Designer's Widget Editing Mode#The Property Editor}{\QD},
951 and both standard Qt widgets and user-created forms can be given dynamic
952 properties.
953
954 \section1 Internationalization (I18n)
955
956 All QObject subclasses support Qt's translation features, making it possible
957 to translate an application's user interface into different languages.
958
959 To make user-visible text translatable, it must be wrapped in calls to
960 the tr() function. This is explained in detail in the
961 \l{Writing Source Code for Translation} document.
962
963 \sa QMetaObject, QPointer, QObjectCleanupHandler, Q_DISABLE_COPY()
964 \sa {Object Trees & Ownership}
965*/
966
967/*****************************************************************************
968 QObject member functions
969 *****************************************************************************/
970
971// check the constructor's parent thread argument
972static bool check_parent_thread(QObject *parent,
973 QThreadData *parentThreadData,
974 QThreadData *currentThreadData)
975{
976 if (parent && parentThreadData != currentThreadData) {
977 QThread *parentThread = parentThreadData->thread.loadAcquire();
978 QThread *currentThread = currentThreadData->thread.loadAcquire();
979 qWarning("QObject: Cannot create children for a parent that is in a different thread.\n"
980 "(Parent is %s(%p), parent's thread is %s(%p), current thread is %s(%p)",
981 parent->metaObject()->className(),
982 parent,
983 parentThread ? parentThread->metaObject()->className() : "QThread",
984 parentThread,
985 currentThread ? currentThread->metaObject()->className() : "QThread",
986 currentThread);
987 return false;
988 }
989 return true;
990}
991
992/*!
993 Constructs an object with parent object \a parent.
994
995 The parent of an object may be viewed as the object's owner. For
996 instance, a \l{QDialog}{dialog box} is the parent of the \uicontrol{OK}
997 and \uicontrol{Cancel} buttons it contains.
998
999 The destructor of a parent object destroys all child objects.
1000
1001 Setting \a parent to \nullptr constructs an object with no parent. If the
1002 object is a widget, it will become a top-level window.
1003
1004 \sa parent(), findChild(), findChildren()
1005*/
1006
1007QObject::QObject(QObject *parent)
1008 : QObject(*new QObjectPrivate, parent)
1009{
1010}
1011
1012/*!
1013 \internal
1014 */
1015QObject::QObject(QObjectPrivate &dd, QObject *parent)
1016 : d_ptr(&dd)
1017{
1018 Q_ASSERT_X(this != parent, Q_FUNC_INFO, "Cannot parent a QObject to itself");
1019
1020 Q_D(QObject);
1021 d_ptr->q_ptr = this;
1022 QThreadData *parentThreadData = parent ? parent->d_func()->threadData.loadRelaxed() : nullptr;
1023 QThreadData *threadData;
1024 if (parent && !parentThreadData->thread.loadRelaxed()) {
1025 threadData = parentThreadData;
1026 } else {
1027 threadData = QThreadData::current();
1028 if (!check_parent_thread(parent, parentThreadData, threadData))
1029 parent = nullptr;
1030 }
1031 threadData->ref();
1032 d->threadData.storeRelaxed(threadData);
1033
1034 if (parent) {
1035 // Protect against setParent() throwing (we send an event to the parent).
1036 auto scopeDeref = qScopeGuard([threadData] { threadData->deref(); });
1037 if (d->willBeWidget) {
1038 d->parent = parent;
1039 d->parent->d_func()->children.append(this);
1040 // no events sent here, this is done at the end of the QWidget constructor
1041 } else {
1042 setParent(parent);
1043 }
1044 scopeDeref.dismiss();
1045 }
1046
1047 // Neither the hook nor the trace should throw or otherwise halt this
1048 // object's creation. It's a bug in them if they do.
1049 if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
1050 reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(this);
1051 Q_TRACE(QObject_ctor, this);
1052}
1053
1054void QObjectPrivate::clearBindingStorage()
1055{
1056 bindingStorage.clear();
1057}
1058
1059/*!
1060 Destroys the object, deleting all its child objects.
1061
1062 All signals to and from the object are automatically disconnected, and
1063 any pending posted events for the object are removed from the event
1064 queue. However, it is often safer to use deleteLater() rather than
1065 deleting a QObject subclass directly.
1066
1067 \warning All child objects are deleted. If any of these objects
1068 are on the stack or global, sooner or later your program will
1069 crash. We do not recommend holding pointers to child objects from
1070 outside the parent. If you still do, the destroyed() signal gives
1071 you an opportunity to detect when an object is destroyed.
1072
1073 \warning Deleting a QObject while it is handling an event
1074 delivered to it can cause a crash. You must not delete the QObject
1075 directly if it exists in a different thread than the one currently
1076 executing. Use deleteLater() instead, which will cause the event
1077 loop to delete the object after all pending events have been
1078 delivered to it.
1079
1080 \sa deleteLater()
1081*/
1082
1083QObject::~QObject()
1084{
1085 Q_D(QObject);
1086 d->wasDeleted = true;
1087 d->blockSig = 0; // unblock signals so we always emit destroyed()
1088
1089 if (!d->bindingStorage.isValid()) {
1090 // this might be the case after an incomplete thread-move
1091 // remove this object from the pending list in that case
1092 if (QThread *ownThread = thread()) {
1093 auto *privThread = static_cast<QThreadPrivate *>(
1094 QObjectPrivate::get(ownThread));
1095 privThread->removeObjectWithPendingBindingStatusChange(this);
1096 }
1097 }
1098
1099 // If we reached this point, we need to clear the binding data
1100 // as the corresponding properties are no longer useful
1101 d->clearBindingStorage();
1102
1103 QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.loadRelaxed();
1104 if (sharedRefcount) {
1105 if (sharedRefcount->strongref.loadRelaxed() > 0) {
1106 qWarning("QObject: shared QObject was deleted directly. The program is malformed and may crash.");
1107 // but continue deleting, it's too late to stop anyway
1108 }
1109
1110 // indicate to all QWeakPointers that this QObject has now been deleted
1111 sharedRefcount->strongref.storeRelaxed(0);
1112 if (!sharedRefcount->weakref.deref())
1113 delete sharedRefcount;
1114 }
1115
1116 if (!d->wasWidget && d->isSignalConnected(0)) {
1117 emit destroyed(this);
1118 }
1119
1120 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::destroyed)
1121 QAbstractDeclarativeData::destroyed(d->declarativeData, this);
1122
1123 QObjectPrivate::ConnectionData *cd = d->connections.loadAcquire();
1124 if (cd) {
1125 if (cd->currentSender) {
1126 cd->currentSender->receiverDeleted();
1127 cd->currentSender = nullptr;
1128 }
1129
1130 QBasicMutex *signalSlotMutex = signalSlotLock(this);
1131 QMutexLocker locker(signalSlotMutex);
1132
1133 // disconnect all receivers
1134 int receiverCount = cd->signalVectorCount();
1135 for (int signal = -1; signal < receiverCount; ++signal) {
1136 QObjectPrivate::ConnectionList &connectionList = cd->connectionsForSignal(signal);
1137
1138 while (QObjectPrivate::Connection *c = connectionList.first.loadRelaxed()) {
1139 Q_ASSERT(c->receiver.loadAcquire());
1140
1141 QBasicMutex *m = signalSlotLock(c->receiver.loadRelaxed());
1142 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1143 if (c == connectionList.first.loadAcquire() && c->receiver.loadAcquire()) {
1144 cd->removeConnection(c);
1145 Q_ASSERT(connectionList.first.loadRelaxed() != c);
1146 }
1147 if (needToUnlock)
1148 m->unlock();
1149 }
1150 }
1151
1152 /* Disconnect all senders:
1153 */
1154 const Qt::HANDLE currentThreadId = QThread::currentThreadId();
1155 while (QObjectPrivate::Connection *node = cd->senders) {
1156 Q_ASSERT(node->receiver.loadAcquire());
1157 QObject *sender = node->sender;
1158 // Notify sender before removing the connection from its list. If sender is being
1159 // destroyed too, this makes its destructor block on the receiver's lock (which we
1160 // hold) and not finish until we release it, so sender stays alive while
1161 // disconnectNotifySender() touches it.
1162 disconnectNotifySender(sender, node->signal_index, currentThreadId);
1163 QBasicMutex *m = signalSlotLock(sender);
1164 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1165 //the node has maybe been removed while the mutex was unlocked in relock?
1166 if (node != cd->senders) {
1167 // We hold the wrong mutex
1168 Q_ASSERT(needToUnlock);
1169 m->unlock();
1170 continue;
1171 }
1172
1173 QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections.loadRelaxed();
1174 Q_ASSERT(senderData);
1175
1176 QtPrivate::QSlotObjectBase *slotObj = nullptr;
1177 if (node->isSlotObject) {
1178 slotObj = node->slotObj;
1179 node->isSlotObject = false;
1180 }
1181
1182 senderData->removeConnection(node);
1183 /*
1184 When we unlock, another thread has the chance to delete/modify sender data.
1185 Thus we need to call cleanOrphanedConnections before unlocking. We use the
1186 variant of the function which assumes that the lock is already held to avoid
1187 a deadlock.
1188 We need to hold m, the sender lock. Considering that we might execute arbitrary user
1189 code, we should already release the signalSlotMutex here – unless they are the same.
1190 */
1191 const bool locksAreTheSame = signalSlotMutex == m;
1192 if (!locksAreTheSame)
1193 locker.unlock();
1194 senderData->cleanOrphanedConnections(
1195 sender,
1196 QObjectPrivate::ConnectionData::AlreadyLockedAndTemporarilyReleasingLock
1197 );
1198 if (needToUnlock)
1199 m->unlock();
1200
1201 if (locksAreTheSame) // otherwise already unlocked
1202 locker.unlock();
1203 if (slotObj)
1204 slotObj->destroyIfLastRef();
1205 locker.relock();
1206 }
1207
1208 // invalidate all connections on the object and make sure
1209 // activate() will skip them
1210 cd->currentConnectionId.storeRelaxed(0);
1211 }
1212 if (cd && !cd->ref.deref())
1213 delete cd;
1214 d->connections.storeRelaxed(nullptr);
1215
1216 if (!d->children.isEmpty())
1217 d->deleteChildren();
1218
1219 if (Q_UNLIKELY(qtHookData[QHooks::RemoveQObject]))
1220 reinterpret_cast<QHooks::RemoveQObjectCallback>(qtHookData[QHooks::RemoveQObject])(this);
1221
1222 Q_TRACE(QObject_dtor, this);
1223
1224 if (d->parent) // remove it from parent object
1225 d->setParent_helper(nullptr);
1226}
1227
1228inline QObjectPrivate::Connection::~Connection()
1229{
1230 if (ownArgumentTypes) {
1231 const int *v = argumentTypes.loadRelaxed();
1232 if (v != &DIRECT_CONNECTION_ONLY)
1233 delete[] v;
1234 }
1235 if (isSlotObject)
1236 slotObj->destroyIfLastRef();
1237}
1238
1239
1240/*!
1241 \fn const QMetaObject *QObject::metaObject() const
1242
1243 Returns a pointer to the meta-object of this object.
1244
1245 A meta-object contains information about a class that inherits
1246 QObject, e.g. class name, superclass name, properties, signals and
1247 slots. Every QObject subclass that contains the Q_OBJECT macro will have a
1248 meta-object.
1249
1250 The meta-object information is required by the signal/slot
1251 connection mechanism and the property system. The inherits()
1252 function also makes use of the meta-object.
1253
1254 If you have no pointer to an actual object instance but still
1255 want to access the meta-object of a class, you can use \l
1256 staticMetaObject.
1257
1258 Example:
1259
1260 \snippet code/src_corelib_kernel_qobject.cpp 1
1261
1262 \sa staticMetaObject
1263*/
1264
1265/*!
1266 \variable QObject::staticMetaObject
1267
1268 This variable stores the meta-object for the class.
1269
1270 A meta-object contains information about a class that inherits
1271 QObject, e.g. class name, superclass name, properties, signals and
1272 slots. Every class that contains the Q_OBJECT macro will also have
1273 a meta-object.
1274
1275 The meta-object information is required by the signal/slot
1276 connection mechanism and the property system. The inherits()
1277 function also makes use of the meta-object.
1278
1279 If you have a pointer to an object, you can use metaObject() to
1280 retrieve the meta-object associated with that object.
1281
1282 Example:
1283
1284 \snippet code/src_corelib_kernel_qobject.cpp 2
1285
1286 \sa metaObject()
1287*/
1288
1289/*!
1290 \fn template <class T> T qobject_cast(QObject *object)
1291 \fn template <class T> T qobject_cast(const QObject *object)
1292 \relates QObject
1293
1294 Returns the given \a object cast to type T if the object is of type
1295 T (or of a subclass); otherwise returns \nullptr. If \a object is
1296 \nullptr then it will also return \nullptr.
1297
1298 The class T must inherit (directly or indirectly) QObject and be
1299 declared with the \l Q_OBJECT macro.
1300
1301 A class is considered to inherit itself.
1302
1303 Example:
1304
1305 \snippet code/src_corelib_kernel_qobject.cpp 3
1306
1307 The qobject_cast() function behaves similarly to the standard C++
1308 \c dynamic_cast(), with the advantages that it doesn't require
1309 RTTI support and it works across dynamic library boundaries.
1310
1311 qobject_cast() can also be used in conjunction with interfaces.
1312
1313 \warning If T isn't declared with the Q_OBJECT macro, this
1314 function's return value is undefined.
1315
1316 \sa QObject::inherits()
1317*/
1318
1319/*!
1320 \fn bool QObject::inherits(const char *className) const
1321
1322 Returns \c true if this object is an instance of a class that
1323 inherits \a className or a QObject subclass that inherits \a
1324 className; otherwise returns \c false.
1325
1326 A class is considered to inherit itself.
1327
1328 Example:
1329
1330 \snippet code/src_corelib_kernel_qobject.cpp 4
1331
1332 If you need to determine whether an object is an instance of a particular
1333 class for the purpose of casting it, consider using qobject_cast<Type *>(object)
1334 instead.
1335
1336 \sa metaObject(), qobject_cast()
1337*/
1338
1339/*!
1340 \property QObject::objectName
1341
1342 \brief the name of this object
1343
1344 You can find an object by name (and type) using findChild().
1345 You can find a set of objects with findChildren().
1346
1347 \snippet code/src_corelib_kernel_qobject.cpp 5
1348
1349 By default, this property contains an empty string.
1350
1351 \sa metaObject(), QMetaObject::className()
1352*/
1353
1354QString QObject::objectName() const
1355{
1356 Q_D(const QObject);
1357#if QT_CONFIG(thread)
1358 if (QThread::currentThreadId() != d->threadData.loadRelaxed()->threadId.loadRelaxed()) // Unsafe code path
1359 return d->extraData ? d->extraData->objectName.valueBypassingBindings() : QString();
1360#endif
1361 if (!d->extraData && QtPrivate::isAnyBindingEvaluating()) {
1362 QObjectPrivate *dd = const_cast<QObjectPrivate *>(d);
1363 // extraData is mutable, so this should be safe
1364 dd->extraData = new QObjectPrivate::ExtraData(dd);
1365 }
1366 return d->extraData ? d->extraData->objectName : QString();
1367}
1368
1369/*!
1370 \internal
1371 Only use if you know nothing can be bound yet. Usually used for
1372 internal objects that do get names.
1373*/
1374void QObjectPrivate::setObjectNameWithoutBindings(const QString &name)
1375{
1376 ensureExtraData();
1377 extraData->objectName.setValueBypassingBindings(name);
1378}
1379
1380/*!
1381 \fn void QObject::setObjectName(const QString &name)
1382 Sets the object's name to \a name.
1383*/
1384void QObject::doSetObjectName(const QString &name)
1385{
1386 Q_D(QObject);
1387
1388 d->ensureExtraData();
1389
1390 d->extraData->objectName.removeBindingUnlessInWrapper();
1391
1392 if (d->extraData->objectName.valueBypassingBindings() != name) {
1393 d->extraData->objectName.setValueBypassingBindings(name);
1394 d->extraData->objectName.notify(); // also emits a signal
1395 }
1396}
1397
1398/*!
1399 \overload
1400 \since 6.4
1401*/
1402void QObject::setObjectName(QAnyStringView name)
1403{
1404 Q_D(QObject);
1405
1406 d->ensureExtraData();
1407
1408 d->extraData->objectName.removeBindingUnlessInWrapper();
1409
1410 if (d->extraData->objectName.valueBypassingBindings() != name) {
1411 d->extraData->objectName.setValueBypassingBindings(name.toString());
1412 d->extraData->objectName.notify(); // also emits a signal
1413 }
1414}
1415
1416QBindable<QString> QObject::bindableObjectName()
1417{
1418 Q_D(QObject);
1419
1420 d->ensureExtraData();
1421
1422 return QBindable<QString>(&d->extraData->objectName);
1423}
1424
1425/*! \fn void QObject::objectNameChanged(const QString &objectName)
1426
1427 This signal is emitted after the object's name has been changed. The new object name is passed as \a objectName.
1428
1429 \sa QObject::objectName
1430*/
1431
1432/*!
1433 \fn bool QObject::isWidgetType() const
1434
1435 Returns \c true if the object is a widget; otherwise returns \c false.
1436
1437 Calling this function is equivalent to calling
1438 \c{inherits("QWidget")}, except that it is much faster.
1439*/
1440
1441/*!
1442 \fn bool QObject::isWindowType() const
1443
1444 Returns \c true if the object is a window; otherwise returns \c false.
1445
1446 Calling this function is equivalent to calling
1447 \c{inherits("QWindow")}, except that it is much faster.
1448*/
1449
1450/*!
1451 \fn bool QObject::isQuickItemType() const
1452
1453 Returns \c true if the object is a QQuickItem; otherwise returns \c false.
1454
1455 Calling this function is equivalent to calling
1456 \c{inherits("QQuickItem")}, except that it is much faster.
1457
1458 \since 6.4
1459*/
1460
1461/*!
1462 Returns whether the object has been created by the QML engine or
1463 ownership has been explicitly set via QJSEngine::setObjectOwnership().
1464 \since 6.11
1465*/
1466bool QObject::isQmlExposed() const noexcept
1467{
1468 Q_D(const QObject);
1469 return !d->isDeletingChildren && d->declarativeData;
1470}
1471
1472/*!
1473 This virtual function receives events to an object and should
1474 return true if the event \a e was recognized and processed.
1475
1476 The event() function can be reimplemented to customize the
1477 behavior of an object.
1478
1479 Make sure you call the parent event class implementation
1480 for all the events you did not handle.
1481
1482 Example:
1483
1484 \snippet code/src_corelib_kernel_qobject.cpp 52
1485
1486 \sa installEventFilter(), timerEvent(), QCoreApplication::sendEvent(),
1487 QCoreApplication::postEvent()
1488*/
1489
1490bool QObject::event(QEvent *e)
1491{
1492 switch (e->type()) {
1493 case QEvent::Timer:
1494 timerEvent((QTimerEvent *)e);
1495 break;
1496
1497 case QEvent::ChildAdded:
1498 case QEvent::ChildPolished:
1499 case QEvent::ChildRemoved:
1500 childEvent((QChildEvent *)e);
1501 break;
1502
1503 case QEvent::DeferredDelete:
1504 delete this;
1505 break;
1506
1507 case QEvent::DisconnectNotify: {
1508 // Posted by disconnectNotifySender(), now that we are in our own thread
1509 const QMetaObject *mo = metaObject();
1510 const int signalIndex = static_cast<QDisconnectNotifyEvent *>(e)->signalIndex();
1511 disconnectNotify(QMetaObjectPrivate::signal(mo, signalIndex));
1512 break;
1513 }
1514
1515 case QEvent::MetaCall:
1516 {
1517 QAbstractMetaCallEvent *mce = static_cast<QAbstractMetaCallEvent*>(e);
1518
1519 QObjectPrivate::ConnectionData *connections = d_func()->connections.loadAcquire();
1520 if (!connections) {
1521 QMutexLocker locker(signalSlotLock(this));
1522 d_func()->ensureConnectionData();
1523 connections = d_func()->connections.loadRelaxed();
1524 }
1525 QObjectPrivate::Sender sender(this, const_cast<QObject*>(mce->sender()), mce->signalId(), connections);
1526
1527 mce->placeMetaCall(this);
1528 break;
1529 }
1530
1531 case QEvent::ThreadChange: {
1532 Q_D(QObject);
1533 QThreadData *threadData = d->threadData.loadRelaxed();
1534 QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
1535 if (eventDispatcher) {
1536 QList<QAbstractEventDispatcher::TimerInfoV2> timers = eventDispatcher->timersForObject(this);
1537 if (!timers.isEmpty()) {
1538 const bool res = eventDispatcher->unregisterTimers(this);
1539 // do not to release our timer ids back to the pool (since the timer ids are moving to a new thread).
1540 Q_ASSERT_X(res, Q_FUNC_INFO,
1541 "QAbstractEventDispatcher::unregisterTimers() returned false,"
1542 " but there are timers associated with this object.");
1543 auto reRegisterTimers = [this, timers = std::move(timers)]() {
1544 QAbstractEventDispatcher *eventDispatcher =
1545 d_func()->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
1546 for (const auto &ti : timers)
1547 eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType, this);
1548 };
1549 QMetaObject::invokeMethod(this, std::move(reRegisterTimers), Qt::QueuedConnection);
1550 }
1551 }
1552 break;
1553 }
1554
1555 default:
1556 if (e->type() >= QEvent::User) {
1557 customEvent(e);
1558 break;
1559 }
1560 return false;
1561 }
1562 return true;
1563}
1564
1565/*!
1566 \fn void QObject::timerEvent(QTimerEvent *event)
1567
1568 This event handler can be reimplemented in a subclass to receive
1569 timer events for the object.
1570
1571 QChronoTimer provides higher-level interfaces to the timer functionality,
1572 and also more general information about timers. The timer event is passed
1573 in the \a event parameter.
1574
1575 \sa startTimer(), killTimer(), event()
1576*/
1577
1578void QObject::timerEvent(QTimerEvent *)
1579{
1580}
1581
1582
1583/*!
1584 This event handler can be reimplemented in a subclass to receive
1585 child events. The event is passed in the \a event parameter.
1586
1587 QEvent::ChildAdded and QEvent::ChildRemoved events are sent to
1588 objects when children are added or removed. In both cases you can
1589 only rely on the child being a QObject, or if isWidgetType()
1590 returns \c true, a QWidget. (This is because, in the
1591 \l{QEvent::ChildAdded}{ChildAdded} case, the child is not yet
1592 fully constructed, and in the \l{QEvent::ChildRemoved}{ChildRemoved}
1593 case it might have been destructed already).
1594
1595 QEvent::ChildPolished events are sent to widgets when children
1596 are polished, or when polished children are added. If you receive
1597 a child polished event, the child's construction is usually
1598 completed. However, this is not guaranteed, and multiple polish
1599 events may be delivered during the execution of a widget's
1600 constructor.
1601
1602 For every child widget, you receive one
1603 \l{QEvent::ChildAdded}{ChildAdded} event, zero or more
1604 \l{QEvent::ChildPolished}{ChildPolished} events, and one
1605 \l{QEvent::ChildRemoved}{ChildRemoved} event.
1606
1607 The \l{QEvent::ChildPolished}{ChildPolished} event is omitted if
1608 a child is removed immediately after it is added. If a child is
1609 polished several times during construction and destruction, you
1610 may receive several child polished events for the same child,
1611 each time with a different virtual table.
1612
1613 \sa event()
1614*/
1615
1616void QObject::childEvent(QChildEvent * /* event */)
1617{
1618}
1619
1620
1621/*!
1622 This event handler can be reimplemented in a subclass to receive
1623 custom events. Custom events are user-defined events with a type
1624 value at least as large as the QEvent::User item of the
1625 QEvent::Type enum, and is typically a QEvent subclass. The event
1626 is passed in the \a event parameter.
1627
1628 \sa event(), QEvent
1629*/
1630void QObject::customEvent(QEvent * /* event */)
1631{
1632}
1633
1634
1635
1636/*!
1637 Filters events if this object has been installed as an event
1638 filter for the \a watched object.
1639
1640 In your reimplementation of this function, if you want to filter
1641 the \a event out, i.e. stop it being handled further, return
1642 true; otherwise return false.
1643
1644 Example:
1645 \snippet code/src_corelib_kernel_qobject.cpp 6
1646
1647 Notice in the example above that unhandled events are passed to
1648 the base class's eventFilter() function, since the base class
1649 might have reimplemented eventFilter() for its own internal
1650 purposes.
1651
1652 Some events, such as \l QEvent::ShortcutOverride must be explicitly
1653 accepted (by calling \l {QEvent::}{accept()} on them) in order to prevent
1654 propagation.
1655
1656 \warning If you delete the receiver object in this function, be
1657 sure to return true. Otherwise, Qt will forward the event to the
1658 deleted object and the program might crash.
1659
1660 \sa installEventFilter()
1661*/
1662
1663bool QObject::eventFilter(QObject * /* watched */, QEvent * /* event */)
1664{
1665 return false;
1666}
1667
1668/*!
1669 \fn bool QObject::signalsBlocked() const
1670
1671 Returns \c true if signals are blocked; otherwise returns \c false.
1672
1673 Signals are not blocked by default.
1674
1675 \sa blockSignals(), QSignalBlocker
1676*/
1677
1678/*!
1679 If \a block is true, signals emitted by this object are blocked
1680 (i.e., emitting a signal will not invoke anything connected to it).
1681 If \a block is false, no such blocking will occur.
1682
1683 The return value is the previous value of signalsBlocked().
1684
1685 Note that the destroyed() signal will be emitted even if the signals
1686 for this object have been blocked.
1687
1688 Signals emitted while being blocked are not buffered.
1689
1690 \sa signalsBlocked(), QSignalBlocker
1691*/
1692
1693bool QObject::blockSignals(bool block) noexcept
1694{
1695 Q_D(QObject);
1696 bool previous = d->blockSig;
1697 d->blockSig = block;
1698 return previous;
1699}
1700
1701/*!
1702 Returns the thread in which the object lives.
1703
1704 \sa moveToThread()
1705*/
1706QThread *QObject::thread() const
1707{
1708 return d_func()->threadData.loadRelaxed()->thread.loadAcquire();
1709}
1710
1711/*!
1712 Changes the thread affinity for this object and its children and
1713 returns \c true on success. The object cannot be moved if it has a
1714 parent. Event processing will continue in the \a targetThread.
1715
1716 To move an object to the main thread, use QApplication::instance()
1717 to retrieve a pointer to the current application, and then use
1718 QApplication::thread() to retrieve the thread in which the
1719 application lives. For example:
1720
1721 \snippet code/src_corelib_kernel_qobject.cpp 7
1722
1723 If \a targetThread is \nullptr, all event processing for this object
1724 and its children stops, as they are no longer associated with any
1725 thread.
1726
1727 Note that all active timers for the object will be reset. The
1728 timers are first stopped in the current thread and restarted (with
1729 the same interval) in the \a targetThread. As a result, constantly
1730 moving an object between threads can postpone timer events
1731 indefinitely.
1732
1733 A QEvent::ThreadChange event is sent to this object just before
1734 the thread affinity is changed. You can handle this event to
1735 perform any special processing. Note that any new events that are
1736 posted to this object will be handled in the \a targetThread,
1737 provided it is not \nullptr: when it is \nullptr, no event processing
1738 for this object or its children can happen, as they are no longer
1739 associated with any thread.
1740
1741 \warning This function is \e not thread-safe; the current thread
1742 must be same as the current thread affinity. In other words, this
1743 function can only "push" an object from the current thread to
1744 another thread, it cannot "pull" an object from any arbitrary
1745 thread to the current thread. There is one exception to this rule
1746 however: objects with no thread affinity can be "pulled" to the
1747 current thread.
1748
1749 In Qt versions prior to 6.7, this function had no return value (\c void).
1750
1751 \sa thread()
1752 */
1753bool QObject::moveToThread(QThread *targetThread QT6_IMPL_NEW_OVERLOAD_TAIL)
1754{
1755 Q_D(QObject);
1756
1757 if (d->threadData.loadRelaxed()->thread.loadAcquire() == targetThread) {
1758 // object is already in this thread
1759 return true;
1760 }
1761
1762 if (d->parent != nullptr) {
1763 qWarning("QObject::moveToThread: Cannot move objects with a parent");
1764 return false;
1765 }
1766 if (d->isWidget) {
1767 qWarning("QObject::moveToThread: Widgets cannot be moved to a new thread");
1768 return false;
1769 }
1770 if (!d->bindingStorage.isEmpty()) {
1771 qWarning("QObject::moveToThread: Can not move objects that contain bindings or are used in bindings to a new thread.");
1772 return false;
1773 }
1774
1775 QThreadData *currentData = QThreadData::current();
1776 QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : nullptr;
1777 QThreadData *thisThreadData = d->threadData.loadAcquire();
1778 if (!thisThreadData->thread.loadRelaxed() && currentData == targetData) {
1779 // one exception to the rule: we allow moving objects with no thread affinity to the current thread
1780 currentData = thisThreadData;
1781 } else if (thisThreadData != currentData) {
1782 qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
1783 "Cannot move to target thread (%p)\n",
1784 currentData->thread.loadRelaxed(), thisThreadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() : nullptr);
1785
1786#ifdef Q_OS_DARWIN
1787 qWarning("You might be loading two sets of Qt binaries into the same process. "
1788 "Check that all plugins are compiled against the right Qt binaries. Export "
1789 "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.");
1790#endif
1791
1792 return false;
1793 }
1794
1795 // prepare to move
1796 d->moveToThread_helper();
1797
1798 if (!targetData)
1799 targetData = new QThreadData(0);
1800
1801 // make sure nobody adds/removes connections to this object while we're moving it
1802 QMutexLocker l(signalSlotLock(this));
1803
1804 QOrderedMutexLocker locker(&currentData->postEventList.mutex,
1805 &targetData->postEventList.mutex);
1806
1807 // keep currentData alive (since we've got it locked)
1808 currentData->ref();
1809
1810 // move the object
1811 auto threadPrivate = targetThread
1812 ? static_cast<QThreadPrivate *>(QThreadPrivate::get(targetThread))
1813 : nullptr;
1814 QBindingStatus *bindingStatus = threadPrivate
1815 ? threadPrivate->bindingStatus()
1816 : nullptr;
1817 if (threadPrivate && !bindingStatus) {
1818 bindingStatus = threadPrivate->addObjectWithPendingBindingStatusChange(this);
1819 }
1820 d_func()->setThreadData_helper(currentData, targetData, bindingStatus);
1821
1822 locker.unlock();
1823
1824 // now currentData can commit suicide if it wants to
1825 currentData->deref();
1826 return true;
1827}
1828
1829void QObjectPrivate::moveToThread_helper()
1830{
1831 Q_Q(QObject);
1832 QEvent e(QEvent::ThreadChange);
1833 QCoreApplication::sendEvent(q, &e);
1834 bindingStorage.clear();
1835 for (int i = 0; i < children.size(); ++i) {
1836 QObject *child = children.at(i);
1837 child->d_func()->moveToThread_helper();
1838 }
1839}
1840
1841void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status)
1842{
1843 Q_Q(QObject);
1844
1845 if (status) {
1846 // the new thread is already running
1847 this->bindingStorage.bindingStatus = status;
1848 }
1849
1850 // move posted events
1851 qsizetype eventsMoved = 0;
1852 for (qsizetype i = 0; i < currentData->postEventList.size(); ++i) {
1853 const QPostEvent &pe = currentData->postEventList.at(i);
1854 if (!pe.event)
1855 continue;
1856 if (pe.receiver == q) {
1857 // move this post event to the targetList
1858 targetData->postEventList.addEvent(pe);
1859 const_cast<QPostEvent &>(pe).event = nullptr;
1860 ++eventsMoved;
1861 }
1862 }
1863 if (eventsMoved > 0 && targetData->hasEventDispatcher()) {
1864 targetData->canWait = false;
1865 targetData->eventDispatcher.loadRelaxed()->wakeUp();
1866 }
1867
1868 // the current emitting thread shouldn't restore currentSender after calling moveToThread()
1869 ConnectionData *cd = connections.loadAcquire();
1870 if (cd) {
1871 if (cd->currentSender) {
1872 cd->currentSender->receiverDeleted();
1873 cd->currentSender = nullptr;
1874 }
1875
1876 // adjust the receiverThreadId values in the Connections
1877 if (cd) {
1878 auto *c = cd->senders;
1879 while (c) {
1880 QObject *r = c->receiver.loadRelaxed();
1881 if (r) {
1882 Q_ASSERT(r == q);
1883 targetData->ref();
1884 QThreadData *old = c->receiverThreadData.loadRelaxed();
1885 if (old)
1886 old->deref();
1887 c->receiverThreadData.storeRelaxed(targetData);
1888 }
1889 c = c->next;
1890 }
1891 }
1892
1893 }
1894
1895 // set new thread data
1896 targetData->ref();
1897 threadData.loadRelaxed()->deref();
1898
1899 // synchronizes with loadAcquire e.g. in QCoreApplication::postEvent
1900 threadData.storeRelease(targetData);
1901
1902 for (int i = 0; i < children.size(); ++i) {
1903 QObject *child = children.at(i);
1904 child->d_func()->setThreadData_helper(currentData, targetData, status);
1905 }
1906}
1907
1908//
1909// The timer flag hasTimer is set when startTimer is called.
1910// It is not reset when killing the timer because more than
1911// one timer might be active.
1912//
1913
1914/*!
1915 \fn int QObject::startTimer(int interval, Qt::TimerType timerType)
1916
1917 This is an overloaded function that will start a timer of type
1918 \a timerType and a timeout of \a interval milliseconds. This is
1919 equivalent to calling:
1920 \code
1921 startTimer(std::chrono::milliseconds{interval}, timerType);
1922 \endcode
1923
1924 \include timers-common.qdocinc negative-intervals-not-allowed
1925
1926 \sa timerEvent(), killTimer(), QChronoTimer, QBasicTimer
1927*/
1928
1929int QObject::startTimer(int interval, Qt::TimerType timerType)
1930{
1931 // no overflow can happen here:
1932 // 2^31 ms * 1,000,000 always fits a 64-bit signed integer type
1933 return startTimer(std::chrono::milliseconds{interval}, timerType);
1934}
1935
1936/*!
1937 \since 5.9
1938 \overload
1939
1940 Starts a timer and returns a timer identifier, or returns zero if
1941 it could not start a timer.
1942
1943 A timer event will occur every \a interval until killTimer()
1944 is called. If \a interval is equal to \c{std::chrono::duration::zero()},
1945 then the timer event occurs once every time control returns to the event
1946 loop. The ordering between these timer events and other sources of events
1947 is unspecified.
1948
1949 \include timers-common.qdocinc negative-intervals-not-allowed
1950
1951 The virtual timerEvent() function is called with the QTimerEvent
1952 event parameter class when a timer event occurs. Reimplement this
1953 function to get timer events.
1954
1955 If multiple timers are running, the QTimerEvent::id() method can be
1956 used to find out which timer was activated.
1957
1958 Example:
1959
1960 \snippet code/src_corelib_kernel_qobject.cpp 8
1961
1962 Note that the accuracy of the timer depends on the underlying operating
1963 system and hardware.
1964
1965 The \a timerType argument allows you to customize the accuracy of
1966 the timer. See Qt::TimerType for information on the different timer types.
1967 Most platforms support an accuracy of 20 milliseconds; some provide more.
1968 If Qt is unable to deliver the requested number of timer events, it will
1969 silently discard some.
1970
1971 The QTimer and QChronoTimer classes provide a high-level programming
1972 interface with single-shot timers and timer signals instead of
1973 events. There is also a QBasicTimer class that is more lightweight than
1974 QChronoTimer but less clumsy than using timer IDs directly.
1975
1976 \note Starting from Qt 6.8 the type of \a interval
1977 is \c std::chrono::nanoseconds, prior to that it was \c
1978 std::chrono::milliseconds. This change is backwards compatible with
1979 older releases of Qt.
1980
1981 \note In Qt 6.8, QObject was changed to use Qt::TimerId to represent timer
1982 IDs. This method converts the TimerId to int for backwards compatibility
1983 reasons, however you can use Qt::TimerId to check the value returned by
1984 this method, for example:
1985 \snippet code/src_corelib_kernel_qobject.cpp invalid-timer-id
1986
1987 \sa timerEvent(), killTimer(), QChronoTimer, QBasicTimer
1988*/
1989int QObject::startTimer(std::chrono::nanoseconds interval, Qt::TimerType timerType)
1990{
1991 Q_D(QObject);
1992
1993 using namespace std::chrono_literals;
1994
1995 if (interval < 0ns) {
1996 qWarning("QObject::startTimer: negative intervals aren't allowed; the "
1997 "interval will be set to 1ms.");
1998 interval = 1ms;
1999 }
2000
2001 auto thisThreadData = d->threadData.loadRelaxed();
2002 if (Q_UNLIKELY(thisThreadData != QThreadData::current())) {
2003 qWarning("QObject::startTimer: Timers cannot be started from another thread");
2004 return 0;
2005 }
2006
2007 auto dispatcher = thisThreadData->eventDispatcher.loadRelaxed();
2008 if (Q_UNLIKELY(!dispatcher)) {
2009 qWarning("QObject::startTimer: current thread's event dispatcher has already been destroyed");
2010 return 0;
2011 }
2012
2013 Qt::TimerId timerId = dispatcher->registerTimer(interval, timerType, this);
2014 d->ensureExtraData();
2015 d->extraData->runningTimers.append(timerId);
2016 return int(timerId);
2017}
2018
2019/*!
2020 Kills the timer with timer identifier, \a id.
2021
2022 The timer identifier is returned by startTimer() when a timer
2023 event is started.
2024
2025 \sa timerEvent(), startTimer()
2026*/
2027
2028void QObject::killTimer(int id)
2029{
2030 killTimer(Qt::TimerId{id});
2031}
2032
2033/*!
2034 \since 6.8
2035 \overload
2036*/
2037void QObject::killTimer(Qt::TimerId id)
2038{
2039 Q_D(QObject);
2040 auto thisThreadData = d->threadData.loadRelaxed();
2041 if (thisThreadData->threadId.loadRelaxed() != QThread::currentThreadId()) {
2042 qWarning("QObject::killTimer: Timers cannot be stopped from another thread");
2043 return;
2044 }
2045 if (id > Qt::TimerId::Invalid) {
2046 qsizetype at = d->extraData ? d->extraData->runningTimers.indexOf(id) : -1;
2047 if (at == -1) {
2048 // timer isn't owned by this object
2049 qWarning("QObject::killTimer(): Error: timer id %d is not valid for object %p (%s, %ls), timer has not been killed",
2050 qToUnderlying(id),
2051 this,
2052 metaObject()->className(),
2053 qUtf16Printable(objectName()));
2054 return;
2055 }
2056
2057 if (thisThreadData->hasEventDispatcher())
2058 thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimer(id);
2059
2060 d->extraData->runningTimers.remove(at);
2061 QAbstractEventDispatcherPrivate::releaseTimerId(id);
2062 }
2063}
2064
2065/*!
2066 \fn QObject *QObject::parent() const
2067
2068 Returns a pointer to the parent object.
2069
2070 \sa children()
2071*/
2072
2073/*!
2074 \fn const QObjectList &QObject::children() const
2075
2076 Returns a list of child objects.
2077 The QObjectList class is defined in the \c{<QObject>} header
2078 file as the following:
2079
2080 \quotefromfile kernel/qobject.h
2081 \skipto /typedef .*QObjectList/
2082 \printuntil QObjectList
2083
2084 The first child added is the \l{QList::first()}{first} object in
2085 the list and the last child added is the \l{QList::last()}{last}
2086 object in the list, i.e. new children are appended at the end.
2087
2088 Note that the list order changes when QWidget children are
2089 \l{QWidget::raise()}{raised} or \l{QWidget::lower()}{lowered}. A
2090 widget that is raised becomes the last object in the list, and a
2091 widget that is lowered becomes the first object in the list.
2092
2093 \sa findChild(), findChildren(), parent(), setParent()
2094*/
2095
2096
2097/*!
2098 \fn template<typename T> T *QObject::findChild(QAnyStringView name, Qt::FindChildOptions options) const
2099
2100 Returns the child of this object that can be cast into type T and
2101 that is called \a name, or \nullptr if there is no such object.
2102 A null \a name argument causes all objects to be matched. An empty,
2103 non-null \a name matches only objects whose \l objectName is empty.
2104 The search is performed recursively, unless \a options specifies the
2105 option FindDirectChildrenOnly.
2106
2107 If there is more than one child matching the search, the most-direct
2108 ancestor is returned. If there are several most-direct ancestors, the
2109 first child in children() will be returned. In that case, it's better
2110 to use findChildren() to get the complete list of all children.
2111
2112 This example returns a child \c{QPushButton} of \c{parentWidget}
2113 named \c{"button1"}, even if the button isn't a direct child of
2114 the parent:
2115
2116 \snippet code/src_corelib_kernel_qobject.cpp 10
2117
2118 This example returns a \c{QListWidget} child of \c{parentWidget}:
2119
2120 \snippet code/src_corelib_kernel_qobject.cpp 11
2121
2122 This example returns a child \c{QPushButton} of \c{parentWidget}
2123 (its direct parent) named \c{"button1"}:
2124
2125 \snippet code/src_corelib_kernel_qobject.cpp 41
2126
2127 This example returns a \c{QListWidget} child of \c{parentWidget},
2128 its direct parent:
2129
2130 \snippet code/src_corelib_kernel_qobject.cpp 42
2131
2132 \note In Qt versions prior to 6.7, this function took \a name as
2133 \c{QString}, not \c{QAnyStringView}.
2134
2135 \sa findChildren()
2136*/
2137
2138/*!
2139 \fn template<typename T> T *QObject::findChild(Qt::FindChildOptions options) const
2140 \overload
2141 \since 6.7
2142
2143 Returns the child of this object that can be cast into type T, or
2144 \nullptr if there is no such object.
2145 The search is performed recursively, unless \a options specifies the
2146 option FindDirectChildrenOnly.
2147
2148 If there is more than one child matching the search, the most-direct ancestor
2149 is returned. If there are several most-direct ancestors, the first child in
2150 children() will be returned. In that case, it's better to use findChildren()
2151 to get the complete list of all children.
2152
2153 \sa findChildren()
2154*/
2155
2156/*!
2157 \fn template<typename T> QList<T> QObject::findChildren(QAnyStringView name, Qt::FindChildOptions options) const
2158
2159 Returns all children of this object with the given \a name that can be
2160 cast to type T, or an empty list if there are no such objects.
2161 A null \a name argument causes all objects to be matched, an empty one
2162 only those whose objectName is empty.
2163 The search is performed recursively, unless \a options specifies the
2164 option FindDirectChildrenOnly.
2165
2166 The following example shows how to find a list of child \c{QWidget}s of
2167 the specified \c{parentWidget} named \c{widgetname}:
2168
2169 \snippet code/src_corelib_kernel_qobject.cpp 12
2170
2171 This example returns all \c{QPushButton}s that are children of \c{parentWidget}:
2172
2173 \snippet code/src_corelib_kernel_qobject.cpp 13
2174
2175 This example returns all \c{QPushButton}s that are immediate children of \c{parentWidget}:
2176
2177 \snippet code/src_corelib_kernel_qobject.cpp 43
2178
2179 \note In Qt versions prior to 6.7, this function took \a name as
2180 \c{QString}, not \c{QAnyStringView}.
2181
2182 \sa findChild()
2183*/
2184
2185/*!
2186 \fn template<typename T> QList<T> QObject::findChildren(Qt::FindChildOptions options) const
2187 \overload
2188 \since 6.3
2189
2190 Returns all children of this object that can be cast to type T, or
2191 an empty list if there are no such objects.
2192 The search is performed recursively, unless \a options specifies the
2193 option FindDirectChildrenOnly.
2194
2195 \sa findChild()
2196*/
2197
2198/*!
2199 \fn template<typename T> QList<T> QObject::findChildren(const QRegularExpression &re, Qt::FindChildOptions options) const
2200 \overload findChildren()
2201
2202 \since 5.0
2203
2204 Returns the children of this object that can be cast to type T
2205 and that have names matching the regular expression \a re,
2206 or an empty list if there are no such objects.
2207 The search is performed recursively, unless \a options specifies the
2208 option FindDirectChildrenOnly.
2209*/
2210
2211/*!
2212 \fn template<typename T> T qFindChild(const QObject *obj, const QString &name)
2213 \relates QObject
2214 \overload qFindChildren()
2215 \deprecated [4.8]
2216
2217 This function is equivalent to
2218 \a{obj}->\l{QObject::findChild()}{findChild}<T>(\a name).
2219
2220 \note This function was provided as a workaround for MSVC 6
2221 which did not support member template functions. It is advised
2222 to use the other form in new code.
2223
2224 \sa QObject::findChild()
2225*/
2226
2227/*!
2228 \fn template<typename T> QList<T> qFindChildren(const QObject *obj, const QString &name)
2229 \relates QObject
2230 \overload qFindChildren()
2231 \deprecated [4.8]
2232
2233 This function is equivalent to
2234 \a{obj}->\l{QObject::findChildren()}{findChildren}<T>(\a name).
2235
2236 \note This function was provided as a workaround for MSVC 6
2237 which did not support member template functions. It is advised
2238 to use the other form in new code.
2239
2240 \sa QObject::findChildren()
2241*/
2242
2243static bool matches_objectName_non_null(QObject *obj, QAnyStringView name)
2244{
2245 if (auto ext = QObjectPrivate::get(obj)->extraData)
2246 return ext ->objectName.valueBypassingBindings() == name;
2247 return name.isEmpty();
2248}
2249
2250/*!
2251 \internal
2252*/
2253void qt_qFindChildren_helper(const QObject *parent, QAnyStringView name,
2254 const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
2255{
2256 Q_ASSERT(parent);
2257 Q_ASSERT(list);
2258 for (QObject *obj : parent->children()) {
2259 if (mo.cast(obj) && (name.isNull() || matches_objectName_non_null(obj, name)))
2260 list->append(obj);
2261 if (options & Qt::FindChildrenRecursively)
2262 qt_qFindChildren_helper(obj, name, mo, list, options);
2263 }
2264}
2265
2266#if QT_CONFIG(regularexpression)
2267/*!
2268 \internal
2269*/
2270void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re,
2271 const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
2272{
2273 Q_ASSERT(parent);
2274 Q_ASSERT(list);
2275 for (QObject *obj : parent->children()) {
2276 if (mo.cast(obj)) {
2277 QRegularExpressionMatch m = re.match(obj->objectName());
2278 if (m.hasMatch())
2279 list->append(obj);
2280 }
2281 if (options & Qt::FindChildrenRecursively)
2282 qt_qFindChildren_helper(obj, re, mo, list, options);
2283 }
2284}
2285#endif // QT_CONFIG(regularexpression)
2286
2287/*!
2288 \internal
2289*/
2290QObject *qt_qFindChild_helper(const QObject *parent, QAnyStringView name, const QMetaObject &mo, Qt::FindChildOptions options)
2291{
2292 Q_ASSERT(parent);
2293 for (QObject *obj : parent->children()) {
2294 if (mo.cast(obj) && (name.isNull() || matches_objectName_non_null(obj, name)))
2295 return obj;
2296 }
2297 if (options & Qt::FindChildrenRecursively) {
2298 for (QObject *child : parent->children()) {
2299 if (QObject *obj = qt_qFindChild_helper(child, name, mo, options))
2300 return obj;
2301 }
2302 }
2303 return nullptr;
2304}
2305
2306/*!
2307 Makes the object a child of \a parent.
2308
2309 \sa parent(), children()
2310*/
2311void QObject::setParent(QObject *parent)
2312{
2313 Q_D(QObject);
2314 Q_ASSERT(!d->isWidget);
2315 d->setParent_helper(parent);
2316}
2317
2318void QObjectPrivate::deleteChildren()
2319{
2320 Q_ASSERT_X(!isDeletingChildren, "QObjectPrivate::deleteChildren()", "isDeletingChildren already set, did this function recurse?");
2321 isDeletingChildren = true;
2322 // delete children objects
2323 // don't use qDeleteAll as the destructor of the child might
2324 // delete siblings
2325 for (int i = 0; i < children.size(); ++i) {
2326 currentChildBeingDeleted = children.at(i);
2327 children[i] = nullptr;
2328 delete currentChildBeingDeleted;
2329 }
2330 children.clear();
2331 currentChildBeingDeleted = nullptr;
2332 isDeletingChildren = false;
2333}
2334
2335void QObjectPrivate::setParent_helper(QObject *o)
2336{
2337 Q_Q(QObject);
2338 Q_ASSERT_X(q != o, Q_FUNC_INFO, "Cannot parent a QObject to itself");
2339#ifdef QT_DEBUG
2340 const auto checkForParentChildLoops = qScopeGuard([&](){
2341 int depth = 0;
2342 auto p = parent;
2343 while (p) {
2344 if (++depth == CheckForParentChildLoopsWarnDepth) {
2345 qWarning("QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
2346 "this is undefined behavior",
2347 q, q->metaObject()->className(), qPrintable(q->objectName()));
2348 }
2349 p = p->parent();
2350 }
2351 });
2352#endif
2353
2354 if (o == parent)
2355 return;
2356
2357 if (parent) {
2358 QObjectPrivate *parentD = parent->d_func();
2359 if (parentD->isDeletingChildren && wasDeleted
2360 && parentD->currentChildBeingDeleted == q) {
2361 // don't do anything since QObjectPrivate::deleteChildren() already
2362 // cleared our entry in parentD->children.
2363 } else {
2364 const qsizetype index = parentD->children.indexOf(q);
2365 if (index < 0) {
2366 // we're probably recursing into setParent() from a ChildRemoved event, don't do anything
2367 } else if (parentD->isDeletingChildren) {
2368 parentD->children[index] = nullptr;
2369 } else {
2370 parentD->children.removeAt(index);
2371 if (sendChildEvents && parentD->receiveChildEvents) {
2372 QChildEvent e(QEvent::ChildRemoved, q);
2373 QCoreApplication::sendEvent(parent, &e);
2374 }
2375 }
2376 }
2377 }
2378
2379 if (receiveParentEvents) {
2380 Q_ASSERT(!isWidget); // Handled in QWidget
2381 QEvent e(QEvent::ParentAboutToChange);
2382 QCoreApplication::sendEvent(q, &e);
2383 }
2384
2385 parent = o;
2386
2387 if (parent) {
2388 // object hierarchies are constrained to a single thread
2389 if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) {
2390 qWarning("QObject::setParent: Cannot set parent, new parent is in a different thread");
2391 parent = nullptr;
2392 return;
2393 }
2394 parent->d_func()->children.append(q);
2395 if (sendChildEvents && parent->d_func()->receiveChildEvents) {
2396 if (!isWidget) {
2397 QChildEvent e(QEvent::ChildAdded, q);
2398 QCoreApplication::sendEvent(parent, &e);
2399 }
2400 }
2401 }
2402
2403 if (receiveParentEvents) {
2404 Q_ASSERT(!isWidget); // Handled in QWidget
2405 QEvent e(QEvent::ParentChange);
2406 QCoreApplication::sendEvent(q, &e);
2407 }
2408}
2409
2410/*!
2411 \fn void QObject::installEventFilter(QObject *filterObj)
2412
2413 Installs an event filter \a filterObj on this object. For example:
2414 \snippet code/src_corelib_kernel_qobject.cpp 14
2415
2416 An event filter is an object that receives all events that are
2417 sent to this object. The filter can either stop the event or
2418 forward it to this object. The event filter \a filterObj receives
2419 events via its eventFilter() function. The eventFilter() function
2420 must return true if the event should be filtered, (i.e. stopped);
2421 otherwise it must return false.
2422
2423 If multiple event filters are installed on a single object, the
2424 filter that was installed last is activated first.
2425
2426 If \a filterObj has already been installed for this object,
2427 this function moves it so it acts as if it was installed last.
2428
2429 Here's a \c KeyPressEater class that eats the key presses of its
2430 monitored objects:
2431
2432 \snippet code/src_corelib_kernel_qobject.cpp 15
2433
2434 And here's how to install it on two widgets:
2435
2436 \snippet code/src_corelib_kernel_qobject.cpp 16
2437
2438 The QShortcut class, for example, uses this technique to intercept
2439 shortcut key presses.
2440
2441 \warning If you delete the receiver object in your eventFilter()
2442 function, be sure to return true. If you return false, Qt sends
2443 the event to the deleted object and the program will crash.
2444
2445 Note that the filtering object must be in the same thread as this
2446 object. If \a filterObj is in a different thread, this function does
2447 nothing. If either \a filterObj or this object are moved to a different
2448 thread after calling this function, the event filter will not be
2449 called until both objects have the same thread affinity again (it
2450 is \e not removed).
2451
2452 \sa removeEventFilter(), eventFilter(), event()
2453*/
2454
2455void QObject::installEventFilter(QObject *obj)
2456{
2457 Q_D(QObject);
2458 if (!obj)
2459 return;
2460 if (d->threadData.loadRelaxed() != obj->d_func()->threadData.loadRelaxed()) {
2461 qWarning("QObject::installEventFilter(): Cannot filter events for objects in a different thread.");
2462 return;
2463 }
2464
2465 d->ensureExtraData();
2466
2467 // clean up unused items in the list along the way:
2468 auto isNullOrEquals = [](auto obj) { return [obj](const auto &p) { return !p || p == obj; }; };
2469 d->extraData->eventFilters.removeIf(isNullOrEquals(obj));
2470 d->extraData->eventFilters.prepend(obj);
2471}
2472
2473/*!
2474 Removes an event filter object \a obj from this object. The
2475 request is ignored if such an event filter has not been installed.
2476
2477 All event filters for this object are automatically removed when
2478 this object is destroyed.
2479
2480 It is always safe to remove an event filter, even during event
2481 filter activation (i.e. from the eventFilter() function).
2482
2483 \sa installEventFilter(), eventFilter(), event()
2484*/
2485
2486void QObject::removeEventFilter(QObject *obj)
2487{
2488 Q_D(QObject);
2489 if (d->extraData) {
2490 for (auto &filter : d->extraData->eventFilters) {
2491 if (filter == obj) {
2492 filter = nullptr;
2493 break;
2494 }
2495 }
2496 }
2497}
2498
2499/*!
2500 \fn void QObject::destroyed(QObject *obj)
2501
2502 This signal is emitted immediately before the object \a obj is
2503 destroyed, after any instances of QPointer have been notified,
2504 and cannot be blocked.
2505
2506 All the objects's children are destroyed immediately after this
2507 signal is emitted.
2508
2509 \sa deleteLater(), QPointer
2510*/
2511
2512/*!
2513 \threadsafe
2514
2515 Schedules this object for deletion.
2516
2517 The object will be deleted when control returns to the event
2518 loop. If the event loop is not running when this function is
2519 called (e.g. deleteLater() is called on an object before
2520 QCoreApplication::exec()), the object will be deleted once the
2521 event loop is started. If deleteLater() is called after the main event loop
2522 has stopped, the object will not be deleted.
2523 If deleteLater() is called on an object that lives in a
2524 thread with no running event loop, the object will be destroyed when the
2525 thread finishes.
2526
2527 A common pattern when using a worker \c QObject in a \c QThread
2528 is to connect the thread's \c finished() signal to the worker's
2529 \c deleteLater() slot to ensure it is safely deleted:
2530
2531 \code
2532 connect(thread, &QThread::finished, worker, &QObject::deleteLater);
2533 \endcode
2534
2535 Note that entering and leaving a new event loop (e.g., by opening a modal
2536 dialog) will \e not perform the deferred deletion; for the object to be
2537 deleted, the control must return to the event loop from which deleteLater()
2538 was called. This does not apply to objects deleted while a previous, nested
2539 event loop was still running: the Qt event loop will delete those objects
2540 as soon as the new nested event loop starts.
2541
2542 In situations where Qt is not driving the event dispatcher via e.g.
2543 QCoreApplication::exec() or QEventLoop::exec(), deferred deletes
2544 will not be processed automatically. To ensure deferred deletion in
2545 this scenario, the following workaround can be used:
2546
2547 \code
2548 const auto *eventDispatcher = QThread::currentThread()->eventDispatcher();
2549 QObject::connect(eventDispatcher, &QAbstractEventDispatcher::aboutToBlock,
2550 QThread::currentThread(), []{
2551 if (QThread::currentThread()->loopLevel() == 0)
2552 QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
2553 }
2554 );
2555 \endcode
2556
2557 \sa destroyed(), QPointer
2558*/
2559void QObject::deleteLater()
2560{
2561#ifdef QT_DEBUG
2562 if (qApp == this)
2563 qWarning("You are deferring the delete of QCoreApplication, this may not work as expected.");
2564#endif
2565
2566
2567 // De-bounce QDeferredDeleteEvents. Use the post event list mutex
2568 // to guard access to deleteLaterCalled, so we don't need a separate
2569 // mutex in QObjectData.
2570 auto eventListLocker = QCoreApplicationPrivate::lockThreadPostEventList(this);
2571 if (!eventListLocker.threadData)
2572 return;
2573
2574 // FIXME: The deleteLaterCalled flag is part of a bit field,
2575 // so we likely have data races here, even with the mutex above,
2576 // as long as we're not guarding every access to the bit field.
2577
2578 Q_D(QObject);
2579 if (d->deleteLaterCalled)
2580 return;
2581
2582 d->deleteLaterCalled = true;
2583
2584 int loopLevel = 0;
2585 int scopeLevel = 0;
2586
2587 auto *objectThreadData = eventListLocker.threadData;
2588 if (objectThreadData == QThreadData::current()) {
2589 // Remember the current running eventloop for deleteLater
2590 // calls in the object's own thread.
2591
2592 // Events sent by non-Qt event handlers (such as glib) may not
2593 // have the scopeLevel set correctly. The scope level makes sure that
2594 // code like this:
2595 // foo->deleteLater();
2596 // qApp->processEvents(); // without passing QEvent::DeferredDelete
2597 // will not cause "foo" to be deleted before returning to the event loop.
2598
2599 loopLevel = objectThreadData->loopLevel;
2600 scopeLevel = objectThreadData->scopeLevel;
2601
2602 // If the scope level is 0 while loopLevel != 0, we are called from a
2603 // non-conformant code path, and our best guess is that the scope level
2604 // should be 1. (Loop level 0 is special: it means that no event loops
2605 // are running.)
2606 if (scopeLevel == 0 && loopLevel != 0)
2607 scopeLevel = 1;
2608 }
2609
2610 eventListLocker.unlock();
2611 QCoreApplication::postEvent(this,
2612 new QDeferredDeleteEvent(loopLevel, scopeLevel));
2613}
2614
2615/*!
2616 \internal
2617
2618 Destroys \a object in the thread it belongs to, via deleteLater(), so that its
2619 vtable and members are not touched from the wrong thread. Falls back to deleting
2620 it right away when that thread cannot run the deferred delete: it is the current
2621 thread, or it has no event dispatcher (never started, or torn down at application
2622 exit). This is meant for objects deleted from a thread that is usually not their
2623 own, e.g. a worker handed to a thread pool.
2624
2625 The thread and the dispatcher are read from the object's QThreadData, which stays
2626 alive as long as the object does, rather than from QThread, which the owning thread
2627 may be destroying concurrently.
2628*/
2629void QObjectPrivate::deleteInOwnThread(QObject *object)
2630{
2631 QThreadData *objectData = QObjectPrivate::get(object)->threadData.loadRelaxed();
2632 if (objectData->hasEventDispatcher()
2633 && objectData->threadId.loadRelaxed() != QThread::currentThreadId()) {
2634 object->deleteLater();
2635 } else {
2636 delete object;
2637 }
2638}
2639
2640/*!
2641 \fn QString QObject::tr(const char *sourceText, const char *disambiguation, int n)
2642 \reentrant
2643
2644 Returns a translated version of \a sourceText, optionally based on a
2645 \a disambiguation string and value of \a n for strings containing plurals;
2646 otherwise returns QString::fromUtf8(\a sourceText) if no appropriate
2647 translated string is available.
2648
2649 Example:
2650 \snippet ../widgets/itemviews/spreadsheet/spreadsheet.cpp implicit tr context
2651 \dots
2652
2653 If the same \a sourceText is used in different roles within the
2654 same context, an additional identifying string may be passed in
2655 \a disambiguation (\nullptr by default).
2656
2657 Example:
2658
2659 \snippet code/src_corelib_kernel_qobject.cpp 17
2660 \dots
2661
2662 See \l{Writing Source Code for Translation} for a detailed description of
2663 Qt's translation mechanisms in general, and the
2664 \l{Writing Source Code for Translation#Disambiguate Identical Text}
2665 {Disambiguate Identical Text} section for information on disambiguation.
2666
2667 \warning This method is reentrant only if all translators are
2668 installed \e before calling this method. Installing or removing
2669 translators while performing translations is not supported. Doing
2670 so will probably result in crashes or other undesirable behavior.
2671
2672 \sa QCoreApplication::translate(), {Internationalization with Qt}
2673*/
2674
2675/*****************************************************************************
2676 Signals and slots
2677 *****************************************************************************/
2678
2679namespace {
2680// This class provides (per-thread) storage for qFlagLocation()
2681class FlaggedDebugSignatures
2682{
2683 uint idx = 0;
2684 std::array<const char *, 2> locations = {}; // one for the SIGNAL, one for the SLOT
2685
2686public:
2687 void store(const char* method) noexcept
2688 { locations[idx++ % locations.size()] = method; }
2689
2690 bool contains(const char *method) const noexcept
2691 { return std::find(locations.begin(), locations.end(), method) != locations.end(); }
2692};
2693
2694Q_CONSTINIT static thread_local FlaggedDebugSignatures flaggedSignatures = {};
2695} // unnamed namespace
2696
2697const char *qFlagLocation(const char *method)
2698{
2699 flaggedSignatures.store(method);
2700 return method;
2701}
2702
2703static int extract_code(const char *member)
2704{
2705 // extract code, ensure QMETHOD_CODE <= code <= QSIGNAL_CODE
2706 return (((int)(*member) - '0') & 0x3);
2707}
2708
2709static const char *extract_location(const char *member)
2710{
2711 if (flaggedSignatures.contains(member)) {
2712 // signature includes location information after the first null-terminator
2713 const char *location = member + qstrlen(member) + 1;
2714 if (*location != '\0')
2715 return location;
2716 }
2717 return nullptr;
2718}
2719
2720static bool check_signal_macro(const QObject *sender, const char *signal,
2721 const char *func, const char *op)
2722{
2723 int sigcode = extract_code(signal);
2724 if (sigcode != QSIGNAL_CODE) {
2725 if (sigcode == QSLOT_CODE)
2726 qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s", func, op,
2727 sender->metaObject()->className(), signal + 1);
2728 else
2729 qCWarning(lcConnect, "QObject::%s: Use the SIGNAL macro to %s %s::%s", func, op,
2730 sender->metaObject()->className(), signal);
2731 return false;
2732 }
2733 return true;
2734}
2735
2736static bool check_method_code(int code, const QObject *object, const char *method, const char *func)
2737{
2738 if (code != QSLOT_CODE && code != QSIGNAL_CODE) {
2739 qCWarning(lcConnect,
2740 "QObject::%s: Use the SLOT or SIGNAL macro to "
2741 "%s %s::%s",
2742 func, func, object->metaObject()->className(), method);
2743 return false;
2744 }
2745 return true;
2746}
2747
2748#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
2749static void check_and_warn_non_slot(const char *func, const char *method, int membcode,
2750 const QMetaObject *rmeta, const QMetaMethod &rmethod)
2751{
2752 if (membcode == QSLOT_CODE && rmethod.methodType() != QMetaMethod::Slot) {
2753 // In Qt7 QMetaObject::indexOfSlot{,relative} will return -1 if `method`
2754 // isn't a slot.
2755 qCWarning(lcConnect,
2756 "QObject::%s: the SLOT() macro is used with a non-slot function: %s::%s. "
2757 "This currently works due to backwards-compatibility reasons. In Qt7 the "
2758 "SLOT() macro will work only for methods marked as slots.",
2759 func, rmeta->className(), method);
2760 }
2761}
2762#endif // QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
2763
2765static void err_method_notfound(const QObject *object,
2766 const char *method, const char *func)
2767{
2768 const char *type = "method";
2769 switch (extract_code(method)) {
2770 case QSLOT_CODE: type = "slot"; break;
2771 case QSIGNAL_CODE: type = "signal"; break;
2772 }
2773 const char *loc = extract_location(method);
2774 const char *err;
2775 if (strchr(method, ')') == nullptr) // common typing mistake
2776 err = "Parentheses expected,";
2777 else
2778 err = "No such";
2779 qCWarning(lcConnect, "QObject::%s: %s %s %s::%s%s%s", func, err, type,
2780 object->metaObject()->className(), method + 1, loc ? " in " : "", loc ? loc : "");
2781}
2782
2783enum class ConnectionEnd : bool { Sender, Receiver };
2785static void err_info_about_object(const char *func, const QObject *o, ConnectionEnd end)
2786{
2787 if (!o)
2788 return;
2789 const QString name = o->objectName();
2790 if (name.isEmpty())
2791 return;
2792 const bool sender = end == ConnectionEnd::Sender;
2793 qCWarning(lcConnect, "QObject::%s: (%s name:%*s'%ls')",
2794 func,
2795 sender ? "sender" : "receiver",
2796 sender ? 3 : 1, // ← length of generated whitespace
2797 "",
2798 qUtf16Printable(name));
2799}
2800
2802static void err_info_about_objects(const char *func, const QObject *sender, const QObject *receiver)
2803{
2806}
2807
2809static void connectWarning(const QObject *sender,
2810 const QMetaObject *senderMetaObject,
2811 const QObject *receiver,
2812 const char *message)
2813{
2814 const char *senderString = sender ? sender->metaObject()->className()
2815 : senderMetaObject ? senderMetaObject->className()
2816 : "Unknown";
2817 const char *receiverString = receiver ? receiver->metaObject()->className()
2818 : "Unknown";
2819 qCWarning(lcConnect, "QObject::connect(%s, %s): %s", senderString, receiverString, message);
2820}
2821
2822/*!
2823 Returns a pointer to the object that sent the signal, if called in
2824 a slot activated by a signal; otherwise it returns \nullptr. The pointer
2825 is valid only during the execution of the slot that calls this
2826 function from this object's thread context.
2827
2828 The pointer returned by this function becomes invalid if the
2829 sender is destroyed, or if the slot is disconnected from the
2830 sender's signal.
2831
2832 \warning This function violates the object-oriented principle of
2833 modularity. However, getting access to the sender might be useful
2834 when many signals are connected to a single slot.
2835
2836 \warning As mentioned above, the return value of this function is
2837 not valid when the slot is called via a Qt::DirectConnection from
2838 a thread different from this object's thread. Do not use this
2839 function in this type of scenario.
2840
2841 \sa senderSignalIndex()
2842*/
2843
2844QObject *QObject::sender() const
2845{
2846 Q_D(const QObject);
2847
2848 QMutexLocker locker(signalSlotLock(this));
2849 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2850 if (!cd || !cd->currentSender)
2851 return nullptr;
2852
2853 for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2854 if (c->sender == cd->currentSender->sender)
2855 return cd->currentSender->sender;
2856 }
2857
2858 return nullptr;
2859}
2860
2861/*!
2862 \since 4.8
2863
2864 Returns the meta-method index of the signal that called the currently
2865 executing slot, which is a member of the class returned by sender().
2866 If called outside of a slot activated by a signal, -1 is returned.
2867
2868 For signals with default parameters, this function will always return
2869 the index with all parameters, regardless of which was used with
2870 connect(). For example, the signal \c {destroyed(QObject *obj = \nullptr)}
2871 will have two different indexes (with and without the parameter), but
2872 this function will always return the index with a parameter. This does
2873 not apply when overloading signals with different parameters.
2874
2875 \warning This function violates the object-oriented principle of
2876 modularity. However, getting access to the signal index might be useful
2877 when many signals are connected to a single slot.
2878
2879 \warning The return value of this function is not valid when the slot
2880 is called via a Qt::DirectConnection from a thread different from this
2881 object's thread. Do not use this function in this type of scenario.
2882
2883 \sa sender(), QMetaObject::indexOfSignal(), QMetaObject::method()
2884*/
2885
2886int QObject::senderSignalIndex() const
2887{
2888 Q_D(const QObject);
2889
2890 QMutexLocker locker(signalSlotLock(this));
2891 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2892 if (!cd || !cd->currentSender)
2893 return -1;
2894
2895 for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2896 if (c->sender == cd->currentSender->sender) {
2897 // Convert from signal range to method range
2898 return QMetaObjectPrivate::signal(c->sender->metaObject(), cd->currentSender->signal).methodIndex();
2899 }
2900 }
2901
2902 return -1;
2903}
2904
2905/*!
2906 Returns the number of receivers connected to the \a signal.
2907
2908 Since both slots and signals can be used as receivers for signals,
2909 and the same connections can be made many times, the number of
2910 receivers is the same as the number of connections made from this
2911 signal.
2912
2913 When calling this function, you can use the \c SIGNAL() macro to
2914 pass a specific signal:
2915
2916 \snippet code/src_corelib_kernel_qobject.cpp 21
2917
2918 As the code snippet above illustrates, you can use this function to avoid
2919 expensive operations or emitting a signal that nobody listens to.
2920
2921 \warning In a multithreaded application, consecutive calls to this
2922 function are not guaranteed to yield the same results.
2923
2924 \warning This function violates the object-oriented principle of
2925 modularity. In particular, this function must not be called from an
2926 override of connectNotify() or disconnectNotify(), as those might get
2927 called from any thread.
2928
2929 \sa isSignalConnected()
2930*/
2931
2932int QObject::receivers(const char *signal) const
2933{
2934 Q_D(const QObject);
2935 int receivers = 0;
2936 if (signal) {
2937 QByteArray signal_name = QMetaObject::normalizedSignature(signal);
2938 signal = signal_name;
2939#ifndef QT_NO_DEBUG
2940 if (!check_signal_macro(this, signal, "receivers", "bind"))
2941 return 0;
2942#endif
2943 signal++; // skip code
2944 int signal_index = d->signalIndex(signal);
2945 if (signal_index < 0) {
2946#ifndef QT_NO_DEBUG
2947 err_method_notfound(this, signal - 1, "receivers");
2948#endif
2949 return 0;
2950 }
2951
2952 if (!d->isSignalConnected(signal_index))
2953 return receivers;
2954
2955 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::receivers) {
2956 receivers += QAbstractDeclarativeData::receivers(d->declarativeData, this,
2957 signal_index);
2958 }
2959
2960 QMutexLocker locker(signalSlotLock(this));
2961 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2962 if (cd && signal_index < cd->signalVectorCount()) {
2963 const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
2964 while (c) {
2965 receivers += c->receiver.loadRelaxed() ? 1 : 0;
2966 c = c->nextConnectionList.loadRelaxed();
2967 }
2968 }
2969 }
2970 return receivers;
2971}
2972
2973/*!
2974 \since 5.0
2975 Returns \c true if the \a signal is connected to at least one receiver,
2976 otherwise returns \c false.
2977
2978 \a signal must be a signal member of this object, otherwise the behaviour
2979 is undefined.
2980
2981 \snippet code/src_corelib_kernel_qobject.cpp 49
2982
2983 As the code snippet above illustrates, you can use this function to avoid
2984 expensive operations or emitting a signal that nobody listens to.
2985
2986 \warning In a multithreaded application, consecutive calls to this
2987 function are not guaranteed to yield the same results.
2988
2989 \warning This function violates the object-oriented principle of
2990 modularity. In particular, this function must not be called from an
2991 override of connectNotify() or disconnectNotify(), as those might get
2992 called from any thread.
2993
2994 \sa receivers()
2995*/
2996bool QObject::isSignalConnected(const QMetaMethod &signal) const
2997{
2998 Q_D(const QObject);
2999 if (!signal.mobj)
3000 return false;
3001
3002 Q_ASSERT_X(signal.mobj->cast(this) && signal.methodType() == QMetaMethod::Signal,
3003 "QObject::isSignalConnected" , "the parameter must be a signal member of the object");
3004 uint signalIndex = signal.relativeMethodIndex();
3005
3006 if (signal.data.flags() & MethodCloned)
3007 signalIndex = QMetaObjectPrivate::originalClone(signal.mobj, signalIndex);
3008
3009 signalIndex += QMetaObjectPrivate::signalOffset(signal.mobj);
3010
3011 QMutexLocker locker(signalSlotLock(this));
3012 return d->isSignalConnected(signalIndex, true);
3013}
3014
3015/*!
3016 \internal
3017
3018 This helper function calculates signal and method index for the given
3019 member in the specified class.
3020
3021 \list
3022 \li If member.mobj is \nullptr then both signalIndex and methodIndex are set to -1.
3023
3024 \li If specified member is not a member of obj instance class (or one of
3025 its parent classes) then both signalIndex and methodIndex are set to -1.
3026 \endlist
3027
3028 This function is used by QObject::connect and QObject::disconnect which
3029 are working with QMetaMethod.
3030
3031 \a signalIndex is set to the signal index of member. If the member
3032 specified is not signal this variable is set to -1.
3033
3034 \a methodIndex is set to the method index of the member. If the
3035 member is not a method of the object specified by the \a obj argument this
3036 variable is set to -1.
3037*/
3038void QMetaObjectPrivate::memberIndexes(const QObject *obj,
3039 const QMetaMethod &member,
3040 int *signalIndex, int *methodIndex)
3041{
3042 *signalIndex = -1;
3043 *methodIndex = -1;
3044 if (!obj || !member.mobj)
3045 return;
3046 const QMetaObject *m = obj->metaObject();
3047 // Check that member is member of obj class
3048 while (m != nullptr && m != member.mobj)
3049 m = m->d.superdata;
3050 if (!m)
3051 return;
3052 *signalIndex = *methodIndex = member.relativeMethodIndex();
3053
3054 int signalOffset;
3055 int methodOffset;
3056 computeOffsets(m, &signalOffset, &methodOffset);
3057
3058 *methodIndex += methodOffset;
3059 if (member.methodType() == QMetaMethod::Signal) {
3060 *signalIndex = originalClone(m, *signalIndex);
3061 *signalIndex += signalOffset;
3062 } else {
3063 *signalIndex = -1;
3064 }
3065}
3066
3067#ifndef QT_NO_DEBUG
3068static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaMethod &signal,
3069 const QMetaObject *receiver, const QMetaMethod &method)
3070{
3071 if (signal.attributes() & QMetaMethod::Compatibility) {
3072 if (!(method.attributes() & QMetaMethod::Compatibility))
3073 qCWarning(lcConnect, "QObject::connect: Connecting from COMPAT signal (%s::%s)",
3074 sender->className(), signal.methodSignature().constData());
3075 } else if ((method.attributes() & QMetaMethod::Compatibility)
3076 && method.methodType() == QMetaMethod::Signal) {
3077 qCWarning(lcConnect, "QObject::connect: Connecting from %s::%s to COMPAT slot (%s::%s)",
3078 sender->className(), signal.methodSignature().constData(), receiver->className(),
3079 method.methodSignature().constData());
3080 }
3081}
3082#endif
3083
3084/*!
3085 \threadsafe
3086
3087 Creates a connection of the given \a type from the \a signal in
3088 the \a sender object to the \a method in the \a receiver object.
3089 Returns a handle to the connection that can be used to disconnect
3090 it later.
3091
3092 You must use the \c SIGNAL() and \c SLOT() macros when specifying
3093 the \a signal and the \a method, for example:
3094
3095 \snippet code/src_corelib_kernel_qobject.cpp 22
3096
3097 This example ensures that the label always displays the current
3098 scroll bar value. Note that the signal and slots parameters must not
3099 contain any variable names, only the type. E.g. the following would
3100 not work and return false:
3101
3102 \snippet code/src_corelib_kernel_qobject.cpp 23
3103
3104 A signal can also be connected to another signal:
3105
3106 \snippet code/src_corelib_kernel_qobject.cpp 24
3107
3108 In this example, the \c MyWidget constructor relays a signal from
3109 a private member variable, and makes it available under a name
3110 that relates to \c MyWidget.
3111
3112 A signal can be connected to many slots and signals. Many signals
3113 can be connected to one slot.
3114
3115 If a signal is connected to several slots, the slots are activated
3116 in the same order in which the connections were made, when the
3117 signal is emitted.
3118
3119 The function returns a QMetaObject::Connection that represents
3120 a handle to a connection if it successfully
3121 connects the signal to the slot. The connection handle will be invalid
3122 if it cannot create the connection, for example, if QObject is unable
3123 to verify the existence of either \a signal or \a method, or if their
3124 signatures aren't compatible.
3125 You can check if the handle is valid by casting it to a bool.
3126
3127 By default, a signal is emitted for every connection you make;
3128 two signals are emitted for duplicate connections. You can break
3129 all of these connections with a single disconnect() call.
3130 If you pass the Qt::UniqueConnection \a type, the connection will only
3131 be made if it is not a duplicate. If there is already a duplicate
3132 (exact same signal to the exact same slot on the same objects),
3133 the connection will fail and connect will return an invalid QMetaObject::Connection.
3134
3135 \note Qt::UniqueConnections do not work for lambdas, non-member functions
3136 and functors; they only apply to connecting to member functions.
3137
3138 The optional \a type parameter describes the type of connection
3139 to establish. In particular, it determines whether a particular
3140 signal is delivered to a slot immediately or queued for delivery
3141 at a later time. If the signal is queued, the parameters must be
3142 of types that are known to Qt's meta-object system, because Qt
3143 needs to copy the arguments to store them in an event behind the
3144 scenes. If you try to use a queued connection and get the error
3145 message
3146
3147 \snippet code/src_corelib_kernel_qobject.cpp 25
3148
3149 call qRegisterMetaType() to register the data type before you
3150 establish the connection.
3151
3152 \sa disconnect(), sender(), qRegisterMetaType(), Q_DECLARE_METATYPE(),
3153 {Differences between String-Based and Functor-Based Connections}
3154*/
3155QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal,
3156 const QObject *receiver, const char *method,
3157 Qt::ConnectionType type)
3158{
3159 if (sender == nullptr || receiver == nullptr || signal == nullptr || method == nullptr) {
3160 qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
3161 sender ? sender->metaObject()->className() : "(nullptr)",
3162 (signal && *signal) ? signal + 1 : "(nullptr)",
3163 receiver ? receiver->metaObject()->className() : "(nullptr)",
3164 (method && *method) ? method + 1 : "(nullptr)");
3165 return QMetaObject::Connection(nullptr);
3166 }
3167
3168 if (!check_signal_macro(sender, signal, "connect", "bind"))
3169 return QMetaObject::Connection(nullptr);
3170
3171 int membcode = extract_code(method);
3172 if (!check_method_code(membcode, receiver, method, "connect"))
3173 return QMetaObject::Connection(nullptr);
3174
3175 QByteArray pinnedSignal;
3176 const QMetaObject *smeta = sender->metaObject();
3177 const char *signal_arg = signal;
3178 ++signal; // skip code
3179 QByteArrayView signalView{signal}; // after skipping code
3180 QArgumentTypeArray signalTypes;
3181 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3182 QByteArrayView signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3183 int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3184 if (signal_index < 0) {
3185 // check for normalized signatures
3186 pinnedSignal = QMetaObjectPrivate::normalizedSignature(signalView);
3187 signalView = pinnedSignal;
3188
3189 signalTypes.clear();
3190 signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3191 smeta = sender->metaObject();
3192 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3193 }
3194 if (signal_index < 0) {
3195 err_method_notfound(sender, signal_arg, "connect");
3196 err_info_about_objects("connect", sender, receiver);
3197 return QMetaObject::Connection(nullptr);
3198 }
3199 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3200 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3201
3202 QByteArray pinnedMethod;
3203 const char *method_arg = method;
3204 ++method; // skip code
3205 QByteArrayView methodView{method}; // after skipping code
3206
3207 QArgumentTypeArray methodTypes;
3208 QByteArrayView methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3209 const QMetaObject *rmeta = receiver->metaObject();
3210 int method_index_relative = -1;
3211 Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
3212 switch (membcode) {
3213 case QSLOT_CODE:
3214 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3215 &rmeta, methodName, methodTypes);
3216 break;
3217 case QSIGNAL_CODE:
3218 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3219 &rmeta, methodName, methodTypes);
3220 break;
3221 }
3222
3223 if (method_index_relative < 0) {
3224 // check for normalized methods
3225 pinnedMethod = QMetaObjectPrivate::normalizedSignature(methodView);
3226 methodView = pinnedMethod;
3227
3228 methodTypes.clear();
3229 methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3230 // rmeta may have been modified above
3231 rmeta = receiver->metaObject();
3232 switch (membcode) {
3233 case QSLOT_CODE:
3234 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3235 &rmeta, methodName, methodTypes);
3236 break;
3237 case QSIGNAL_CODE:
3238 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3239 &rmeta, methodName, methodTypes);
3240 break;
3241 }
3242 }
3243
3244 if (method_index_relative < 0) {
3245 err_method_notfound(receiver, method_arg, "connect");
3246 err_info_about_objects("connect", sender, receiver);
3247 return QMetaObject::Connection(nullptr);
3248 }
3249
3250 if (!QMetaObjectPrivate::checkConnectArgs(signalTypes, methodTypes)) {
3251 qCWarning(lcConnect,
3252 "QObject::connect: Incompatible sender/receiver arguments"
3253 "\n %s::%s --> %s::%s",
3254 sender->metaObject()->className(), signalView.constData(),
3255 receiver->metaObject()->className(), methodView.constData());
3256 return QMetaObject::Connection(nullptr);
3257 }
3258
3259 // ### Future work: attempt get the metatypes from the meta object first
3260 // because it's possible they're all registered.
3261 int *types = nullptr;
3262 if (type == Qt::QueuedConnection && !(types = queuedConnectionTypes(signalTypes))) {
3263 return QMetaObject::Connection(nullptr);
3264 }
3265
3266 QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
3267#ifndef QT_NO_DEBUG
3268 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3269 check_and_warn_compat(smeta, smethod, rmeta, rmethod);
3270#endif
3271
3272#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
3273 check_and_warn_non_slot("connect", method, membcode, rmeta, rmethod);
3274#endif
3275
3276 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3277 sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
3278 return handle;
3279}
3280
3281/*!
3282 \since 4.8
3283
3284 Creates a connection of the given \a type from the \a signal in
3285 the \a sender object to the \a method in the \a receiver object.
3286 Returns a handle to the connection that can be used to disconnect
3287 it later.
3288
3289 The Connection handle will be invalid if it cannot create the
3290 connection, for example, the parameters were invalid.
3291 You can check if the QMetaObject::Connection is valid by casting it to a bool.
3292
3293 This function works in the same way as
3294 \c {connect(const QObject *sender, const char *signal,
3295 const QObject *receiver, const char *method,
3296 Qt::ConnectionType type)}
3297 but it uses QMetaMethod to specify signal and method.
3298
3299 \sa connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
3300 */
3301QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMethod &signal,
3302 const QObject *receiver, const QMetaMethod &method,
3303 Qt::ConnectionType type)
3304{
3305 if (sender == nullptr
3306 || receiver == nullptr
3307 || signal.methodType() != QMetaMethod::Signal
3308 || method.methodType() == QMetaMethod::Constructor) {
3309 qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
3310 sender ? sender->metaObject()->className() : "(nullptr)",
3311 signal.methodSignature().constData(),
3312 receiver ? receiver->metaObject()->className() : "(nullptr)",
3313 method.methodSignature().constData());
3314 return QMetaObject::Connection(nullptr);
3315 }
3316
3317 int signal_index;
3318 int method_index;
3319 {
3320 int dummy;
3321 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3322 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3323 }
3324
3325 const QMetaObject *smeta = sender->metaObject();
3326 const QMetaObject *rmeta = receiver->metaObject();
3327 if (signal_index == -1) {
3328 qCWarning(lcConnect, "QObject::connect: Can't find signal %s on instance of class %s",
3329 signal.methodSignature().constData(), smeta->className());
3330 return QMetaObject::Connection(nullptr);
3331 }
3332 if (method_index == -1) {
3333 qCWarning(lcConnect, "QObject::connect: Can't find method %s on instance of class %s",
3334 method.methodSignature().constData(), rmeta->className());
3335 return QMetaObject::Connection(nullptr);
3336 }
3337
3338 if (!QMetaObject::checkConnectArgs(signal.methodSignature().constData(),
3339 method.methodSignature().constData())) {
3340 qCWarning(lcConnect,
3341 "QObject::connect: Incompatible sender/receiver arguments"
3342 "\n %s::%s --> %s::%s",
3343 smeta->className(), signal.methodSignature().constData(), rmeta->className(),
3344 method.methodSignature().constData());
3345 return QMetaObject::Connection(nullptr);
3346 }
3347
3348 int *types = nullptr;
3349 if ((type == Qt::QueuedConnection) && !(types = queuedConnectionTypes(signal)))
3350 return QMetaObject::Connection(nullptr);
3351
3352#ifndef QT_NO_DEBUG
3353 check_and_warn_compat(smeta, signal, rmeta, method);
3354#endif
3355 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3356 sender, signal_index, signal.enclosingMetaObject(), receiver, method_index, nullptr, type, types));
3357 return handle;
3358}
3359
3360/*!
3361 \fn bool QObject::connect(const QObject *sender, const char *signal, const char *method, Qt::ConnectionType type) const
3362 \overload connect()
3363 \threadsafe
3364
3365 Connects \a signal from the \a sender object to this object's \a
3366 method.
3367
3368 Equivalent to connect(\a sender, \a signal, \c this, \a method, \a type).
3369
3370 Every connection you make emits a signal, so duplicate connections emit
3371 two signals. You can break a connection using disconnect().
3372
3373 \sa disconnect()
3374*/
3375
3376/*!
3377 \threadsafe
3378
3379 Disconnects \a signal in object \a sender from \a method in object
3380 \a receiver. Returns \c true if the connection is successfully broken;
3381 otherwise returns \c false.
3382
3383 A signal-slot connection is removed when either of the objects
3384 involved are destroyed.
3385
3386 disconnect() is typically used in three ways, as the following
3387 examples demonstrate.
3388 \list 1
3389 \li Disconnect everything connected to an object's signals:
3390
3391 \snippet code/src_corelib_kernel_qobject.cpp 26
3392
3393 equivalent to the non-static overloaded function
3394
3395 \snippet code/src_corelib_kernel_qobject.cpp 27
3396
3397 \li Disconnect everything connected to a specific signal:
3398
3399 \snippet code/src_corelib_kernel_qobject.cpp 28
3400
3401 equivalent to the non-static overloaded function
3402
3403 \snippet code/src_corelib_kernel_qobject.cpp 29
3404
3405 \li Disconnect a specific receiver:
3406
3407 \snippet code/src_corelib_kernel_qobject.cpp 30
3408
3409 equivalent to the non-static overloaded function
3410
3411 \snippet code/src_corelib_kernel_qobject.cpp 31
3412
3413 \endlist
3414
3415 \include includes/qobject.qdocinc disconnect-mismatch
3416 \include includes/qobject.qdocinc disconnect-queued
3417
3418 \nullptr may be used as a wildcard, meaning "any signal", "any receiving
3419 object", or "any slot in the receiving object", respectively.
3420
3421 The \a sender may never be \nullptr. (You cannot disconnect signals
3422 from more than one object in a single call.)
3423
3424 If \a signal is \nullptr, it disconnects \a receiver and \a method from
3425 any signal. If not, only the specified signal is disconnected.
3426
3427 If \a receiver is \nullptr, it disconnects anything connected to \a
3428 signal. If not, slots in objects other than \a receiver are not
3429 disconnected.
3430
3431 If \a method is \nullptr, it disconnects anything that is connected to \a
3432 receiver. If not, only slots named \a method will be disconnected,
3433 and all other slots are left alone. The \a method must be \nullptr
3434 if \a receiver is left out, so you cannot disconnect a
3435 specifically-named slot on all objects.
3436
3437 \include includes/qobject.qdocinc disconnect-all
3438
3439 \sa connect()
3440*/
3441bool QObject::disconnect(const QObject *sender, const char *signal,
3442 const QObject *receiver, const char *method)
3443{
3444 if (sender == nullptr || (receiver == nullptr && method != nullptr)) {
3445 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
3446 return false;
3447 }
3448
3449 const char *signal_arg = signal;
3450 if (signal) {
3451 if (!check_signal_macro(sender, signal, "disconnect", "unbind"))
3452 return false;
3453 ++signal; // skip code
3454 }
3455
3456 const char *method_arg = method;
3457 int membcode = -1;
3458 if (method) {
3459 membcode = extract_code(method);
3460 if (!check_method_code(membcode, receiver, method, "disconnect"))
3461 return false;
3462 ++method; // skip code
3463 }
3464
3465 QByteArray pinnedSignal;
3466 const QMetaObject *smeta = sender->metaObject();
3467 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3468 int signal_index = -1;
3469 QByteArrayView signalName;
3470 QArgumentTypeArray signalTypes;
3471 if (signal) {
3472 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3473 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3474 if (signal_index == -1) {
3475 pinnedSignal = QMetaObject::normalizedSignature(signal);
3476 signal = pinnedSignal.constData();
3477 signalTypes.clear();
3478 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3479 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3480 signalTypes);
3481 }
3482 if (signal_index == -1) {
3483 err_method_notfound(sender, signal_arg, "disconnect");
3484 err_info_about_objects("disconnect", sender, receiver);
3485 return false;
3486 }
3487 }
3488
3489 auto getMethodIndex = [](int code, const QMetaObject *mo, QByteArrayView name,
3490 const QArgumentTypeArray &types) {
3491 switch (code) {
3492 case QSLOT_CODE:
3493 return QMetaObjectPrivate::indexOfSlot(mo, name, types);
3494 case QSIGNAL_CODE:
3495 return QMetaObjectPrivate::indexOfSignal(mo, name, types);
3496 }
3497 return -1;
3498 };
3499
3500 QByteArray pinnedMethod;
3501 const QMetaObject *rmeta = receiver ? receiver->metaObject() : nullptr;
3502 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 7);
3503 int method_index = -1;
3504 QByteArrayView methodName;
3505 QArgumentTypeArray methodTypes;
3506 if (method) {
3507 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3508 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3509 if (method_index == -1) {
3510 pinnedMethod = QMetaObject::normalizedSignature(method);
3511 method = pinnedMethod.constData();
3512 methodTypes.clear();
3513 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3514 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3515 }
3516 if (method_index == -1) {
3517 err_method_notfound(receiver, method_arg, "disconnect");
3518 err_info_about_objects("disconnect", sender, receiver);
3519 return false;
3520 }
3521 }
3522
3523 /* We now iterate through all the sender's and receiver's meta
3524 * objects in order to also disconnect possibly shadowed signals
3525 * and slots with the same signature.
3526 */
3527 bool res = false;
3528 do {
3529 if (signal) {
3530 // Already computed the signal_index for `smeta` above
3531 if (smeta != sender->metaObject()) {
3532 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3533 signalTypes);
3534 }
3535 if (signal_index < 0)
3536 break;
3537 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3538 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3539 }
3540
3541 if (!method) {
3542 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1, nullptr);
3543 } else {
3544 do {
3545 // Already computed the method_index for receiver->metaObject() above
3546 if (rmeta != receiver->metaObject())
3547 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3548 if (method_index >= 0) {
3549#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
3550 check_and_warn_non_slot("disconnect", method, membcode, rmeta,
3551 rmeta->method(method_index));
3552#endif
3553 while (method_index < rmeta->methodOffset())
3554 rmeta = rmeta->superClass();
3555 }
3556 if (method_index < 0)
3557 break;
3558 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index, nullptr);
3559 } while ((rmeta = rmeta->superClass()));
3560 }
3561 } while (signal && (smeta = smeta->superClass()));
3562
3563 if (res) {
3564 if (!signal)
3565 const_cast<QObject *>(sender)->disconnectNotify(QMetaMethod());
3566 }
3567 return res;
3568}
3569
3570/*!
3571 \since 4.8
3572
3573 Disconnects \a signal in object \a sender from \a method in object
3574 \a receiver. Returns \c true if the connection is successfully broken;
3575 otherwise returns \c false.
3576
3577 This function provides the same possibilities like
3578 \c {disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method) }
3579 but uses QMetaMethod to represent the signal and the method to be disconnected.
3580
3581 Additionally this function returns false and no signals and slots disconnected
3582 if:
3583 \list 1
3584
3585 \li \a signal is not a member of sender class or one of its parent classes.
3586
3587 \li \a method is not a member of receiver class or one of its parent classes.
3588
3589 \li \a signal instance represents not a signal.
3590
3591 \endlist
3592
3593 \include includes/qobject.qdocinc disconnect-mismatch
3594 \include includes/qobject.qdocinc disconnect-queued
3595
3596 QMetaMethod() may be used as wildcard in the meaning "any signal" or "any slot in receiving object".
3597 In the same way \nullptr can be used for \a receiver in the meaning "any receiving object".
3598 In this case method should also be QMetaMethod(). \a sender parameter should be never \nullptr.
3599
3600 \include includes/qobject.qdocinc disconnect-all
3601
3602 \sa disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
3603 */
3604bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal,
3605 const QObject *receiver, const QMetaMethod &method)
3606{
3607 if (sender == nullptr || (receiver == nullptr && method.mobj != nullptr)) {
3608 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
3609 return false;
3610 }
3611 if (signal.mobj) {
3612 if (signal.methodType() != QMetaMethod::Signal) {
3613 qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s",
3614 "disconnect","unbind",
3615 sender->metaObject()->className(), signal.methodSignature().constData());
3616 return false;
3617 }
3618 }
3619 if (method.mobj) {
3620 if (method.methodType() == QMetaMethod::Constructor) {
3621 qCWarning(lcConnect, "QObject::disconnect: cannot use constructor as argument %s::%s",
3622 receiver->metaObject()->className(), method.methodSignature().constData());
3623 return false;
3624 }
3625 }
3626
3627 int signal_index;
3628 int method_index;
3629 {
3630 int dummy;
3631 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3632 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3633 }
3634 // If we are here sender is not nullptr. If signal is not nullptr while signal_index
3635 // is -1 then this signal is not a member of sender.
3636 if (signal.mobj && signal_index == -1) {
3637 qCWarning(lcConnect, "QObject::disconnect: signal %s not found on class %s",
3638 signal.methodSignature().constData(), sender->metaObject()->className());
3639 return false;
3640 }
3641 // If this condition is true then method is not a member of receiver.
3642 if (receiver && method.mobj && method_index == -1) {
3643 qCWarning(lcConnect, "QObject::disconnect: method %s not found on class %s",
3644 method.methodSignature().constData(), receiver->metaObject()->className());
3645 return false;
3646 }
3647
3648 if (!QMetaObjectPrivate::disconnect(sender, signal_index, signal.mobj, receiver, method_index, nullptr))
3649 return false;
3650
3651 if (!signal.isValid()) {
3652 // The signal is a wildcard, meaning all signals were disconnected.
3653 // QMetaObjectPrivate::disconnect() doesn't call disconnectNotify()
3654 // per connection in this case. Call it once now, with an invalid
3655 // QMetaMethod as argument, as documented.
3656 const_cast<QObject *>(sender)->disconnectNotify(signal);
3657 }
3658 return true;
3659}
3660
3661/*!
3662 \threadsafe
3663
3664 \fn bool QObject::disconnect(const char *signal, const QObject *receiver, const char *method) const
3665 \overload disconnect()
3666
3667 Disconnects \a signal from \a method of \a receiver.
3668
3669 \include includes/qobject.qdocinc disconnect-mismatch
3670 \include includes/qobject.qdocinc disconnect-queued
3671
3672 A signal-slot connection is removed when either of the objects
3673 involved are destroyed.
3674
3675 \include includes/qobject.qdocinc disconnect-all
3676*/
3677
3678/*!
3679 \fn bool QObject::disconnect(const QObject *receiver, const char *method) const
3680 \overload disconnect()
3681
3682 Disconnects all signals in this object from \a receiver's \a
3683 method.
3684
3685 \include includes/qobject.qdocinc disconnect-mismatch
3686 \include includes/qobject.qdocinc disconnect-queued
3687
3688 A signal-slot connection is removed when either of the objects
3689 involved are destroyed.
3690*/
3691
3692
3693/*!
3694 \since 5.0
3695
3696 This virtual function is called when something has been connected
3697 to \a signal in this object.
3698
3699 If you want to compare \a signal with a specific signal, you can
3700 use QMetaMethod::fromSignal() as follows:
3701
3702 \snippet code/src_corelib_kernel_qobject.cpp 32
3703
3704 \warning This function violates the object-oriented principle of
3705 modularity. However, it might be useful when you need to perform
3706 an expensive operation only if something is connected to a signal.
3707
3708 \warning This function is called from the thread which performs the
3709 connection, which may be a different thread from the thread in which
3710 this object lives. This function may also be called with a QObject internal
3711 mutex locked. It is therefore not allowed to re-enter any QObject
3712 functions, including isSignalConnected(), from your reimplementation. If
3713 you lock a mutex in your reimplementation, make sure that you don't call
3714 QObject functions with that mutex held in other places or it will result in
3715 a deadlock.
3716
3717 \sa connect(), disconnectNotify()
3718*/
3719
3720void QObject::connectNotify(const QMetaMethod &signal)
3721{
3722 Q_UNUSED(signal);
3723}
3724
3725/*!
3726 \since 5.0
3727
3728 This virtual function is called when something has been
3729 disconnected from \a signal in this object.
3730
3731 See connectNotify() for an example of how to compare
3732 \a signal with a specific signal.
3733
3734 If all signals were disconnected from this object (e.g., the
3735 signal argument to disconnect() was \nullptr), disconnectNotify()
3736 is only called once, and the \a signal will be an invalid
3737 QMetaMethod (QMetaMethod::isValid() returns \c false).
3738
3739 When a receiver living in another thread is destroyed, this function is
3740 called later, from this object's own thread; if that thread has no running
3741 event loop, it is not called at all. In every other case it is called right
3742 away, from the thread that is disconnecting the signal.
3743
3744 \warning This function violates the object-oriented principle of
3745 modularity. However, it might be useful for optimizing access to
3746 expensive resources.
3747
3748 \warning This function is called from the thread which performs the
3749 disconnection, which may be a different thread from the thread in which
3750 this object lives. This function may also be called with a QObject internal
3751 mutex locked. It is therefore not allowed to re-enter any QObject
3752 functions, including isSignalConnected(), from your reimplementation. If
3753 you lock a mutex in your reimplementation, make sure that you don't call
3754 QObject functions with that mutex held in other places or it will result in
3755 a deadlock.
3756
3757 \sa disconnect(), connectNotify()
3758*/
3759
3760void QObject::disconnectNotify(const QMetaMethod &signal)
3761{
3762 Q_UNUSED(signal);
3763}
3764
3765/*
3766 \internal
3767 convert a signal index from the method range to the signal range
3768 */
3769static int methodIndexToSignalIndex(const QMetaObject **base, int signal_index)
3770{
3771 if (signal_index < 0)
3772 return signal_index;
3773 const QMetaObject *metaObject = *base;
3774 while (metaObject && metaObject->methodOffset() > signal_index)
3775 metaObject = metaObject->superClass();
3776
3777 if (metaObject) {
3778 int signalOffset, methodOffset;
3779 computeOffsets(metaObject, &signalOffset, &methodOffset);
3780 if (signal_index < metaObject->methodCount())
3781 signal_index = QMetaObjectPrivate::originalClone(metaObject, signal_index - methodOffset) + signalOffset;
3782 else
3783 signal_index = signal_index - methodOffset + signalOffset;
3784 *base = metaObject;
3785 }
3786 return signal_index;
3787}
3788
3789/*!
3790 \internal
3791 \a types is a 0-terminated vector of meta types for queued
3792 connections.
3793
3794 if \a signal_index is -1, then we effectively connect *all* signals
3795 from the sender to the receiver's slot
3796 */
3797QMetaObject::Connection QMetaObject::connect(const QObject *sender, int signal_index,
3798 const QObject *receiver, int method_index, int type,
3799 int *types)
3800{
3801 const QMetaObject *smeta = sender->metaObject();
3802 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3803 return Connection(QMetaObjectPrivate::connect(sender, signal_index, smeta,
3804 receiver, method_index,
3805 nullptr, //FIXME, we could speed this connection up by computing the relative index
3806 type, types));
3807}
3808
3809/*!
3810 \internal
3811 Same as the QMetaObject::connect, but \a signal_index must be the result of QObjectPrivate::signalIndex
3812
3813 method_index is relative to the rmeta metaobject, if rmeta is \nullptr, then it is absolute index
3814
3815 the QObjectPrivate::Connection* has a refcount of 2, so it must be passed to a QMetaObject::Connection
3816 */
3817QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender,
3818 int signal_index, const QMetaObject *smeta,
3819 const QObject *receiver, int method_index,
3820 const QMetaObject *rmeta, int type, int *types)
3821{
3822 QObject *s = const_cast<QObject *>(sender);
3823 QObject *r = const_cast<QObject *>(receiver);
3824
3825 int method_offset = rmeta ? rmeta->methodOffset() : 0;
3826 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 6);
3827 QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall : nullptr;
3828
3829 QOrderedMutexLocker locker(signalSlotLock(sender),
3830 signalSlotLock(receiver));
3831
3832 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3833 if (type & Qt::UniqueConnection && scd) {
3834 if (scd->signalVectorCount() > signal_index) {
3835 const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
3836
3837 int method_index_absolute = method_index + method_offset;
3838
3839 while (c2) {
3840 if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute)
3841 return nullptr;
3842 c2 = c2->nextConnectionList.loadRelaxed();
3843 }
3844 }
3845 }
3846 type &= ~Qt::UniqueConnection;
3847
3848 const bool isSingleShot = type & Qt::SingleShotConnection;
3849 type &= ~Qt::SingleShotConnection;
3850
3851 Q_ASSERT(type >= 0);
3852 Q_ASSERT(type <= 3);
3853
3854 std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
3855 c->sender = s;
3856 c->signal_index = signal_index;
3857 c->receiver.storeRelaxed(r);
3858 QThreadData *td = r->d_func()->threadData.loadAcquire();
3859 td->ref();
3860 c->receiverThreadData.storeRelaxed(td);
3861 c->method_relative = method_index;
3862 c->method_offset = method_offset;
3863 c->connectionType = type;
3864 c->isSlotObject = false;
3865 c->argumentTypes.storeRelaxed(types);
3866 c->callFunction = callFunction;
3867 c->isSingleShot = isSingleShot;
3868
3869 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
3870
3871 locker.unlock();
3872 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3873 if (smethod.isValid())
3874 s->connectNotify(smethod);
3875
3876 return c.release();
3877}
3878
3879/*!
3880 \internal
3881 */
3882bool QMetaObject::disconnect(const QObject *sender, int signal_index,
3883 const QObject *receiver, int method_index)
3884{
3885 const QMetaObject *smeta = sender->metaObject();
3886 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3887 return QMetaObjectPrivate::disconnect(sender, signal_index, smeta,
3888 receiver, method_index, nullptr);
3889}
3890
3891/*!
3892 \internal
3893
3894Disconnect a single signal connection. If QMetaObject::connect() has been called
3895multiple times for the same sender, signal_index, receiver and method_index only
3896one of these connections will be removed.
3897 */
3898bool QMetaObject::disconnectOne(const QObject *sender, int signal_index,
3899 const QObject *receiver, int method_index)
3900{
3901 const QMetaObject *smeta = sender->metaObject();
3902 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3903 return QMetaObjectPrivate::disconnect(sender, signal_index, smeta,
3904 receiver, method_index, nullptr,
3905 QMetaObjectPrivate::DisconnectOne);
3906}
3907
3908/*!
3909 \internal
3910 Helper function to remove the connection from the senders list and set the receivers to \nullptr
3911 */
3912bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::ConnectionData *connections, int signalIndex,
3913 const QObject *receiver, int method_index, void **slot,
3914 QBasicMutex *senderMutex, DisconnectType disconnectType)
3915{
3916 bool success = false;
3917
3918 auto &connectionList = connections->connectionsForSignal(signalIndex);
3919 auto *c = connectionList.first.loadRelaxed();
3920 while (c) {
3921 QObject *r = c->receiver.loadRelaxed();
3922 if (r && (receiver == nullptr || (r == receiver
3923 && (method_index < 0 || (!c->isSlotObject && c->method() == method_index))
3924 && (slot == nullptr || (c->isSlotObject && c->slotObj->compare(slot)))))) {
3925 bool needToUnlock = false;
3926 QBasicMutex *receiverMutex = nullptr;
3927 if (r) {
3928 receiverMutex = signalSlotLock(r);
3929 // need to relock this receiver and sender in the correct order
3930 needToUnlock = QOrderedMutexLocker::relock(senderMutex, receiverMutex);
3931 }
3932 if (c->receiver.loadRelaxed())
3933 connections->removeConnection(c);
3934
3935 if (needToUnlock)
3936 receiverMutex->unlock();
3937
3938 success = true;
3939
3940 if (disconnectType == DisconnectOne)
3941 return success;
3942 }
3943 c = c->nextConnectionList.loadRelaxed();
3944 }
3945 return success;
3946}
3947
3948/*!
3949 \internal
3950 Same as the QMetaObject::disconnect, but \a signal_index must be the result of QObjectPrivate::signalIndex
3951 */
3952bool QMetaObjectPrivate::disconnect(const QObject *sender,
3953 int signal_index, const QMetaObject *smeta,
3954 const QObject *receiver, int method_index, void **slot,
3955 DisconnectType disconnectType)
3956{
3957 if (!sender)
3958 return false;
3959
3960 QObject *s = const_cast<QObject *>(sender);
3961
3962 QBasicMutex *senderMutex = signalSlotLock(sender);
3963 QMutexLocker locker(senderMutex);
3964
3965 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3966 if (!scd)
3967 return false;
3968
3969 // Capture the message arguments now and emit the warning after unlocking:
3970 // qWarning() may re-enter connect/disconnect from the message handler and
3971 // deadlock on the lock held here (QTBUG-145216).
3972 struct WildcardDestroyedWarning
3973 {
3974 QByteArray className;
3975 QByteArray objectName;
3976 };
3977 std::optional<WildcardDestroyedWarning> wildcardDestroyedWarning;
3978
3979 bool success = false;
3980 {
3981 // prevent incoming connections changing the connections->receivers while unlocked
3982 QObjectPrivate::ConnectionDataPointer connections(scd);
3983
3984 if (signal_index < 0) {
3985 // wildcard disconnect - warn if this disconnects destroyed()
3986 if (!receiver && method_index < 0 && sender->d_func()->isSignalConnected(0)) {
3987 wildcardDestroyedWarning = WildcardDestroyedWarning{
3988 sender->metaObject()->className(),
3989 sender->objectName().toLocal8Bit()
3990 };
3991 }
3992 // remove from all connection lists
3993 for (int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
3994 if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
3995 success = true;
3996 }
3997 } else if (signal_index < scd->signalVectorCount()) {
3998 if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
3999 success = true;
4000 }
4001 }
4002
4003 locker.unlock();
4004
4005 if (wildcardDestroyedWarning) {
4006 qWarning("QObject::disconnect: wildcard call disconnects from destroyed signal of %s::%s",
4007 wildcardDestroyedWarning->className.constData(),
4008 wildcardDestroyedWarning->objectName.isEmpty()
4009 ? "unnamed"
4010 : wildcardDestroyedWarning->objectName.constData());
4011 }
4012
4013 if (success) {
4014 scd->cleanOrphanedConnections(s);
4015
4016 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
4017 if (smethod.isValid())
4018 s->disconnectNotify(smethod);
4019 }
4020
4021 return success;
4022}
4023
4024// Helpers for formatting the connect statements of connectSlotsByName()'s debug mode
4025static QByteArray formatConnectionSignature(const char *className, const QMetaMethod &method)
4026{
4027 const auto signature = method.methodSignature();
4028 Q_ASSERT(signature.endsWith(')'));
4029 const qsizetype openParen = signature.indexOf('(');
4030 const bool hasParameters = openParen > 0 && openParen < signature.size() - 2;
4031 QByteArray result;
4032 if (hasParameters) {
4033 const qsizetype len = signature.size() - openParen - 2;
4034 result += "qOverload<" + QByteArrayView{signature}.slice(openParen + 1, len) + ">(";
4035 }
4036 result += '&';
4037 result += className + QByteArrayLiteral("::") + method.name();
4038 if (hasParameters)
4039 result += ')';
4040 return result;
4041}
4042
4043static QByteArray msgConnect(const QMetaObject *senderMo, const QByteArray &senderName,
4044 const QMetaMethod &signal, const QObject *receiver, int receiverIndex)
4045{
4046 const auto receiverMo = receiver->metaObject();
4047 const auto slot = receiverMo->method(receiverIndex);
4048 QByteArray message = QByteArrayLiteral("QObject::connect(")
4049 + senderName + ", " + formatConnectionSignature(senderMo->className(), signal)
4050 + ", " + receiver->objectName().toLatin1() + ", "
4051 + formatConnectionSignature(receiverMo->className(), slot) + ");";
4052 return message;
4053}
4054
4055/*!
4056 \fn void QMetaObject::connectSlotsByName(QObject *object)
4057
4058 Searches recursively for all child objects of the given \a object, and connects
4059 matching signals from them to slots of \a object that follow the following form:
4060
4061 \snippet code/src_corelib_kernel_qobject.cpp 33
4062
4063 Let's assume our object has a child object of type \c{QPushButton} with
4064 the \l{QObject::objectName}{object name} \c{button1}. The slot to catch the
4065 button's \c{clicked()} signal would be:
4066
4067 \snippet code/src_corelib_kernel_qobject.cpp 34
4068
4069 If \a object itself has a properly set object name, its own signals are also
4070 connected to its respective slots.
4071
4072 \sa QObject::setObjectName()
4073 */
4074void QMetaObject::connectSlotsByName(QObject *o)
4075{
4076 if (!o)
4077 return;
4078 const QMetaObject *mo = o->metaObject();
4079 Q_ASSERT(mo);
4080 const QObjectList list = // list of all objects to look for matching signals including...
4081 o->findChildren<QObject *>() // all children of 'o'...
4082 << o; // and the object 'o' itself
4083
4084 // for each method/slot of o ...
4085 for (int i = 0; i < mo->methodCount(); ++i) {
4086 const QByteArray slotSignature = mo->method(i).methodSignature();
4087 const char *slot = slotSignature.constData();
4088 Q_ASSERT(slot);
4089
4090 // ...that starts with "on_", ...
4091 if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
4092 continue;
4093
4094 // ...we check each object in our list, ...
4095 bool foundIt = false;
4096 for (int j = 0; j < list.size(); ++j) {
4097 const QObject *co = list.at(j);
4098 const QByteArray coName = co->objectName().toLatin1();
4099
4100 // ...discarding those whose objectName is not fitting the pattern "on_<objectName>_...", ...
4101 if (coName.isEmpty() || qstrncmp(slot + 3, coName.constData(), coName.size()) || slot[coName.size()+3] != '_')
4102 continue;
4103
4104 const char *signal = slot + coName.size() + 4; // the 'signal' part of the slot name
4105
4106 // ...for the presence of a matching signal "on_<objectName>_<signal>".
4107 const QMetaObject *smeta;
4108 int sigIndex = co->d_func()->signalIndex(signal, &smeta);
4109 if (sigIndex < 0) {
4110 // if no exactly fitting signal (name + complete parameter type list) could be found
4111 // look for just any signal with the correct name and at least the slot's parameter list.
4112 // Note: if more than one of those signals exist, the one that gets connected is
4113 // chosen 'at random' (order of declaration in source file)
4114 QList<QByteArray> compatibleSignals;
4115 const QMetaObject *smo = co->metaObject();
4116 int sigLen = int(qstrlen(signal)) - 1; // ignore the trailing ')'
4117 for (int k = QMetaObjectPrivate::absoluteSignalCount(smo)-1; k >= 0; --k) {
4118 const QMetaMethod method = QMetaObjectPrivate::signal(smo, k);
4119 if (!qstrncmp(method.methodSignature().constData(), signal, sigLen)) {
4120 smeta = method.enclosingMetaObject();
4121 sigIndex = k;
4122 compatibleSignals.prepend(method.methodSignature());
4123 }
4124 }
4125 if (compatibleSignals.size() > 1)
4126 qCWarning(lcConnectSlotsByName) << "QMetaObject::connectSlotsByName: Connecting slot" << slot
4127 << "with the first of the following compatible signals:" << compatibleSignals;
4128 }
4129
4130 if (sigIndex < 0)
4131 continue;
4132
4133 // we connect it...
4134 if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) {
4135 foundIt = true;
4136 qCDebug(lcConnectSlotsByName, "%s",
4137 msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData());
4138 // ...and stop looking for further objects with the same name.
4139 // Note: the Designer will make sure each object name is unique in the above
4140 // 'list' but other code may create two child objects with the same name. In
4141 // this case one is chosen 'at random'.
4142 break;
4143 }
4144 }
4145 if (foundIt) {
4146 // we found our slot, now skip all overloads
4147 while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
4148 ++i;
4149 } else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
4150 // check if the slot has the following signature: "on_..._...(..."
4151 qsizetype iParen = slotSignature.indexOf('(');
4152 qsizetype iLastUnderscore = slotSignature.lastIndexOf('_', iParen - 1);
4153 if (iLastUnderscore > 3)
4154 qCWarning(lcConnectSlotsByName,
4155 "QMetaObject::connectSlotsByName: No matching signal for %s", slot);
4156 }
4157 }
4158}
4159
4160/*!
4161 \fn template<typename PointerToMemberFunction> QMetaObject::Connection QMetaObject::connect(
4162 const QObject *sender, const QMetaMethod &signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type)
4163
4164 \threadsafe
4165 \overload connect()
4166
4167 \since 6.10
4168
4169 Creates a connection of the given \a type from the \a signal in
4170 the \a sender object to the \a method in the \a receiver object.
4171 Returns a handle to the connection that can be used to disconnect
4172 it later.
4173
4174 The Connection handle will be invalid if it cannot create the
4175 connection, for example, the parameters were invalid.
4176 You can check if the QMetaObject::Connection is valid by casting
4177 it to a bool.
4178 Pass the returned handle to QObject::disconnect() to disconnect
4179 the connection.
4180
4181 A slot can be connected to a given signal if the signal has at
4182 least as many arguments as the slot. There must be an exact match
4183 between the corresponding signal and slot arguments, implicit
4184 conversions and type checking are not handled by this function.
4185 Overloaded slots need to be explicitly be resolved with
4186 help of \l qOverload.
4187 \a signal needs to be the meta-method of a signal, otherwise an
4188 invalid connection will be returned.
4189
4190 \sa QObject::connect(), QObject::disconnect()
4191 */
4192
4193/*!
4194 \fn template<typename Functor> QMetaObject::Connection QMetaObject::connect(
4195 const QObject *sender, const QMetaMethod &signal, const QObject *context, Functor functor, Qt::ConnectionType type)
4196
4197 \threadsafe
4198 \overload connect()
4199
4200 \since 6.10
4201
4202 Creates a connection of a given \a type from \a signal in
4203 \a sender object to \a functor to be placed in a specific event
4204 loop of \a context.
4205 Returns a handle to the connection that can be used to disconnect
4206 it later.
4207 This can be useful for connecting a signal retrieved from
4208 meta-object introspection to a lambda capturing local variables.
4209
4210 \note Qt::UniqueConnections do not work for lambdas, non-member
4211 functions and functors; they only apply to member functions.
4212
4213 The slot function can be any function or functor with with equal
4214 or fewer arguments than the signal. There must be an exact match
4215 between the corresponding signal and slot arguments, implicit
4216 conversions and type checking are not handled by this function.
4217 Overloaded functors need to be explicitly be resolved with
4218 help of \l qOverload.
4219 \a signal needs to be the meta-method of a signal, otherwise an
4220 invalid connection will be returned.
4221
4222 The connection will automatically disconnect if the sender or
4223 the context is destroyed.
4224 However, you should take care that any objects used within
4225 the functor are still alive when the signal is emitted.
4226
4227 \sa QObject::connect(), QObject::disconnect()
4228 */
4229QMetaObject::Connection QMetaObject::connectImpl(const QObject *sender, const QMetaMethod &signal,
4230 const QObject *receiver, void **slot,
4231 QtPrivate::QSlotObjectBase *slotObjRaw, Qt::ConnectionType type)
4232{
4233 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
4234 Q_ASSERT_X(slotObjRaw, "QMetaObject::connect", "Internal error, caller must not pass null slotObj");
4235
4236 const QMetaObject *senderMetaObject = sender->metaObject();
4237 if (!signal.isValid() || signal.methodType() != QMetaMethod::Signal) {
4238 connectWarning(sender, senderMetaObject, receiver, "invalid signal parameter");
4239 return QMetaObject::Connection();
4240 }
4241
4242 int signal_index;
4243 {
4244 int dummy;
4245 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
4246 }
4247
4248 if (signal_index == -1) {
4249 qCWarning(lcConnect, "QObject::connect: Can't find signal %s on instance of class %s",
4250 signal.methodSignature().constData(), senderMetaObject->className());
4251 return QMetaObject::Connection();
4252 }
4253
4254 return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj.release(), type, nullptr, senderMetaObject);
4255}
4256
4257/*!
4258 \internal
4259 A small RAII helper for QSlotObjectBase.
4260 Calls ref on construction and destroyLastRef in its dtor.
4261 Allows construction from a nullptr in which case it does nothing.
4262 */
4264 SlotObjectGuard() = default;
4265 // move would be fine, but we do not need it currently
4273
4275 { return m_slotObject.get(); }
4276
4279
4280 ~SlotObjectGuard() = default;
4281private:
4282 QtPrivate::SlotObjUniquePtr m_slotObject;
4283};
4284
4285/*!
4286 \internal
4287
4288 \a signal must be in the signal index range (see QObjectPrivate::signalIndex()).
4289*/
4290static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv)
4291{
4292 const int *argumentTypes = c->argumentTypes.loadRelaxed();
4293 if (!argumentTypes) {
4294 QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
4295 argumentTypes = queuedConnectionTypes(m);
4296 if (!argumentTypes) // cannot queue arguments
4297 argumentTypes = &DIRECT_CONNECTION_ONLY;
4298 if (!c->argumentTypes.testAndSetOrdered(nullptr, argumentTypes)) {
4299 if (argumentTypes != &DIRECT_CONNECTION_ONLY)
4300 delete[] argumentTypes;
4301 argumentTypes = c->argumentTypes.loadRelaxed();
4302 }
4303 }
4304 if (argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate
4305 return;
4306 int nargs = 1; // include return type
4307 while (argumentTypes[nargs - 1])
4308 ++nargs;
4309
4310 QMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
4311 QObject *receiver = c->receiver.loadRelaxed();
4312 if (!receiver) {
4313 // the connection has been disconnected before we got the lock
4314 return;
4315 }
4316
4317 SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj : nullptr };
4318 locker.unlock();
4319
4320 QVarLengthArray<const QtPrivate::QMetaTypeInterface *, 16> argTypes;
4321 argTypes.reserve(nargs);
4322 argTypes.emplace_back(nullptr); // return type
4323 for (int n = 1; n < nargs; ++n) {
4324 argTypes.emplace_back(QMetaType(argumentTypes[n - 1]).iface()); // convert type ids to QMetaTypeInterfaces
4325 }
4326
4327 auto ev = c->isSlotObject ?
4328 std::make_unique<QQueuedMetaCallEvent>(c->slotObj,
4329 sender, signal, nargs, argTypes.data(), argv) :
4330 std::make_unique<QQueuedMetaCallEvent>(c->method_offset, c->method_relative, c->callFunction,
4331 sender, signal, nargs, argTypes.data(), argv);
4332
4333 if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) {
4334 return;
4335 }
4336
4337 locker.relock();
4338 if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
4339 // the connection has been disconnected while we were unlocked
4340 locker.unlock();
4341 return;
4342 }
4343
4344 QCoreApplication::postEvent(receiver, ev.release());
4345}
4346
4347template <bool callbacks_enabled>
4348void doActivate(QObject *sender, int signal_index, void **argv)
4349{
4350 QObjectPrivate *sp = QObjectPrivate::get(sender);
4351
4352 if (sp->blockSig)
4353 return;
4354
4355 Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
4356
4357 if (sp->isDeclarativeSignalConnected(signal_index)
4358 && QAbstractDeclarativeData::signalEmitted) {
4359 Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
4360 QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
4361 signal_index, argv);
4362 }
4363
4364 const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() : nullptr;
4365
4366 void *empty_argv[] = { nullptr };
4367 if (!argv)
4368 argv = empty_argv;
4369
4370 bool senderDeleted = false;
4371 {
4372 QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadAcquire());
4373 if (!connections || !sp->maybeSignalConnected(signal_index)) {
4374 // The possible declarative connection is done, and nothing else is connected
4375 if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
4376 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4377 if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
4378 signal_spy_set->signal_end_callback(sender, signal_index);
4379 return;
4380 }
4381
4382 if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
4383 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4384
4385 // loadAcquire pairs with the storeRelease in resizeSignalVector(), ensuring
4386 // that all writes to the new SignalVector's contents are visible here.
4387 QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadAcquire();
4388
4389 const QObjectPrivate::ConnectionList *list;
4390 if (signal_index < signalVector->count())
4391 list = &signalVector->at(signal_index);
4392 else
4393 list = &signalVector->at(-1);
4394
4395 Qt::HANDLE currentThreadId = QThread::currentThreadId();
4396 bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
4397
4398 // We need to check against the highest connection id to ensure that signals added
4399 // during the signal emission are not emitted in this emission.
4400 uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
4401 do {
4402 QObjectPrivate::Connection *c = list->first.loadAcquire();
4403 if (!c)
4404 continue;
4405
4406 do {
4407 QObject * const receiver = c->receiver.loadRelaxed();
4408 if (!receiver)
4409 continue;
4410
4411 QThreadData *td = c->receiverThreadData.loadRelaxed();
4412 if (!td)
4413 continue;
4414
4415 bool receiverInSameThread;
4416 if (inSenderThread) {
4417 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4418 } else {
4419 // need to lock before reading the threadId, because moveToThread() could interfere
4420 QMutexLocker lock(signalSlotLock(receiver));
4421 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4422 }
4423
4424
4425 // determine if this connection should be sent immediately or
4426 // put into the event queue
4427 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
4428 || (c->connectionType == Qt::QueuedConnection)) {
4429 queued_activate(sender, signal_index, c, argv);
4430 continue;
4431#if QT_CONFIG(thread)
4432 } else if (c->connectionType == Qt::BlockingQueuedConnection) {
4433 if (receiverInSameThread) {
4434 qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
4435 "Sender is %s(%p), receiver is %s(%p)",
4436 sender->metaObject()->className(), sender,
4437 receiver->metaObject()->className(), receiver);
4438 }
4439
4440 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4441 continue;
4442
4443 QLatch latch(1);
4444 {
4445 QMutexLocker locker(signalSlotLock(receiver));
4446 if (!c->isSingleShot && !c->receiver.loadAcquire())
4447 continue;
4448 QMetaCallEvent *ev = c->isSlotObject ?
4449 new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &latch) :
4450 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
4451 sender, signal_index, argv, &latch);
4452 QCoreApplication::postEvent(receiver, ev);
4453 }
4454 latch.wait();
4455 continue;
4456#endif
4457 }
4458
4459 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4460 continue;
4461
4462 QObjectPrivate::Sender senderData(
4463 receiverInSameThread ? receiver : nullptr, sender, signal_index,
4464 receiverInSameThread ? QObjectPrivate::get(receiver)->connections.loadAcquire() : nullptr);
4465
4466 if (c->isSlotObject) {
4467 SlotObjectGuard obj{c->slotObj};
4468
4469 {
4470 Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
4471 obj->call(receiver, argv);
4472 }
4473 } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
4474 //we compare the vtable to make sure we are not in the destructor of the object.
4475 const int method_relative = c->method_relative;
4476 const auto callFunction = c->callFunction;
4477 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
4478 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)
4479 signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
4480
4481 {
4482 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
4483 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
4484 }
4485
4486 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
4487 signal_spy_set->slot_end_callback(receiver, methodIndex);
4488 } else {
4489 const int method = c->method_relative + c->method_offset;
4490
4491 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {
4492 signal_spy_set->slot_begin_callback(receiver, method, argv);
4493 }
4494
4495 {
4496 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
4497 QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
4498 }
4499
4500 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
4501 signal_spy_set->slot_end_callback(receiver, method);
4502 }
4503 } while ((c = c->nextConnectionList.loadAcquire()) != nullptr && c->id.loadAcquire() <= highestConnectionId);
4504
4505 } while (list != &signalVector->at(-1) &&
4506 //start over for all signals;
4507 ((list = &signalVector->at(-1)), true));
4508
4509 if (connections->currentConnectionId.loadRelaxed() == 0)
4510 senderDeleted = true;
4511 }
4512
4513 if (!senderDeleted) {
4514 sp->connections.loadAcquire()->cleanOrphanedConnections(sender);
4515
4516 if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
4517 signal_spy_set->signal_end_callback(sender, signal_index);
4518 }
4519}
4520
4521/*!
4522 \internal
4523 */
4524void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
4525 void **argv)
4526{
4527 int signal_index = local_signal_index + QMetaObjectPrivate::signalOffset(m);
4528
4529 if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
4530 doActivate<true>(sender, signal_index, argv);
4531 else
4532 doActivate<false>(sender, signal_index, argv);
4533}
4534
4535/*!
4536 \internal
4537 */
4538void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
4539{
4540 int signal_index = signalOffset + local_signal_index;
4541
4542 if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
4543 doActivate<true>(sender, signal_index, argv);
4544 else
4545 doActivate<false>(sender, signal_index, argv);
4546}
4547
4548/*!
4549 \internal
4550 signal_index comes from indexOfMethod()
4551*/
4552void QMetaObject::activate(QObject *sender, int signal_index, void **argv)
4553{
4554 const QMetaObject *mo = sender->metaObject();
4555 while (mo->methodOffset() > signal_index)
4556 mo = mo->superClass();
4557 activate(sender, mo, signal_index - mo->methodOffset(), argv);
4558}
4559
4560/*!
4561 \internal
4562 Returns the signal index used in the internal connections->receivers vector.
4563
4564 It is different from QMetaObject::indexOfSignal(): indexOfSignal is the same as indexOfMethod
4565 while QObjectPrivate::signalIndex is smaller because it doesn't give index to slots.
4566
4567 If \a meta is not \nullptr, it is set to the meta-object where the signal was found.
4568*/
4569int QObjectPrivate::signalIndex(const char *signalName,
4570 const QMetaObject **meta) const
4571{
4572 Q_Q(const QObject);
4573 const QMetaObject *base = q->metaObject();
4574 Q_ASSERT(QMetaObjectPrivate::get(base)->revision >= 7);
4575 QArgumentTypeArray types;
4576 QByteArrayView name = QMetaObjectPrivate::decodeMethodSignature(signalName, types);
4577 int relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, name, types);
4578 if (relative_index < 0)
4579 return relative_index;
4580 relative_index = QMetaObjectPrivate::originalClone(base, relative_index);
4581 if (meta)
4582 *meta = base;
4583 return relative_index + QMetaObjectPrivate::signalOffset(base);
4584}
4585
4586/*****************************************************************************
4587 Properties
4588 *****************************************************************************/
4589
4590/*!
4591 \fn bool QObject::setProperty(const char *name, const QVariant &value)
4592
4593 Sets the value of the object's \a name property to \a value.
4594
4595 If the property is defined in the class using Q_PROPERTY then
4596 true is returned on success and false otherwise. If the property
4597 is not defined using Q_PROPERTY, and therefore not listed in the
4598 meta-object, it is added as a dynamic property and false is returned.
4599
4600 Information about all available properties is provided through the
4601 metaObject() and dynamicPropertyNames().
4602
4603 Dynamic properties can be queried again using property() and can be
4604 removed by setting the property value to an invalid QVariant.
4605 Changing the value of a dynamic property causes a QDynamicPropertyChangeEvent
4606 to be sent to the object.
4607
4608 \b{Note:} Dynamic properties starting with "_q_" are reserved for internal
4609 purposes.
4610
4611 \sa property(), metaObject(), dynamicPropertyNames(), QMetaProperty::write()
4612*/
4613
4614/*!
4615 \fn bool QObject::setProperty(const char *name, QVariant &&value)
4616 \since 6.6
4617 \overload setProperty
4618*/
4619
4620bool QObject::doSetProperty(const char *name, const QVariant &value, QVariant *rvalue)
4621{
4622 Q_D(QObject);
4623 const QMetaObject *meta = metaObject();
4624 if (!name || !meta)
4625 return false;
4626
4627 int id = meta->indexOfProperty(name);
4628 if (id < 0) {
4629 d->ensureExtraData();
4630
4631 const qsizetype idx = d->extraData->propertyNames.indexOf(name);
4632
4633 if (!value.isValid()) {
4634 if (idx == -1)
4635 return false;
4636 d->extraData->propertyNames.removeAt(idx);
4637 d->extraData->propertyValues.removeAt(idx);
4638 } else {
4639 if (idx == -1) {
4640 d->extraData->propertyNames.append(name);
4641 q_choose_append(d->extraData->propertyValues, value, rvalue);
4642 } else {
4643 if (value.userType() == d->extraData->propertyValues.at(idx).userType()
4644 && value == d->extraData->propertyValues.at(idx))
4645 return false;
4646 q_choose_assign(d->extraData->propertyValues[idx], value, rvalue);
4647 }
4648 }
4649
4650 QDynamicPropertyChangeEvent ev(name);
4651 QCoreApplication::sendEvent(this, &ev);
4652
4653 return false;
4654 }
4655 QMetaProperty p = meta->property(id);
4656#ifndef QT_NO_DEBUG
4657 if (!p.isWritable())
4658 qWarning("%s::setProperty: Property \"%s\" invalid,"
4659 " read-only or does not exist", metaObject()->className(), name);
4660#endif
4661 return rvalue ? p.write(this, std::move(*rvalue)) : p.write(this, value);
4662}
4663
4664/*!
4665 Returns the value of the object's \a name property.
4666
4667 If no such property exists, the returned variant is invalid.
4668
4669 Information about all available properties is provided through the
4670 metaObject() and dynamicPropertyNames().
4671
4672 \sa setProperty(), QVariant::isValid(), metaObject(), dynamicPropertyNames()
4673*/
4674QVariant QObject::property(const char *name) const
4675{
4676 Q_D(const QObject);
4677 const QMetaObject *meta = metaObject();
4678 if (!name || !meta)
4679 return QVariant();
4680
4681 int id = meta->indexOfProperty(name);
4682 if (id < 0) {
4683 if (!d->extraData)
4684 return QVariant();
4685 const qsizetype i = d->extraData->propertyNames.indexOf(name);
4686 return d->extraData->propertyValues.value(i);
4687 }
4688 QMetaProperty p = meta->property(id);
4689#ifndef QT_NO_DEBUG
4690 if (!p.isReadable())
4691 qWarning("%s::property: Property \"%s\" invalid or does not exist",
4692 metaObject()->className(), name);
4693#endif
4694 return p.read(this);
4695}
4696
4697/*!
4698 \since 4.2
4699
4700 Returns the names of all properties that were dynamically added to
4701 the object using setProperty().
4702*/
4703QList<QByteArray> QObject::dynamicPropertyNames() const
4704{
4705 Q_D(const QObject);
4706 if (d->extraData)
4707 return d->extraData->propertyNames;
4708 return QList<QByteArray>();
4709}
4710
4711/*****************************************************************************
4712 QObject debugging output routines.
4713 *****************************************************************************/
4714
4715std::string QObjectPrivate::flagsForDumping() const
4716{
4717 return {};
4718}
4719
4720static void dumpRecursive(int level, const QObject *object)
4721{
4722 if (object) {
4723 const int indent = level * 4;
4724 qDebug("%*s%s::%ls %s", indent, "", object->metaObject()->className(),
4725 qUtf16Printable(object->objectName()),
4726 QObjectPrivate::get(object)->flagsForDumping().c_str());
4727 for (auto child : object->children())
4728 dumpRecursive(level + 1, child);
4729 }
4730}
4731
4732
4733/*!
4734 Dumps a tree of children to the debug output.
4735
4736 \note Before Qt 5.9, this function was not const.
4737
4738 \sa dumpObjectInfo()
4739*/
4740
4741void QObject::dumpObjectTree() const
4742{
4743 dumpRecursive(0, this);
4744}
4745
4746/*!
4747 Dumps information about signal connections, etc. for this object
4748 to the debug output.
4749
4750 \note Before Qt 5.9, this function was not const.
4751
4752 \sa dumpObjectTree()
4753*/
4754
4755void QObject::dumpObjectInfo() const
4756{
4757 qDebug("OBJECT %s::%s", metaObject()->className(),
4758 objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
4759
4760 Q_D(const QObject);
4761 QMutexLocker locker(signalSlotLock(this));
4762
4763 // first, look for connections where this object is the sender
4764 qDebug(" SIGNALS OUT");
4765
4766 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
4767 if (cd && cd->signalVectorCount() > 0) {
4768 QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
4769 for (int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
4770 const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
4771 if (!c)
4772 continue;
4773 const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index);
4774 qDebug(" signal: %s", signal.methodSignature().constData());
4775
4776 // receivers
4777 while (c) {
4778 if (!c->receiver.loadRelaxed()) {
4779 qDebug(" <Disconnected receiver>");
4780 c = c->nextConnectionList.loadRelaxed();
4781 continue;
4782 }
4783 if (c->isSlotObject) {
4784 qDebug(" <functor or function pointer>");
4785 c = c->nextConnectionList.loadRelaxed();
4786 continue;
4787 }
4788 const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
4789 const QMetaMethod method = receiverMetaObject->method(c->method());
4790 qDebug(" --> %s::%s %s",
4791 receiverMetaObject->className(),
4792 c->receiver.loadRelaxed()->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
4793 method.methodSignature().constData());
4794 c = c->nextConnectionList.loadRelaxed();
4795 }
4796 }
4797 } else {
4798 qDebug( " <None>" );
4799 }
4800
4801 // now look for connections where this object is the receiver
4802 qDebug(" SIGNALS IN");
4803
4804 if (cd && cd->senders) {
4805 for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
4806 QByteArray slotName = QByteArrayLiteral("<unknown>");
4807 if (!s->isSlotObject) {
4808 const QMetaMethod slot = metaObject()->method(s->method());
4809 slotName = slot.methodSignature();
4810 }
4811 qDebug(" <-- %s::%s %s",
4812 s->sender->metaObject()->className(),
4813 s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()),
4814 slotName.constData());
4815 }
4816 } else {
4817 qDebug(" <None>");
4818 }
4819}
4820
4821
4822#ifndef QT_NO_DEBUG_STREAM
4823void QObjectPrivate::writeToDebugStream(QDebug &dbg) const
4824{
4825 Q_Q(const QObject);
4826 dbg.nospace() << q->metaObject()->className() << '(' << (const void *)q;
4827 if (!q->objectName().isEmpty())
4828 dbg << ", name = " << q->objectName();
4829 dbg << ')';
4830}
4831
4832QDebug operator<<(QDebug dbg, const QObject *o)
4833{
4834 QDebugStateSaver saver(dbg);
4835 if (!o)
4836 return dbg << "QObject(0x0)";
4837
4838 const QObjectPrivate *d = QObjectPrivate::get(o);
4839 d->writeToDebugStream(dbg);
4840 return dbg;
4841}
4842#endif
4843
4844/*!
4845 \macro Q_CLASSINFO(Name, Value)
4846 \relates QObject
4847
4848 This macro associates extra information to the class, which is available
4849 using QObject::metaObject(). The extra information takes the form of a
4850 \a Name string and a \a Value literal string.
4851
4852 Example:
4853
4854 \snippet code/src_corelib_kernel_qobject.cpp 35
4855
4856 Qt makes use of the macro in \l{Qt D-Bus} and \l{Qt Qml} modules.
4857 For instance, when defining \l{QML Object Types} in C++, you can
4858 designate a property as the \e default one:
4859
4860 \snippet code/doc_src_properties.cpp 7
4861
4862 \sa QMetaObject::classInfo()
4863 \sa {Using Qt D-Bus Adaptors}
4864 \sa {Defining QML Types from C++}
4865*/
4866
4867/*!
4868 \macro Q_INTERFACES(...)
4869 \relates QObject
4870
4871 This macro tells Qt which interfaces the class implements. This
4872 is used when implementing plugins.
4873
4874 \sa Q_DECLARE_INTERFACE(), Q_PLUGIN_METADATA(), {How to Create Qt Plugins}
4875*/
4876
4877/*!
4878 \macro Q_PROPERTY(...)
4879 \relates QObject
4880
4881 This macro is used for declaring properties in classes that
4882 inherit QObject. Properties behave like class data members, but
4883 they have additional features accessible through the \l
4884 {Meta-Object System}.
4885
4886 \snippet code/doc_src_properties.cpp 0
4887
4888 The property name and type and the \c READ function are required.
4889 The type can be any type supported by QVariant, or it can be a
4890 user-defined type. The other items are optional, but a \c WRITE
4891 function is common. The attributes default to true except \c USER,
4892 which defaults to false.
4893
4894 For example:
4895
4896 \snippet code/src_corelib_kernel_qobject.cpp 37
4897
4898 For more details about how to use this macro, and a more detailed
4899 example of its use, see the discussion on \l {Qt's Property System}.
4900
4901 \sa {Qt's Property System}
4902*/
4903
4904/*!
4905 \macro Q_ENUMS(...)
4906 \relates QObject
4907 \deprecated [5.5]
4908
4909 In new code, you should prefer the use of the Q_ENUM() macro, which makes the
4910 type available also to the meta type system.
4911 For instance, QMetaEnum::fromType() will not work with types declared with Q_ENUMS().
4912
4913 This macro registers one or several enum types to the meta-object
4914 system.
4915
4916 If you want to register an enum that is declared in another class,
4917 the enum must be fully qualified with the name of the class
4918 defining it. In addition, the class \e defining the enum has to
4919 inherit QObject as well as declare the enum using Q_ENUMS().
4920
4921 \sa {Qt's Property System}
4922*/
4923
4924/*!
4925 \macro Q_FLAGS(...)
4926 \relates QObject
4927 \deprecated [5.5]
4928
4929 This macro registers one or several \l{QFlags}{flags types} with the
4930 meta-object system. It is typically used in a class definition to declare
4931 that values of a given enum can be used as flags and combined using the
4932 bitwise OR operator.
4933
4934 \note This macro takes care of registering individual flag values
4935 with the meta-object system, so it is unnecessary to use Q_ENUMS()
4936 in addition to this macro.
4937
4938 In new code, you should prefer the use of the Q_FLAG() macro, which makes the
4939 type available also to the meta type system.
4940
4941 \sa {Qt's Property System}
4942*/
4943
4944/*!
4945 \macro Q_ENUM(...)
4946 \relates QObject
4947 \since 5.5
4948
4949 This macro registers an enum type with the meta-object system.
4950 It must be placed after the enum declaration in a class that has the Q_OBJECT,
4951 Q_GADGET or Q_GADGET_EXPORT macro. For namespaces use \l Q_ENUM_NS() instead.
4952
4953 For example:
4954
4955 \snippet code/src_corelib_kernel_qobject.cpp 38
4956
4957 Enumerations that are declared with Q_ENUM have their QMetaEnum registered in the
4958 enclosing QMetaObject. You can also use QMetaEnum::fromType() to get the QMetaEnum.
4959
4960 Registered enumerations are automatically registered also to the Qt meta
4961 type system, making them known to QMetaType without the need to use
4962 Q_DECLARE_METATYPE(). This will enable useful features; for example, if used
4963 in a QVariant, you can convert them to strings. Likewise, passing them to
4964 QDebug will print out their names.
4965
4966 \sa {Qt's Property System}
4967*/
4968
4969
4970/*!
4971 \macro Q_FLAG(...)
4972 \relates QObject
4973 \since 5.5
4974
4975 This macro registers a single \l{QFlags}{flags type} with the
4976 meta-object system. It is typically used in a class definition to declare
4977 that values of a given enum can be used as flags and combined using the
4978 bitwise OR operator. For namespaces use \l Q_FLAG_NS() instead.
4979
4980 The macro must be placed after the enum declaration. The declaration of
4981 the flags type is done using the \l Q_DECLARE_FLAGS() macro.
4982
4983 For example, in QItemSelectionModel, the
4984 \l{QItemSelectionModel::SelectionFlags}{SelectionFlags} flag is
4985 declared in the following way:
4986
4987 \quotefromfile itemmodels/qitemselectionmodel.h
4988
4989 \skipto class Q_CORE_EXPORT QItemSelectionModel
4990 \printuntil Q_OBJECT
4991
4992 \dots
4993
4994 \skipto public:
4995 \printuntil Q_FLAG(SelectionFlags)
4996
4997 \skipuntil Q_DISABLE_COPY
4998 \printto Q_DECLARE_OPERATORS_FOR_FLAGS
4999
5000 \note The Q_FLAG macro takes care of registering individual flag values
5001 with the meta-object system, so it is unnecessary to use Q_ENUM()
5002 in addition to this macro.
5003
5004 \sa {Qt's Property System}
5005*/
5006
5007/*!
5008 \macro Q_ENUM_NS(...)
5009 \relates QObject
5010 \since 5.8
5011
5012 This macro registers an enum type with the meta-object system.
5013 It must be placed after the enum declaration in a namespace that
5014 has the Q_NAMESPACE macro. It is the same as \l Q_ENUM but in a
5015 namespace.
5016
5017 Enumerations that are declared with Q_ENUM_NS have their QMetaEnum
5018 registered in the enclosing QMetaObject. You can also use
5019 QMetaEnum::fromType() to get the QMetaEnum.
5020
5021 Registered enumerations are automatically registered also to the Qt meta
5022 type system, making them known to QMetaType without the need to use
5023 Q_DECLARE_METATYPE(). This will enable useful features; for example, if
5024 used in a QVariant, you can convert them to strings. Likewise, passing them
5025 to QDebug will print out their names.
5026
5027 \sa {Qt's Property System}
5028*/
5029
5030
5031/*!
5032 \macro Q_FLAG_NS(...)
5033 \relates QObject
5034 \since 5.8
5035
5036 This macro registers a single \l{QFlags}{flags type} with the
5037 meta-object system. It is used in a namespace that has the
5038 Q_NAMESPACE macro, to declare that values of a given enum can be
5039 used as flags and combined using the bitwise OR operator.
5040 It is the same as \l Q_FLAG but in a namespace.
5041
5042 The macro must be placed after the enum declaration.
5043
5044 \note The Q_FLAG_NS macro takes care of registering individual flag
5045 values with the meta-object system, so it is unnecessary to use
5046 Q_ENUM_NS() in addition to this macro.
5047
5048 \sa {Qt's Property System}
5049*/
5050
5051/*!
5052 \macro Q_OBJECT
5053 \relates QObject
5054
5055 The Q_OBJECT macro is used to enable meta-object features, such as dynamic
5056 properties, signals, and slots.
5057
5058 You can add the Q_OBJECT macro to any section of a class definition that
5059 declares its own signals and slots or that uses other services provided by
5060 Qt's meta-object system.
5061
5062//! [qobject-macros-private-access-specifier]
5063 \note This macro expansion ends with a \c private: access specifier. If you
5064 declare members immediately after this macro, those members will also be
5065 private. To add public (or protected) members right after the macro, use a
5066 \c {public:} (or \c {protected:}) access specifier.
5067//! [qobject-macros-private-access-specifier]
5068
5069 Example:
5070
5071 \snippet signalsandslots/signalsandslots.h 1
5072 \codeline
5073 \snippet signalsandslots/signalsandslots.h 2
5074 \snippet signalsandslots/signalsandslots.h 3
5075
5076 \note This macro requires the class to be a subclass of QObject. Use
5077 Q_GADGET or Q_GADGET_EXPORT instead of Q_OBJECT to enable the meta object
5078 system's support for enums in a class that is not a QObject subclass.
5079
5080 \sa {Meta-Object System}, {Signals and Slots}, {Qt's Property System}
5081*/
5082
5083/*!
5084 \macro Q_GADGET
5085 \relates QObject
5086
5087 The Q_GADGET macro is a lighter version of the Q_OBJECT macro for classes
5088 that do not inherit from QObject but still want to use some of the
5089 reflection capabilities offered by QMetaObject.
5090
5091 \include qobject.cpp qobject-macros-private-access-specifier
5092
5093 Q_GADGETs can have Q_ENUM, Q_PROPERTY and Q_INVOKABLE, but they cannot have
5094 signals or slots.
5095
5096 Q_GADGET makes a class member, \c{staticMetaObject}, available.
5097 \c{staticMetaObject} is of type QMetaObject and provides access to the
5098 enums declared with Q_ENUM.
5099
5100 \sa Q_GADGET_EXPORT
5101*/
5102
5103/*!
5104 \macro Q_GADGET_EXPORT(EXPORT_MACRO)
5105 \relates QObject
5106 \since 6.3
5107
5108 The Q_GADGET_EXPORT macro works exactly like the Q_GADGET macro.
5109 However, the \c{staticMetaObject} variable that is made available (see
5110 Q_GADGET) is declared with the supplied \a EXPORT_MACRO qualifier. This is
5111 useful if the object needs to be exported from a dynamic library, but the
5112 enclosing class as a whole should not be (e.g. because it consists of mostly
5113 inline functions).
5114
5115 \include qobject.cpp qobject-macros-private-access-specifier
5116
5117 For example:
5118
5119 \code
5120 class Point {
5121 Q_GADGET_EXPORT(EXPORT_MACRO)
5122 Q_PROPERTY(int x MEMBER x)
5123 Q_PROPERTY(int y MEMBER y)
5124 ~~~
5125 \endcode
5126
5127 \sa Q_GADGET, {Creating Shared Libraries}
5128*/
5129
5130/*!
5131 \macro Q_NAMESPACE
5132 \relates QObject
5133 \since 5.8
5134
5135 The Q_NAMESPACE macro can be used to add QMetaObject capabilities
5136 to a namespace.
5137
5138 Q_NAMESPACEs can have Q_CLASSINFO, Q_ENUM_NS, Q_FLAG_NS, but they
5139 cannot have Q_ENUM, Q_FLAG, Q_PROPERTY, Q_INVOKABLE, signals nor slots.
5140
5141 Q_NAMESPACE makes an external variable, \c{staticMetaObject}, available.
5142 \c{staticMetaObject} is of type QMetaObject and provides access to the
5143 enums declared with Q_ENUM_NS/Q_FLAG_NS.
5144
5145 For example:
5146
5147 \code
5148 namespace test {
5149 Q_NAMESPACE
5150 ...
5151 \endcode
5152
5153 \sa Q_NAMESPACE_EXPORT
5154*/
5155
5156/*!
5157 \macro Q_NAMESPACE_EXPORT(EXPORT_MACRO)
5158 \relates QObject
5159 \since 5.14
5160
5161 The Q_NAMESPACE_EXPORT macro can be used to add QMetaObject capabilities
5162 to a namespace.
5163
5164 It works exactly like the Q_NAMESPACE macro. However, the external
5165 \c{staticMetaObject} variable that gets defined in the namespace
5166 is declared with the supplied \a EXPORT_MACRO qualifier. This is
5167 useful if the object needs to be exported from a dynamic library.
5168
5169 For example:
5170
5171 \code
5172 namespace test {
5173 Q_NAMESPACE_EXPORT(EXPORT_MACRO)
5174 ...
5175 \endcode
5176
5177 \sa Q_NAMESPACE, {Creating Shared Libraries}
5178*/
5179
5180/*!
5181 \macro Q_MOC_INCLUDE
5182 \relates QObject
5183 \since 6.0
5184
5185 The Q_MOC_INCLUDE macro can be used within or outside a class, and tell the
5186 \l{moc}{Meta Object Compiler} to add an include.
5187
5188 \code
5189 // Put this in your code and the generated code will include this header.
5190 Q_MOC_INCLUDE("myheader.h")
5191 \endcode
5192
5193 This is useful if the types you use as properties or signal/slots arguments
5194 are forward declared.
5195*/
5196
5197/*!
5198 \macro Q_SIGNALS
5199 \relates QObject
5200
5201 Use this macro to replace the \c signals keyword in class
5202 declarations, when you want to use Qt Signals and Slots with a
5203 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5204
5205 The macro is normally used when \c no_keywords is specified with
5206 the \c CONFIG variable in the \c .pro file, but it can be used
5207 even when \c no_keywords is \e not specified.
5208*/
5209
5210/*!
5211 \macro Q_SIGNAL
5212 \relates QObject
5213
5214 This is an additional macro that allows you to mark a single
5215 function as a signal. It can be quite useful, especially when you
5216 use a 3rd-party source code parser which doesn't understand a \c
5217 signals or \c Q_SIGNALS groups.
5218
5219 Use this macro to replace the \c signals keyword in class
5220 declarations, when you want to use Qt Signals and Slots with a
5221 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5222
5223 The macro is normally used when \c no_keywords is specified with
5224 the \c CONFIG variable in the \c .pro file, but it can be used
5225 even when \c no_keywords is \e not specified.
5226*/
5227
5228/*!
5229 \macro Q_SLOTS
5230 \relates QObject
5231
5232 Use this macro to replace the \c slots keyword in class
5233 declarations, when you want to use Qt Signals and Slots with a
5234 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5235
5236 The macro is normally used when \c no_keywords is specified with
5237 the \c CONFIG variable in the \c .pro file, but it can be used
5238 even when \c no_keywords is \e not specified.
5239*/
5240
5241/*!
5242 \macro Q_SLOT
5243 \relates QObject
5244
5245 This is an additional macro that allows you to mark a single
5246 function as a slot. It can be quite useful, especially when you
5247 use a 3rd-party source code parser which doesn't understand a \c
5248 slots or \c Q_SLOTS groups.
5249
5250 Use this macro to replace the \c slots keyword in class
5251 declarations, when you want to use Qt Signals and Slots with a
5252 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5253
5254 The macro is normally used when \c no_keywords is specified with
5255 the \c CONFIG variable in the \c .pro file, but it can be used
5256 even when \c no_keywords is \e not specified.
5257*/
5258
5259/*!
5260 \macro Q_EMIT
5261 \relates QObject
5262
5263 Use this macro to replace the \c emit keyword for emitting
5264 signals, when you want to use Qt Signals and Slots with a
5265 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5266
5267 The macro is normally used when \c no_keywords is specified with
5268 the \c CONFIG variable in the \c .pro file, but it can be used
5269 even when \c no_keywords is \e not specified.
5270*/
5271
5272/*!
5273 \macro Q_INVOKABLE
5274 \relates QObject
5275
5276 Apply this macro to declarations of member functions to allow them to
5277 be invoked via the meta-object system. The macro is written before
5278 the return type, as shown in the following example:
5279
5280 \snippet qmetaobject-invokable/window.h Window class with invokable method
5281
5282 The \c invokableMethod() function is marked up using Q_INVOKABLE, causing
5283 it to be registered with the meta-object system and enabling it to be
5284 invoked using QMetaObject::invokeMethod().
5285 Since \c normalMethod() function is not registered in this way, it cannot
5286 be invoked using QMetaObject::invokeMethod().
5287
5288 If an invokable member function returns a pointer to a QObject or a
5289 subclass of QObject and it is invoked from QML, special ownership rules
5290 apply. See \l{qtqml-cppintegration-data.html}{Data Type Conversion Between QML and C++}
5291 for more information.
5292*/
5293
5294/*!
5295 \macro Q_REVISION
5296 \relates QObject
5297
5298 Apply this macro to declarations of member functions to tag them with a
5299 revision number in the meta-object system. The macro is written before
5300 the return type, as shown in the following example:
5301
5302 \snippet qmetaobject-revision/window.h Window class with revision
5303
5304 This is useful when using the meta-object system to dynamically expose
5305 objects to another API, as you can match the version expected by multiple
5306 versions of the other API. Consider the following simplified example:
5307
5308 \snippet qmetaobject-revision/main.cpp Window class using revision
5309
5310 Using the same Window class as the previous example, the newProperty and
5311 newMethod would only be exposed in this code when the expected version is
5312 \c{2.1} or greater.
5313
5314 Since all methods are considered to be in revision \c{0} if untagged, a tag
5315 of \c{Q_REVISION(0)} or \c{Q_REVISION(0, 0)} is invalid and ignored.
5316
5317 You can pass one or two integer parameters to \c{Q_REVISION}. If you pass
5318 one parameter, it denotes the minor version only. This means that the major
5319 version is unspecified. If you pass two, the first parameter is the major
5320 version and the second parameter is the minor version.
5321
5322 This tag is not used by the meta-object system itself. Currently this is only
5323 used by the QtQml module.
5324
5325 For a more generic string tag, see \l QMetaMethod::tag()
5326
5327 \sa QMetaMethod::revision()
5328*/
5329
5330/*!
5331 \macro Q_SET_OBJECT_NAME(Object)
5332 \relates QObject
5333 \since 5.0
5334
5335 This macro assigns \a Object the objectName "Object".
5336
5337 It doesn't matter whether \a Object is a pointer or not, the
5338 macro figures that out by itself.
5339
5340 \sa QObject::objectName()
5341*/
5342
5343/*!
5344 \macro QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
5345 \relates QObject
5346 \since 5.8
5347
5348 Defining this macro will disable narrowing and floating-point-to-integral
5349 conversions between the arguments carried by a signal and the arguments
5350 accepted by a slot, when the signal and the slot are connected using the
5351 PMF-based syntax.
5352
5353 \sa QObject::connect
5354*/
5355
5356/*!
5357 \macro QT_NO_CONTEXTLESS_CONNECT
5358 \relates QObject
5359 \since 6.7
5360
5361 Defining this macro will disable the overload of QObject::connect() that
5362 connects a signal to a functor, without also specifying a QObject
5363 as a receiver/context object (that is, the 3-arguments overload
5364 of QObject::connect()).
5365
5366 Using the context-less overload is error prone, because it is easy
5367 to connect to functors that depend on some local state of the
5368 receiving end. If such local state gets destroyed, the connection
5369 does not get automatically disconnected.
5370
5371 Moreover, such connections are always direct connections, which may
5372 cause issues in multithreaded scenarios (for instance, if the
5373 signal is emitted from another thread).
5374
5375 \sa QObject::connect, Qt::ConnectionType
5376*/
5377
5378/*!
5379 \since 6.12
5380 \macro QT_NO_DISCONNECT_CONST_CONNECTION
5381 \relates QObject
5382
5383 Disables the \c{const &} overload of
5384 \l{QObject::disconnect(QMetaObject::Connection&)}{QObject::disconnect()} to
5385 force callers to pass non-const objects.
5386
5387 Passing non-const objects is preferred, because they can be reset
5388 immediately, releasing resources sooner. Different versions of Qt handle
5389 the const overload differently. In older Qt versions, calling the const
5390 overload with a Connection originally declared \c{const} may invoke
5391 undefined behavior. Current Qt versions are safe in this regard, but future
5392 Qt versions may remove the const overload, or have it delay releasing
5393 resources until the Connection object is reassigned or destroyed.
5394
5395 Passing non-const objects avoids all of the issues above.
5396
5397 Code that compiles with this macro set also compiles (and doesn't invoke
5398 undefined behavior) without the macro enabled, and in all Qt versions since
5399 5.0.
5400*/
5401
5402/*!
5403 \typedef QObjectList
5404 \relates QObject
5405
5406 Synonym for QList<QObject *>.
5407*/
5408
5409/*!
5410 \fn template<typename PointerToMemberFunction> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type)
5411 \overload connect()
5412 \threadsafe
5413
5414 Creates a connection of the given \a type from the \a signal in
5415 the \a sender object to the \a method in the \a receiver object.
5416 Returns a handle to the connection that can be used to disconnect
5417 it later.
5418
5419 The signal must be a function declared as a signal in the header.
5420 The slot function can be any member function that can be connected
5421 to the signal.
5422 A slot can be connected to a given signal if the signal has at
5423 least as many arguments as the slot, and there is an implicit
5424 conversion between the types of the corresponding arguments in the
5425 signal and the slot.
5426
5427 Example:
5428
5429 \snippet code/src_corelib_kernel_qobject.cpp 44
5430
5431 This example ensures that the label always displays the current
5432 line edit text.
5433
5434 A signal can be connected to many slots and signals. Many signals
5435 can be connected to one slot.
5436
5437 If a signal is connected to several slots, the slots are activated
5438 in the same order as the order the connection was made, when the
5439 signal is emitted
5440
5441 The function returns an handle to a connection if it successfully
5442 connects the signal to the slot. The Connection handle will be invalid
5443 if it cannot create the connection, for example, if QObject is unable
5444 to verify the existence of \a signal (if it was not declared as a signal)
5445 You can check if the QMetaObject::Connection is valid by casting it to a bool.
5446
5447 By default, a signal is emitted for every connection you make;
5448 two signals are emitted for duplicate connections. You can break
5449 all of these connections with a single disconnect() call.
5450 If you pass the Qt::UniqueConnection \a type, the connection will only
5451 be made if it is not a duplicate. If there is already a duplicate
5452 (exact same signal to the exact same slot on the same objects),
5453 the connection will fail and connect will return an invalid QMetaObject::Connection.
5454
5455 The optional \a type parameter describes the type of connection
5456 to establish. In particular, it determines whether a particular
5457 signal is delivered to a slot immediately or queued for delivery
5458 at a later time. If the signal is queued, the parameters must be
5459 of types that are known to Qt's meta-object system, because Qt
5460 needs to copy the arguments to store them in an event behind the
5461 scenes. If you try to use a queued connection and get the error
5462 message
5463
5464 \snippet code/src_corelib_kernel_qobject.cpp 25
5465
5466 make sure to declare the argument type with Q_DECLARE_METATYPE
5467
5468 Overloaded functions can be resolved with help of \l qOverload.
5469
5470 \sa {Differences between String-Based and Functor-Based Connections}
5471 */
5472
5473/*!
5474 \fn template<typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
5475
5476 \threadsafe
5477 \overload connect()
5478
5479 Creates a connection from \a signal in
5480 \a sender object to \a functor, and returns a handle to the connection
5481
5482 The signal must be a function declared as a signal in the header.
5483 The slot function can be any function or functor that can be connected
5484 to the signal.
5485 A slot function can be connected to a given signal if the signal has at
5486 least as many arguments as the slot function. There must exist implicit
5487 conversion between the types of the corresponding arguments in the
5488 signal and the slot.
5489
5490 Example:
5491
5492 \snippet code/src_corelib_kernel_qobject.cpp 45
5493
5494 Lambda expressions can also be used:
5495
5496 \snippet code/src_corelib_kernel_qobject.cpp 46
5497
5498 The connection will automatically disconnect if the sender is destroyed.
5499 However, you should take care that any objects used within the functor
5500 are still alive when the signal is emitted.
5501
5502 For this reason, it is recommended to use the overload of connect()
5503 that also takes a QObject as a receiver/context. It is possible
5504 to disable the usage of the context-less overload by defining the
5505 \c{QT_NO_CONTEXTLESS_CONNECT} macro.
5506
5507 Overloaded functions can be resolved with help of \l qOverload.
5508
5509 */
5510
5511/*!
5512 \fn template<typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type)
5513
5514 \threadsafe
5515 \overload connect()
5516
5517 \since 5.2
5518
5519 Creates a connection of a given \a type from \a signal in
5520 \a sender object to \a functor to be placed in a specific event
5521 loop of \a context, and returns a handle to the connection.
5522
5523 \note Qt::UniqueConnections do not work for lambdas, non-member functions
5524 and functors; they only apply to connecting to member functions.
5525
5526 The signal must be a function declared as a signal in the header.
5527 The slot function can be any function or functor that can be connected
5528 to the signal.
5529 A slot function can be connected to a given signal if the signal has at
5530 least as many arguments as the slot function. There must exist implicit
5531 conversion between the types of the corresponding arguments in the
5532 signal and the slot.
5533
5534 Example:
5535
5536 \snippet code/src_corelib_kernel_qobject.cpp 50_someFunction
5537 \snippet code/src_corelib_kernel_qobject.cpp 50
5538
5539 Lambda expressions can also be used:
5540
5541 \snippet code/src_corelib_kernel_qobject.cpp 51
5542
5543 The connection will automatically disconnect if the sender or the context
5544 is destroyed.
5545 However, you should take care that any objects used within the functor
5546 are still alive when the signal is emitted.
5547
5548 Overloaded functions can be resolved with help of \l qOverload.
5549 */
5550
5551/*!
5552 \internal
5553
5554 Implementation of the template version of connect
5555
5556 \a sender is the sender object
5557 \a signal is a pointer to a pointer to a member signal of the sender
5558 \a receiver is the receiver object, may not be \nullptr, will be equal to sender when
5559 connecting to a static function or a functor
5560 \a slot a pointer only used when using Qt::UniqueConnection
5561 \a type the Qt::ConnectionType passed as argument to connect
5562 \a types an array of integer with the metatype id of the parameter of the signal
5563 to be used with queued connection
5564 must stay valid at least for the whole time of the connection, this function
5565 do not take ownership. typically static data.
5566 If \nullptr, then the types will be computed when the signal is emit in a queued
5567 connection from the types from the signature.
5568 \a senderMetaObject is the metaobject used to lookup the signal, the signal must be in
5569 this metaobject
5570 */
5571QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,
5572 const QObject *receiver, void **slot,
5573 QtPrivate::QSlotObjectBase *slotObjRaw, Qt::ConnectionType type,
5574 const int *types, const QMetaObject *senderMetaObject)
5575{
5576 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5577 Q_ASSERT_X(slotObjRaw, "QObject::connect", "Internal error, caller must not pass null slotObj");
5578 if (!signal) {
5579 connectWarning(sender, senderMetaObject, receiver, "invalid nullptr parameter");
5580 return QMetaObject::Connection();
5581 }
5582
5583 int signal_index = -1;
5584 void *args[] = { &signal_index, signal };
5585 for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
5586 senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
5587 if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
5588 break;
5589 }
5590 if (!senderMetaObject) {
5591 connectWarning(sender, senderMetaObject, receiver, "signal not found");
5592 return QMetaObject::Connection(nullptr);
5593 }
5594 signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
5595 return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj.release(), type, types, senderMetaObject);
5596}
5597
5598/*!
5599 \internal
5600
5601 Internal version of connect used by the template version of QObject::connect (called via connectImpl) and
5602 also used by the QObjectPrivate::connect version used by QML. The signal_index is expected to be relative
5603 to the number of signals.
5604 */
5605QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index,
5606 const QObject *receiver, void **slot,
5607 QtPrivate::QSlotObjectBase *slotObjRaw, int type,
5608 const int *types, const QMetaObject *senderMetaObject)
5609{
5610 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5611 Q_ASSERT(senderMetaObject);
5612 Q_ASSERT(slotObj);
5613
5614 if (!sender || !receiver) {
5615 connectWarning(sender, senderMetaObject, receiver, "invalid nullptr parameter");
5616 return QMetaObject::Connection();
5617 }
5618
5619 if (type & Qt::UniqueConnection && !slot) {
5620 connectWarning(sender, senderMetaObject, receiver, "unique connections require a pointer to member function of a QObject subclass");
5621 return QMetaObject::Connection();
5622 }
5623
5624 QObject *s = const_cast<QObject *>(sender);
5625 QObject *r = const_cast<QObject *>(receiver);
5626
5627 QOrderedMutexLocker locker(signalSlotLock(sender),
5628 signalSlotLock(receiver));
5629
5630 if (type & Qt::UniqueConnection) {
5631 QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
5632 if (connections && connections->signalVectorCount() > signal_index) {
5633 const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
5634
5635 while (c2) {
5636 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot))
5637 return QMetaObject::Connection();
5638 c2 = c2->nextConnectionList.loadRelaxed();
5639 }
5640 }
5641 }
5642 type &= ~Qt::UniqueConnection;
5643
5644 const bool isSingleShot = type & Qt::SingleShotConnection;
5645 type &= ~Qt::SingleShotConnection;
5646
5647 Q_ASSERT(type >= 0);
5648 Q_ASSERT(type <= 3);
5649
5650 std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
5651 c->sender = s;
5652 c->signal_index = signal_index;
5653 QThreadData *td = r->d_func()->threadData.loadAcquire();
5654 td->ref();
5655 c->receiverThreadData.storeRelaxed(td);
5656 c->receiver.storeRelaxed(r);
5657 c->connectionType = type;
5658 c->isSlotObject = true;
5659 c->slotObj = slotObj.release();
5660 if (types) {
5661 c->argumentTypes.storeRelaxed(types);
5662 c->ownArgumentTypes = false;
5663 }
5664 c->isSingleShot = isSingleShot;
5665
5666 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
5667 QMetaObject::Connection ret(c.release());
5668 locker.unlock();
5669
5670 QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
5671 Q_ASSERT(method.isValid());
5672 s->connectNotify(method);
5673
5674 return ret;
5675}
5676
5677#ifndef QT_NO_DISCONNECT_CONST_CONNECTION
5678/*!
5679 Disconnects \a connection and resets it to
5680 \l{QMetaObject::Connection::operator bool()}{invalid}.
5681
5682 If \a connection is invalid or has already been disconnected, do nothing
5683 and return false.
5684
5685 \note Future versions of Qt may only accept non-const objects here.
5686
5687 \sa QT_NO_DISCONNECT_CONST_CONNECTION
5688 \sa connect()
5689 */
5690bool QObject::disconnect(const QMetaObject::Connection &connection)
5691{
5692 // keep in sync with non-const overload
5693 QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(connection.d_ptr);
5694 if (!c)
5695 return false;
5696 const bool disconnected = QObjectPrivate::removeConnection(c);
5697 connection.d_ptr = nullptr;
5698 c->deref(); // has been removed from the QMetaObject::Connection object
5699 return disconnected;
5700}
5701#endif // QT_NO_DISCONNECT_CONST_CONNECTION
5702
5703/*!
5704 \since 6.12
5705 \fn bool QObject::disconnect(QMetaObject::Connection &connection)
5706 \fn bool QObject::disconnect(QMetaObject::Connection &&connection)
5707
5708 Disconnect a connection.
5709
5710 If \a connection is
5711 \l{QMetaObject::Connection::operator bool()}{invalid}
5712 or has already been disconnected, do nothing and return false.
5713
5714 \note In Qt versions prior to 6.12, this function took only by \c{const-&}.
5715
5716 \sa connect()
5717 */
5718bool QObject::disconnect(QMetaObject::Connection &connection)
5719{
5720 // keep in sync with the overload above
5721 QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(connection.d_ptr);
5722 if (!c)
5723 return false;
5724 const bool disconnected = QObjectPrivate::removeConnection(c);
5725 connection.d_ptr = nullptr;
5726 c->deref(); // has been removed from the QMetaObject::Connection object
5727 return disconnected;
5728}
5729
5730/*! \fn template<typename PointerToMemberFunction> bool QObject::disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method)
5731 \overload disconnect()
5732 \threadsafe
5733
5734 Disconnects \a signal in object \a sender from \a method in object
5735 \a receiver. Returns \c true if the connection is successfully broken;
5736 otherwise returns \c false.
5737
5738 A signal-slot connection is removed when either of the objects
5739 involved are destroyed.
5740
5741 disconnect() is typically used in three ways, as the following
5742 examples demonstrate.
5743 \list 1
5744 \li Disconnect everything connected to an object's signals:
5745
5746 \snippet code/src_corelib_kernel_qobject.cpp 26
5747
5748 \li Disconnect everything connected to a specific signal:
5749
5750 \snippet code/src_corelib_kernel_qobject.cpp 47
5751
5752 \li Disconnect a specific receiver:
5753
5754 \snippet code/src_corelib_kernel_qobject.cpp 30
5755
5756 \li Disconnect a connection from one specific signal to a specific slot:
5757
5758 \snippet code/src_corelib_kernel_qobject.cpp 48
5759
5760
5761 \endlist
5762
5763 \nullptr may be used as a wildcard, meaning "any signal", "any receiving
5764 object", or "any slot in the receiving object", respectively.
5765
5766 The \a sender may never be \nullptr. (You cannot disconnect signals
5767 from more than one object in a single call.)
5768
5769 If \a signal is \nullptr, it disconnects \a receiver and \a method from
5770 any signal. If not, only the specified signal is disconnected.
5771
5772 If \a receiver is \nullptr, it disconnects anything connected to \a
5773 signal. If not, only slots in the specified receiver are disconnected.
5774 disconnect() with a non-null \a receiver also disconnects slot functions
5775 that were connected with \a receiver as their context object.
5776
5777 If \a method is \nullptr, it disconnects anything that is connected to \a
5778 receiver. If not, only slots named \a method will be disconnected,
5779 and all other slots are left alone. The \a method must be \nullptr
5780 if \a receiver is left out, so you cannot disconnect a
5781 specifically-named slot on all objects.
5782
5783 \note It is not possible to use this overload to disconnect signals
5784 connected to functors or lambda expressions. That is because it is not
5785 possible to compare them. Instead, use the overload that takes a
5786 QMetaObject::Connection.
5787
5788 \note Unless \a method is \nullptr, this function will also not break
5789 connections that were made using the string-based version of connect(). To
5790 break such connections, use the corresponding string-based overload of
5791 disconnect().
5792
5793 \sa connect()
5794*/
5795
5796bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot, const QMetaObject *senderMetaObject)
5797{
5798 if (sender == nullptr || (receiver == nullptr && slot != nullptr)) {
5799 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
5800 return false;
5801 }
5802
5803 int signal_index = -1;
5804 if (signal) {
5805 void *args[] = { &signal_index, signal };
5806 for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
5807 senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
5808 if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
5809 break;
5810 }
5811 if (!senderMetaObject) {
5812 qCWarning(lcConnect, "QObject::disconnect: signal not found in %s", sender->metaObject()->className());
5813 return false;
5814 }
5815 signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
5816 }
5817
5818 return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1, slot);
5819}
5820
5821/*!
5822 \internal
5823 Used by QML to connect a signal by index to a slot implemented in JavaScript
5824 (wrapped in a custom QSlotObjectBase subclass).
5825
5826 This version of connect assumes that sender and receiver are the same object.
5827
5828 The signal_index is an index relative to the number of methods.
5829 */
5830QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type)
5831{
5832 return QObjectPrivate::connect(sender, signal_index, sender, slotObj, type);
5833}
5834
5835/*!
5836 \internal
5837 Used by QML to connect a signal by index to a slot implemented in JavaScript
5838 (wrapped in a custom QSlotObjectBase subclass).
5839
5840 This is an overload that should be used when \a sender and \a receiver are
5841 different objects.
5842
5843 The signal_index is an index relative to the number of methods.
5844 */
5845QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index,
5846 const QObject *receiver,
5847 QtPrivate::QSlotObjectBase *slotObjRaw,
5848 Qt::ConnectionType type)
5849{
5850 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5851 Q_ASSERT_X(slotObjRaw, "QObjectPrivate::connect", "Internal error, caller must not pass null slotObj");
5852 if (!sender) {
5853 connectWarning(sender, nullptr, receiver, "invalid nullptr parameter");
5854 return QMetaObject::Connection();
5855 }
5856 const QMetaObject *senderMetaObject = sender->metaObject();
5857 signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
5858
5859 return connectImpl(sender, signal_index, receiver, /*slot*/ nullptr, slotObj.release(),
5860 type, /*types*/ nullptr, senderMetaObject);
5861}
5862
5863/*!
5864 \internal
5865 Used by QML to disconnect a signal by index that's connected to a slot implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass)
5866 In the QML case the slot is not a pointer to a pointer to the function to disconnect, but instead it is a pointer to an array of internal values
5867 required for the disconnect.
5868
5869 This version of disconnect assumes that sender and receiver are the same object.
5870 */
5871bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, void **slot)
5872{
5873 return QObjectPrivate::disconnect(sender, signal_index, sender, slot);
5874}
5875
5876/*!
5877 \internal
5878
5879 Used by QML to disconnect a signal by index that's connected to a slot
5880 implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass) In the
5881 QML case the slot is not a pointer to a pointer to the function to disconnect,
5882 but instead it is a pointer to an array of internal values required for the
5883 disconnect.
5884
5885 This is an overload that should be used when \a sender and \a receiver are
5886 different objects.
5887 */
5888bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, const QObject *receiver,
5889 void **slot)
5890{
5891 const QMetaObject *senderMetaObject = sender->metaObject();
5892 signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
5893
5894 return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1,
5895 slot);
5896}
5897
5898/*!
5899 \internal
5900 \threadsafe
5901*/
5902inline bool QObjectPrivate::removeConnection(QObjectPrivate::Connection *c)
5903{
5904 if (!c)
5905 return false;
5906 QObject *receiver = c->receiver.loadRelaxed();
5907 if (!receiver)
5908 return false;
5909
5910 QBasicMutex *senderMutex = signalSlotLock(c->sender);
5911 QBasicMutex *receiverMutex = signalSlotLock(receiver);
5912
5913 QObjectPrivate::ConnectionData *connections;
5914 {
5915 QOrderedMutexLocker locker(senderMutex, receiverMutex);
5916
5917 // load receiver once again and recheck to ensure nobody else has removed the connection in the meantime
5918 receiver = c->receiver.loadRelaxed();
5919 if (!receiver)
5920 return false;
5921
5922 connections = QObjectPrivate::get(c->sender)->connections.loadRelaxed();
5923 Q_ASSERT(connections);
5924 connections->removeConnection(c);
5925
5926 c->sender->disconnectNotify(QMetaObjectPrivate::signal(c->sender->metaObject(), c->signal_index));
5927 // We must not hold the receiver mutex, else we risk dead-locking; we also only need the sender mutex
5928 // It is however vital to hold the senderMutex before calling cleanOrphanedConnections, as otherwise
5929 // another thread might modify/delete the connection
5930 if (receiverMutex != senderMutex) {
5931 receiverMutex->unlock();
5932 }
5933 connections->cleanOrphanedConnections(c->sender, ConnectionData::AlreadyLockedAndTemporarilyReleasingLock);
5934 senderMutex->unlock(); // now both sender and receiver mutex have been manually unlocked
5935 locker.dismiss(); // so we dismiss the QOrderedMutexLocker
5936 }
5937
5938 return true;
5939}
5940
5941/*!
5942 \internal
5943
5944 Used by QPropertyAdaptorSlotObject to get an existing instance for a property, if available
5945 */
5946QtPrivate::QPropertyAdaptorSlotObject *
5947QObjectPrivate::getPropertyAdaptorSlotObject(const QMetaProperty &property)
5948{
5949 if (auto conns = connections.loadAcquire()) {
5950 Q_Q(QObject);
5951 const QMetaObject *metaObject = q->metaObject();
5952 int signal_index = methodIndexToSignalIndex(&metaObject, property.notifySignalIndex());
5953 if (signal_index >= conns->signalVectorCount())
5954 return nullptr;
5955 const auto &connectionList = conns->connectionsForSignal(signal_index);
5956 for (auto c = connectionList.first.loadRelaxed(); c;
5957 c = c->nextConnectionList.loadRelaxed()) {
5958 if (c->isSlotObject) {
5959 if (auto p = QtPrivate::QPropertyAdaptorSlotObject::cast(c->slotObj,
5960 property.propertyIndex()))
5961 return p;
5962 }
5963 }
5964 }
5965 return nullptr;
5966}
5967
5968/*! \class QMetaObject::Connection
5969 \inmodule QtCore
5970 Represents a handle to a signal-slot (or signal-functor) connection.
5971
5972 It can be used to check if the connection is valid and to disconnect it using
5973 QObject::disconnect(). For a signal-functor connection without a context object,
5974 it is the only way to selectively disconnect that connection.
5975
5976 As Connection is just a handle, the underlying signal-slot connection is unaffected
5977 when Connection is destroyed or reassigned.
5978 */
5979
5980/*!
5981 Create a copy of the handle to the \a other connection
5982 */
5983QMetaObject::Connection::Connection(const QMetaObject::Connection &other) : d_ptr(other.d_ptr)
5984{
5985 if (d_ptr)
5986 static_cast<QObjectPrivate::Connection *>(d_ptr)->ref();
5987}
5988
5989/*!
5990 Assigns \a other to this connection and returns a reference to this connection.
5991*/
5992QMetaObject::Connection &QMetaObject::Connection::operator=(const QMetaObject::Connection &other)
5993{
5994 if (other.d_ptr != d_ptr) {
5995 if (d_ptr)
5996 static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
5997 d_ptr = other.d_ptr;
5998 if (other.d_ptr)
5999 static_cast<QObjectPrivate::Connection *>(other.d_ptr)->ref();
6000 }
6001 return *this;
6002}
6003
6004/*!
6005 \fn QMetaObject::Connection::Connection();
6006
6007 Creates a Connection instance.
6008*/
6009
6010/*!
6011 Destructor for QMetaObject::Connection.
6012*/
6013QMetaObject::Connection::~Connection()
6014{
6015 if (d_ptr)
6016 static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
6017}
6018
6019/*! \internal Returns true if the object is still connected */
6020bool QMetaObject::Connection::isConnected_helper() const
6021{
6022 Q_ASSERT(d_ptr); // we're only called from operator RestrictedBool() const
6023 QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(d_ptr);
6024
6025 return c->receiver.loadRelaxed();
6026}
6027
6028
6029/*!
6030 \fn QMetaObject::Connection::operator bool() const
6031
6032 Returns \c true if the connection is valid.
6033
6034 The connection is valid if the call to QObject::connect succeeded.
6035 The connection is invalid if QObject::connect was not able to find
6036 the signal or the slot, or if the arguments do not match.
6037 */
6038
6039QT_END_NAMESPACE
6040
6041#include "moc_qobject.cpp"
Combined button and popup list for selecting options.
Q_TRACE_POINT(qtcore, QCoreApplication_postEvent_exit)
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)
static void check_and_warn_compat(const QMetaObject *sender, const QMetaMethod &signal, const QMetaObject *receiver, const QMetaMethod &method)
Definition qobject.cpp:3068
static int * queuedConnectionTypes(QSpan< const QArgumentType > argumentTypes)
Definition qobject.cpp:116
static int DIRECT_CONNECTION_ONLY
Definition qobject.cpp:67
static void disconnectNotifySender(QObject *sender, int signalIndex, Qt::HANDLE currentThreadId)
Definition qobject.cpp:166
static int methodIndexToSignalIndex(const QMetaObject **base, int signal_index)
Definition qobject.cpp:3769
QObject * qt_qFindChild_helper(const QObject *parent, QAnyStringView name, const QMetaObject &mo, Qt::FindChildOptions options)
Definition qobject.cpp:2290
static const char * extract_location(const char *member)
Definition qobject.cpp:2709
ConnectionEnd
Definition qobject.cpp:2783
Q_TRACE_POINT(qtcore, QMetaObject_activate_slot_functor_entry, void *slotObject)
static bool check_parent_thread(QObject *parent, QThreadData *parentThreadData, QThreadData *currentThreadData)
Definition qobject.cpp:972
static int * queuedConnectionTypes(const QMetaMethod &method)
Definition qobject.cpp:87
static void computeOffsets(const QMetaObject *metaobject, int *signalOffset, int *methodOffset)
Definition qobject.cpp:251
static QBasicMutex * signalSlotLock(const QObject *o)
Definition qobject.cpp:148
static Q_DECL_COLD_FUNCTION void err_method_notfound(const QObject *object, const char *method, const char *func)
Definition qobject.cpp:2765
static Q_DECL_COLD_FUNCTION void connectWarning(const QObject *sender, const QMetaObject *senderMetaObject, const QObject *receiver, const char *message)
Definition qobject.cpp:2809
static bool check_method_code(int code, const QObject *object, const char *method, const char *func)
Definition qobject.cpp:2736
static Q_DECL_COLD_FUNCTION void err_info_about_object(const char *func, const QObject *o, ConnectionEnd end)
Definition qobject.cpp:2785
void qt_register_signal_spy_callbacks(QSignalSpyCallbackSet *callback_set)
Definition qobject.cpp:74
static bool matches_objectName_non_null(QObject *obj, QAnyStringView name)
Definition qobject.cpp:2243
Q_TRACE_POINT(qtcore, QObject_dtor, QObject *object)
Q_TRACE_POINT(qtcore, QMetaObject_activate_entry, QObject *sender, int signalIndex)
static int extract_code(const char *member)
Definition qobject.cpp:2703
static bool check_signal_macro(const QObject *sender, const char *signal, const char *func, const char *op)
Definition qobject.cpp:2720
static Q_DECL_COLD_FUNCTION void err_info_about_objects(const char *func, const QObject *sender, const QObject *receiver)
Definition qobject.cpp:2802
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, QAnyStringView name, const QMetaObject &mo, QList< void * > *list, Qt::FindChildOptions options)
Definition qobject.cpp:2253
Q_CORE_EXPORT const char * qFlagLocation(const char *method)
Definition qobject.cpp:2697
SlotObjectGuard()=default