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