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