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 control returns to the event
1898 loop, that is, there are no more native window 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
2719static void connectWarning(const QObject *sender,
2720 const QMetaObject *senderMetaObject,
2721 const QObject *receiver,
2722 const char *message)
2723{
2724 const char *senderString = sender ? sender->metaObject()->className()
2725 : senderMetaObject ? senderMetaObject->className()
2726 : "Unknown";
2727 const char *receiverString = receiver ? receiver->metaObject()->className()
2728 : "Unknown";
2729 qCWarning(lcConnect, "QObject::connect(%s, %s): %s", senderString, receiverString, message);
2730}
2731
2732/*!
2733 Returns a pointer to the object that sent the signal, if called in
2734 a slot activated by a signal; otherwise it returns \nullptr. The pointer
2735 is valid only during the execution of the slot that calls this
2736 function from this object's thread context.
2737
2738 The pointer returned by this function becomes invalid if the
2739 sender is destroyed, or if the slot is disconnected from the
2740 sender's signal.
2741
2742 \warning This function violates the object-oriented principle of
2743 modularity. However, getting access to the sender might be useful
2744 when many signals are connected to a single slot.
2745
2746 \warning As mentioned above, the return value of this function is
2747 not valid when the slot is called via a Qt::DirectConnection from
2748 a thread different from this object's thread. Do not use this
2749 function in this type of scenario.
2750
2751 \sa senderSignalIndex()
2752*/
2753
2754QObject *QObject::sender() const
2755{
2756 Q_D(const QObject);
2757
2758 QMutexLocker locker(signalSlotLock(this));
2759 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2760 if (!cd || !cd->currentSender)
2761 return nullptr;
2762
2763 for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2764 if (c->sender == cd->currentSender->sender)
2765 return cd->currentSender->sender;
2766 }
2767
2768 return nullptr;
2769}
2770
2771/*!
2772 \since 4.8
2773
2774 Returns the meta-method index of the signal that called the currently
2775 executing slot, which is a member of the class returned by sender().
2776 If called outside of a slot activated by a signal, -1 is returned.
2777
2778 For signals with default parameters, this function will always return
2779 the index with all parameters, regardless of which was used with
2780 connect(). For example, the signal \c {destroyed(QObject *obj = \nullptr)}
2781 will have two different indexes (with and without the parameter), but
2782 this function will always return the index with a parameter. This does
2783 not apply when overloading signals with different parameters.
2784
2785 \warning This function violates the object-oriented principle of
2786 modularity. However, getting access to the signal index might be useful
2787 when many signals are connected to a single slot.
2788
2789 \warning The return value of this function is not valid when the slot
2790 is called via a Qt::DirectConnection from a thread different from this
2791 object's thread. Do not use this function in this type of scenario.
2792
2793 \sa sender(), QMetaObject::indexOfSignal(), QMetaObject::method()
2794*/
2795
2796int QObject::senderSignalIndex() const
2797{
2798 Q_D(const QObject);
2799
2800 QMutexLocker locker(signalSlotLock(this));
2801 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2802 if (!cd || !cd->currentSender)
2803 return -1;
2804
2805 for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2806 if (c->sender == cd->currentSender->sender) {
2807 // Convert from signal range to method range
2808 return QMetaObjectPrivate::signal(c->sender->metaObject(), cd->currentSender->signal).methodIndex();
2809 }
2810 }
2811
2812 return -1;
2813}
2814
2815/*!
2816 Returns the number of receivers connected to the \a signal.
2817
2818 Since both slots and signals can be used as receivers for signals,
2819 and the same connections can be made many times, the number of
2820 receivers is the same as the number of connections made from this
2821 signal.
2822
2823 When calling this function, you can use the \c SIGNAL() macro to
2824 pass a specific signal:
2825
2826 \snippet code/src_corelib_kernel_qobject.cpp 21
2827
2828 As the code snippet above illustrates, you can use this function to avoid
2829 expensive operations or emitting a signal that nobody listens to.
2830
2831 \warning In a multithreaded application, consecutive calls to this
2832 function are not guaranteed to yield the same results.
2833
2834 \warning This function violates the object-oriented principle of
2835 modularity. In particular, this function must not be called from an
2836 override of connectNotify() or disconnectNotify(), as those might get
2837 called from any thread.
2838
2839 \sa isSignalConnected()
2840*/
2841
2842int QObject::receivers(const char *signal) const
2843{
2844 Q_D(const QObject);
2845 int receivers = 0;
2846 if (signal) {
2847 QByteArray signal_name = QMetaObject::normalizedSignature(signal);
2848 signal = signal_name;
2849#ifndef QT_NO_DEBUG
2850 if (!check_signal_macro(this, signal, "receivers", "bind"))
2851 return 0;
2852#endif
2853 signal++; // skip code
2854 int signal_index = d->signalIndex(signal);
2855 if (signal_index < 0) {
2856#ifndef QT_NO_DEBUG
2857 err_method_notfound(this, signal - 1, "receivers");
2858#endif
2859 return 0;
2860 }
2861
2862 if (!d->isSignalConnected(signal_index))
2863 return receivers;
2864
2865 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::receivers) {
2866 receivers += QAbstractDeclarativeData::receivers(d->declarativeData, this,
2867 signal_index);
2868 }
2869
2870 QMutexLocker locker(signalSlotLock(this));
2871 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2872 if (cd && signal_index < cd->signalVectorCount()) {
2873 const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
2874 while (c) {
2875 receivers += c->receiver.loadRelaxed() ? 1 : 0;
2876 c = c->nextConnectionList.loadRelaxed();
2877 }
2878 }
2879 }
2880 return receivers;
2881}
2882
2883/*!
2884 \since 5.0
2885 Returns \c true if the \a signal is connected to at least one receiver,
2886 otherwise returns \c false.
2887
2888 \a signal must be a signal member of this object, otherwise the behaviour
2889 is undefined.
2890
2891 \snippet code/src_corelib_kernel_qobject.cpp 49
2892
2893 As the code snippet above illustrates, you can use this function to avoid
2894 expensive operations or emitting a signal that nobody listens to.
2895
2896 \warning In a multithreaded application, consecutive calls to this
2897 function are not guaranteed to yield the same results.
2898
2899 \warning This function violates the object-oriented principle of
2900 modularity. In particular, this function must not be called from an
2901 override of connectNotify() or disconnectNotify(), as those might get
2902 called from any thread.
2903
2904 \sa receivers()
2905*/
2906bool QObject::isSignalConnected(const QMetaMethod &signal) const
2907{
2908 Q_D(const QObject);
2909 if (!signal.mobj)
2910 return false;
2911
2912 Q_ASSERT_X(signal.mobj->cast(this) && signal.methodType() == QMetaMethod::Signal,
2913 "QObject::isSignalConnected" , "the parameter must be a signal member of the object");
2914 uint signalIndex = signal.relativeMethodIndex();
2915
2916 if (signal.data.flags() & MethodCloned)
2917 signalIndex = QMetaObjectPrivate::originalClone(signal.mobj, signalIndex);
2918
2919 signalIndex += QMetaObjectPrivate::signalOffset(signal.mobj);
2920
2921 QMutexLocker locker(signalSlotLock(this));
2922 return d->isSignalConnected(signalIndex, true);
2923}
2924
2925/*!
2926 \internal
2927
2928 This helper function calculates signal and method index for the given
2929 member in the specified class.
2930
2931 \list
2932 \li If member.mobj is \nullptr then both signalIndex and methodIndex are set to -1.
2933
2934 \li If specified member is not a member of obj instance class (or one of
2935 its parent classes) then both signalIndex and methodIndex are set to -1.
2936 \endlist
2937
2938 This function is used by QObject::connect and QObject::disconnect which
2939 are working with QMetaMethod.
2940
2941 \a signalIndex is set to the signal index of member. If the member
2942 specified is not signal this variable is set to -1.
2943
2944 \a methodIndex is set to the method index of the member. If the
2945 member is not a method of the object specified by the \a obj argument this
2946 variable is set to -1.
2947*/
2948void QMetaObjectPrivate::memberIndexes(const QObject *obj,
2949 const QMetaMethod &member,
2950 int *signalIndex, int *methodIndex)
2951{
2952 *signalIndex = -1;
2953 *methodIndex = -1;
2954 if (!obj || !member.mobj)
2955 return;
2956 const QMetaObject *m = obj->metaObject();
2957 // Check that member is member of obj class
2958 while (m != nullptr && m != member.mobj)
2959 m = m->d.superdata;
2960 if (!m)
2961 return;
2962 *signalIndex = *methodIndex = member.relativeMethodIndex();
2963
2964 int signalOffset;
2965 int methodOffset;
2966 computeOffsets(m, &signalOffset, &methodOffset);
2967
2968 *methodIndex += methodOffset;
2969 if (member.methodType() == QMetaMethod::Signal) {
2970 *signalIndex = originalClone(m, *signalIndex);
2971 *signalIndex += signalOffset;
2972 } else {
2973 *signalIndex = -1;
2974 }
2975}
2976
2977#ifndef QT_NO_DEBUG
2978static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaMethod &signal,
2979 const QMetaObject *receiver, const QMetaMethod &method)
2980{
2981 if (signal.attributes() & QMetaMethod::Compatibility) {
2982 if (!(method.attributes() & QMetaMethod::Compatibility))
2983 qCWarning(lcConnect, "QObject::connect: Connecting from COMPAT signal (%s::%s)",
2984 sender->className(), signal.methodSignature().constData());
2985 } else if ((method.attributes() & QMetaMethod::Compatibility)
2986 && method.methodType() == QMetaMethod::Signal) {
2987 qCWarning(lcConnect, "QObject::connect: Connecting from %s::%s to COMPAT slot (%s::%s)",
2988 sender->className(), signal.methodSignature().constData(), receiver->className(),
2989 method.methodSignature().constData());
2990 }
2991}
2992#endif
2993
2994/*!
2995 \threadsafe
2996
2997 Creates a connection of the given \a type from the \a signal in
2998 the \a sender object to the \a method in the \a receiver object.
2999 Returns a handle to the connection that can be used to disconnect
3000 it later.
3001
3002 You must use the \c SIGNAL() and \c SLOT() macros when specifying
3003 the \a signal and the \a method, for example:
3004
3005 \snippet code/src_corelib_kernel_qobject.cpp 22
3006
3007 This example ensures that the label always displays the current
3008 scroll bar value. Note that the signal and slots parameters must not
3009 contain any variable names, only the type. E.g. the following would
3010 not work and return false:
3011
3012 \snippet code/src_corelib_kernel_qobject.cpp 23
3013
3014 A signal can also be connected to another signal:
3015
3016 \snippet code/src_corelib_kernel_qobject.cpp 24
3017
3018 In this example, the \c MyWidget constructor relays a signal from
3019 a private member variable, and makes it available under a name
3020 that relates to \c MyWidget.
3021
3022 A signal can be connected to many slots and signals. Many signals
3023 can be connected to one slot.
3024
3025 If a signal is connected to several slots, the slots are activated
3026 in the same order in which the connections were made, when the
3027 signal is emitted.
3028
3029 The function returns a QMetaObject::Connection that represents
3030 a handle to a connection if it successfully
3031 connects the signal to the slot. The connection handle will be invalid
3032 if it cannot create the connection, for example, if QObject is unable
3033 to verify the existence of either \a signal or \a method, or if their
3034 signatures aren't compatible.
3035 You can check if the handle is valid by casting it to a bool.
3036
3037 By default, a signal is emitted for every connection you make;
3038 two signals are emitted for duplicate connections. You can break
3039 all of these connections with a single disconnect() call.
3040 If you pass the Qt::UniqueConnection \a type, the connection will only
3041 be made if it is not a duplicate. If there is already a duplicate
3042 (exact same signal to the exact same slot on the same objects),
3043 the connection will fail and connect will return an invalid QMetaObject::Connection.
3044
3045 \note Qt::UniqueConnections do not work for lambdas, non-member functions
3046 and functors; they only apply to connecting to member functions.
3047
3048 The optional \a type parameter describes the type of connection
3049 to establish. In particular, it determines whether a particular
3050 signal is delivered to a slot immediately or queued for delivery
3051 at a later time. If the signal is queued, the parameters must be
3052 of types that are known to Qt's meta-object system, because Qt
3053 needs to copy the arguments to store them in an event behind the
3054 scenes. If you try to use a queued connection and get the error
3055 message
3056
3057 \snippet code/src_corelib_kernel_qobject.cpp 25
3058
3059 call qRegisterMetaType() to register the data type before you
3060 establish the connection.
3061
3062 \sa disconnect(), sender(), qRegisterMetaType(), Q_DECLARE_METATYPE(),
3063 {Differences between String-Based and Functor-Based Connections}
3064*/
3065QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal,
3066 const QObject *receiver, const char *method,
3067 Qt::ConnectionType type)
3068{
3069 if (sender == nullptr || receiver == nullptr || signal == nullptr || method == nullptr) {
3070 qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
3071 sender ? sender->metaObject()->className() : "(nullptr)",
3072 (signal && *signal) ? signal + 1 : "(nullptr)",
3073 receiver ? receiver->metaObject()->className() : "(nullptr)",
3074 (method && *method) ? method + 1 : "(nullptr)");
3075 return QMetaObject::Connection(nullptr);
3076 }
3077
3078 if (!check_signal_macro(sender, signal, "connect", "bind"))
3079 return QMetaObject::Connection(nullptr);
3080
3081 int membcode = extract_code(method);
3082 if (!check_method_code(membcode, receiver, method, "connect"))
3083 return QMetaObject::Connection(nullptr);
3084
3085 QByteArray pinnedSignal;
3086 const QMetaObject *smeta = sender->metaObject();
3087 const char *signal_arg = signal;
3088 ++signal; // skip code
3089 QByteArrayView signalView{signal}; // after skipping code
3090 QArgumentTypeArray signalTypes;
3091 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3092 QByteArrayView signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3093 int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3094 if (signal_index < 0) {
3095 // check for normalized signatures
3096 pinnedSignal = QMetaObjectPrivate::normalizedSignature(signalView);
3097 signalView = pinnedSignal;
3098
3099 signalTypes.clear();
3100 signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3101 smeta = sender->metaObject();
3102 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3103 }
3104 if (signal_index < 0) {
3105 err_method_notfound(sender, signal_arg, "connect");
3106 err_info_about_objects("connect", sender, receiver);
3107 return QMetaObject::Connection(nullptr);
3108 }
3109 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3110 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3111
3112 QByteArray pinnedMethod;
3113 const char *method_arg = method;
3114 ++method; // skip code
3115 QByteArrayView methodView{method}; // after skipping code
3116
3117 QArgumentTypeArray methodTypes;
3118 QByteArrayView methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3119 const QMetaObject *rmeta = receiver->metaObject();
3120 int method_index_relative = -1;
3121 Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
3122 switch (membcode) {
3123 case QSLOT_CODE:
3124 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3125 &rmeta, methodName, methodTypes);
3126 break;
3127 case QSIGNAL_CODE:
3128 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3129 &rmeta, methodName, methodTypes);
3130 break;
3131 }
3132
3133 if (method_index_relative < 0) {
3134 // check for normalized methods
3135 pinnedMethod = QMetaObjectPrivate::normalizedSignature(methodView);
3136 methodView = pinnedMethod;
3137
3138 methodTypes.clear();
3139 methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3140 // rmeta may have been modified above
3141 rmeta = receiver->metaObject();
3142 switch (membcode) {
3143 case QSLOT_CODE:
3144 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3145 &rmeta, methodName, methodTypes);
3146 break;
3147 case QSIGNAL_CODE:
3148 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3149 &rmeta, methodName, methodTypes);
3150 break;
3151 }
3152 }
3153
3154 if (method_index_relative < 0) {
3155 err_method_notfound(receiver, method_arg, "connect");
3156 err_info_about_objects("connect", sender, receiver);
3157 return QMetaObject::Connection(nullptr);
3158 }
3159
3160 if (!QMetaObjectPrivate::checkConnectArgs(signalTypes, methodTypes)) {
3161 qCWarning(lcConnect,
3162 "QObject::connect: Incompatible sender/receiver arguments"
3163 "\n %s::%s --> %s::%s",
3164 sender->metaObject()->className(), signalView.constData(),
3165 receiver->metaObject()->className(), methodView.constData());
3166 return QMetaObject::Connection(nullptr);
3167 }
3168
3169 // ### Future work: attempt get the metatypes from the meta object first
3170 // because it's possible they're all registered.
3171 int *types = nullptr;
3172 if (type == Qt::QueuedConnection && !(types = queuedConnectionTypes(signalTypes))) {
3173 return QMetaObject::Connection(nullptr);
3174 }
3175
3176 QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
3177#ifndef QT_NO_DEBUG
3178 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3179 check_and_warn_compat(smeta, smethod, rmeta, rmethod);
3180#endif
3181
3182#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
3183 check_and_warn_non_slot("connect", method, membcode, rmeta, rmethod);
3184#endif
3185
3186 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3187 sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
3188 return handle;
3189}
3190
3191/*!
3192 \since 4.8
3193
3194 Creates a connection of the given \a type from the \a signal in
3195 the \a sender object to the \a method in the \a receiver object.
3196 Returns a handle to the connection that can be used to disconnect
3197 it later.
3198
3199 The Connection handle will be invalid if it cannot create the
3200 connection, for example, the parameters were invalid.
3201 You can check if the QMetaObject::Connection is valid by casting it to a bool.
3202
3203 This function works in the same way as
3204 \c {connect(const QObject *sender, const char *signal,
3205 const QObject *receiver, const char *method,
3206 Qt::ConnectionType type)}
3207 but it uses QMetaMethod to specify signal and method.
3208
3209 \sa connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
3210 */
3211QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMethod &signal,
3212 const QObject *receiver, const QMetaMethod &method,
3213 Qt::ConnectionType type)
3214{
3215 if (sender == nullptr
3216 || receiver == nullptr
3217 || signal.methodType() != QMetaMethod::Signal
3218 || method.methodType() == QMetaMethod::Constructor) {
3219 qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
3220 sender ? sender->metaObject()->className() : "(nullptr)",
3221 signal.methodSignature().constData(),
3222 receiver ? receiver->metaObject()->className() : "(nullptr)",
3223 method.methodSignature().constData());
3224 return QMetaObject::Connection(nullptr);
3225 }
3226
3227 int signal_index;
3228 int method_index;
3229 {
3230 int dummy;
3231 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3232 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3233 }
3234
3235 const QMetaObject *smeta = sender->metaObject();
3236 const QMetaObject *rmeta = receiver->metaObject();
3237 if (signal_index == -1) {
3238 qCWarning(lcConnect, "QObject::connect: Can't find signal %s on instance of class %s",
3239 signal.methodSignature().constData(), smeta->className());
3240 return QMetaObject::Connection(nullptr);
3241 }
3242 if (method_index == -1) {
3243 qCWarning(lcConnect, "QObject::connect: Can't find method %s on instance of class %s",
3244 method.methodSignature().constData(), rmeta->className());
3245 return QMetaObject::Connection(nullptr);
3246 }
3247
3248 if (!QMetaObject::checkConnectArgs(signal.methodSignature().constData(),
3249 method.methodSignature().constData())) {
3250 qCWarning(lcConnect,
3251 "QObject::connect: Incompatible sender/receiver arguments"
3252 "\n %s::%s --> %s::%s",
3253 smeta->className(), signal.methodSignature().constData(), rmeta->className(),
3254 method.methodSignature().constData());
3255 return QMetaObject::Connection(nullptr);
3256 }
3257
3258 int *types = nullptr;
3259 if ((type == Qt::QueuedConnection) && !(types = queuedConnectionTypes(signal)))
3260 return QMetaObject::Connection(nullptr);
3261
3262#ifndef QT_NO_DEBUG
3263 check_and_warn_compat(smeta, signal, rmeta, method);
3264#endif
3265 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3266 sender, signal_index, signal.enclosingMetaObject(), receiver, method_index, nullptr, type, types));
3267 return handle;
3268}
3269
3270/*!
3271 \fn bool QObject::connect(const QObject *sender, const char *signal, const char *method, Qt::ConnectionType type) const
3272 \overload connect()
3273 \threadsafe
3274
3275 Connects \a signal from the \a sender object to this object's \a
3276 method.
3277
3278 Equivalent to connect(\a sender, \a signal, \c this, \a method, \a type).
3279
3280 Every connection you make emits a signal, so duplicate connections emit
3281 two signals. You can break a connection using disconnect().
3282
3283 \sa disconnect()
3284*/
3285
3286/*!
3287 \threadsafe
3288
3289 Disconnects \a signal in object \a sender from \a method in object
3290 \a receiver. Returns \c true if the connection is successfully broken;
3291 otherwise returns \c false.
3292
3293 A signal-slot connection is removed when either of the objects
3294 involved are destroyed.
3295
3296 disconnect() is typically used in three ways, as the following
3297 examples demonstrate.
3298 \list 1
3299 \li Disconnect everything connected to an object's signals:
3300
3301 \snippet code/src_corelib_kernel_qobject.cpp 26
3302
3303 equivalent to the non-static overloaded function
3304
3305 \snippet code/src_corelib_kernel_qobject.cpp 27
3306
3307 \li Disconnect everything connected to a specific signal:
3308
3309 \snippet code/src_corelib_kernel_qobject.cpp 28
3310
3311 equivalent to the non-static overloaded function
3312
3313 \snippet code/src_corelib_kernel_qobject.cpp 29
3314
3315 \li Disconnect a specific receiver:
3316
3317 \snippet code/src_corelib_kernel_qobject.cpp 30
3318
3319 equivalent to the non-static overloaded function
3320
3321 \snippet code/src_corelib_kernel_qobject.cpp 31
3322
3323 \endlist
3324
3325 \include includes/qobject.qdocinc disconnect-mismatch
3326 \include includes/qobject.qdocinc disconnect-queued
3327
3328 \nullptr may be used as a wildcard, meaning "any signal", "any receiving
3329 object", or "any slot in the receiving object", respectively.
3330
3331 The \a sender may never be \nullptr. (You cannot disconnect signals
3332 from more than one object in a single call.)
3333
3334 If \a signal is \nullptr, it disconnects \a receiver and \a method from
3335 any signal. If not, only the specified signal is disconnected.
3336
3337 If \a receiver is \nullptr, it disconnects anything connected to \a
3338 signal. If not, slots in objects other than \a receiver are not
3339 disconnected.
3340
3341 If \a method is \nullptr, it disconnects anything that is connected to \a
3342 receiver. If not, only slots named \a method will be disconnected,
3343 and all other slots are left alone. The \a method must be \nullptr
3344 if \a receiver is left out, so you cannot disconnect a
3345 specifically-named slot on all objects.
3346
3347 \include includes/qobject.qdocinc disconnect-all
3348
3349 \sa connect()
3350*/
3351bool QObject::disconnect(const QObject *sender, const char *signal,
3352 const QObject *receiver, const char *method)
3353{
3354 if (sender == nullptr || (receiver == nullptr && method != nullptr)) {
3355 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
3356 return false;
3357 }
3358
3359 const char *signal_arg = signal;
3360 if (signal) {
3361 if (!check_signal_macro(sender, signal, "disconnect", "unbind"))
3362 return false;
3363 ++signal; // skip code
3364 }
3365
3366 const char *method_arg = method;
3367 int membcode = -1;
3368 if (method) {
3369 membcode = extract_code(method);
3370 if (!check_method_code(membcode, receiver, method, "disconnect"))
3371 return false;
3372 ++method; // skip code
3373 }
3374
3375 QByteArray pinnedSignal;
3376 const QMetaObject *smeta = sender->metaObject();
3377 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3378 int signal_index = -1;
3379 QByteArrayView signalName;
3380 QArgumentTypeArray signalTypes;
3381 if (signal) {
3382 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3383 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3384 if (signal_index == -1) {
3385 pinnedSignal = QMetaObject::normalizedSignature(signal);
3386 signal = pinnedSignal.constData();
3387 signalTypes.clear();
3388 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3389 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3390 signalTypes);
3391 }
3392 if (signal_index == -1) {
3393 err_method_notfound(sender, signal_arg, "disconnect");
3394 err_info_about_objects("disconnect", sender, receiver);
3395 return false;
3396 }
3397 }
3398
3399 auto getMethodIndex = [](int code, const QMetaObject *mo, QByteArrayView name,
3400 const QArgumentTypeArray &types) {
3401 switch (code) {
3402 case QSLOT_CODE:
3403 return QMetaObjectPrivate::indexOfSlot(mo, name, types);
3404 case QSIGNAL_CODE:
3405 return QMetaObjectPrivate::indexOfSignal(mo, name, types);
3406 }
3407 return -1;
3408 };
3409
3410 QByteArray pinnedMethod;
3411 const QMetaObject *rmeta = receiver ? receiver->metaObject() : nullptr;
3412 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 7);
3413 int method_index = -1;
3414 QByteArrayView methodName;
3415 QArgumentTypeArray methodTypes;
3416 if (method) {
3417 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3418 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3419 if (method_index == -1) {
3420 pinnedMethod = QMetaObject::normalizedSignature(method);
3421 method = pinnedMethod.constData();
3422 methodTypes.clear();
3423 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3424 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3425 }
3426 if (method_index == -1) {
3427 err_method_notfound(receiver, method_arg, "disconnect");
3428 err_info_about_objects("disconnect", sender, receiver);
3429 return false;
3430 }
3431 }
3432
3433 /* We now iterate through all the sender's and receiver's meta
3434 * objects in order to also disconnect possibly shadowed signals
3435 * and slots with the same signature.
3436 */
3437 bool res = false;
3438 do {
3439 if (signal) {
3440 // Already computed the signal_index for `smeta` above
3441 if (smeta != sender->metaObject()) {
3442 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3443 signalTypes);
3444 }
3445 if (signal_index < 0)
3446 break;
3447 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3448 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3449 }
3450
3451 if (!method) {
3452 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1, nullptr);
3453 } else {
3454 do {
3455 // Already computed the method_index for receiver->metaObject() above
3456 if (rmeta != receiver->metaObject())
3457 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3458 if (method_index >= 0) {
3459#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
3460 check_and_warn_non_slot("disconnect", method, membcode, rmeta,
3461 rmeta->method(method_index));
3462#endif
3463 while (method_index < rmeta->methodOffset())
3464 rmeta = rmeta->superClass();
3465 }
3466 if (method_index < 0)
3467 break;
3468 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index, nullptr);
3469 } while ((rmeta = rmeta->superClass()));
3470 }
3471 } while (signal && (smeta = smeta->superClass()));
3472
3473 if (res) {
3474 if (!signal)
3475 const_cast<QObject *>(sender)->disconnectNotify(QMetaMethod());
3476 }
3477 return res;
3478}
3479
3480/*!
3481 \since 4.8
3482
3483 Disconnects \a signal in object \a sender from \a method in object
3484 \a receiver. Returns \c true if the connection is successfully broken;
3485 otherwise returns \c false.
3486
3487 This function provides the same possibilities like
3488 \c {disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method) }
3489 but uses QMetaMethod to represent the signal and the method to be disconnected.
3490
3491 Additionally this function returns false and no signals and slots disconnected
3492 if:
3493 \list 1
3494
3495 \li \a signal is not a member of sender class or one of its parent classes.
3496
3497 \li \a method is not a member of receiver class or one of its parent classes.
3498
3499 \li \a signal instance represents not a signal.
3500
3501 \endlist
3502
3503 \include includes/qobject.qdocinc disconnect-mismatch
3504 \include includes/qobject.qdocinc disconnect-queued
3505
3506 QMetaMethod() may be used as wildcard in the meaning "any signal" or "any slot in receiving object".
3507 In the same way \nullptr can be used for \a receiver in the meaning "any receiving object".
3508 In this case method should also be QMetaMethod(). \a sender parameter should be never \nullptr.
3509
3510 \include includes/qobject.qdocinc disconnect-all
3511
3512 \sa disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
3513 */
3514bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal,
3515 const QObject *receiver, const QMetaMethod &method)
3516{
3517 if (sender == nullptr || (receiver == nullptr && method.mobj != nullptr)) {
3518 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
3519 return false;
3520 }
3521 if (signal.mobj) {
3522 if (signal.methodType() != QMetaMethod::Signal) {
3523 qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s",
3524 "disconnect","unbind",
3525 sender->metaObject()->className(), signal.methodSignature().constData());
3526 return false;
3527 }
3528 }
3529 if (method.mobj) {
3530 if (method.methodType() == QMetaMethod::Constructor) {
3531 qCWarning(lcConnect, "QObject::disconnect: cannot use constructor as argument %s::%s",
3532 receiver->metaObject()->className(), method.methodSignature().constData());
3533 return false;
3534 }
3535 }
3536
3537 int signal_index;
3538 int method_index;
3539 {
3540 int dummy;
3541 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3542 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3543 }
3544 // If we are here sender is not nullptr. If signal is not nullptr while signal_index
3545 // is -1 then this signal is not a member of sender.
3546 if (signal.mobj && signal_index == -1) {
3547 qCWarning(lcConnect, "QObject::disconnect: signal %s not found on class %s",
3548 signal.methodSignature().constData(), sender->metaObject()->className());
3549 return false;
3550 }
3551 // If this condition is true then method is not a member of receiver.
3552 if (receiver && method.mobj && method_index == -1) {
3553 qCWarning(lcConnect, "QObject::disconnect: method %s not found on class %s",
3554 method.methodSignature().constData(), receiver->metaObject()->className());
3555 return false;
3556 }
3557
3558 if (!QMetaObjectPrivate::disconnect(sender, signal_index, signal.mobj, receiver, method_index, nullptr))
3559 return false;
3560
3561 if (!signal.isValid()) {
3562 // The signal is a wildcard, meaning all signals were disconnected.
3563 // QMetaObjectPrivate::disconnect() doesn't call disconnectNotify()
3564 // per connection in this case. Call it once now, with an invalid
3565 // QMetaMethod as argument, as documented.
3566 const_cast<QObject *>(sender)->disconnectNotify(signal);
3567 }
3568 return true;
3569}
3570
3571/*!
3572 \threadsafe
3573
3574 \fn bool QObject::disconnect(const char *signal, const QObject *receiver, const char *method) const
3575 \overload disconnect()
3576
3577 Disconnects \a signal from \a method of \a receiver.
3578
3579 \include includes/qobject.qdocinc disconnect-mismatch
3580 \include includes/qobject.qdocinc disconnect-queued
3581
3582 A signal-slot connection is removed when either of the objects
3583 involved are destroyed.
3584
3585 \include includes/qobject.qdocinc disconnect-all
3586*/
3587
3588/*!
3589 \fn bool QObject::disconnect(const QObject *receiver, const char *method) const
3590 \overload disconnect()
3591
3592 Disconnects all signals in this object from \a receiver's \a
3593 method.
3594
3595 \include includes/qobject.qdocinc disconnect-mismatch
3596 \include includes/qobject.qdocinc disconnect-queued
3597
3598 A signal-slot connection is removed when either of the objects
3599 involved are destroyed.
3600*/
3601
3602
3603/*!
3604 \since 5.0
3605
3606 This virtual function is called when something has been connected
3607 to \a signal in this object.
3608
3609 If you want to compare \a signal with a specific signal, you can
3610 use QMetaMethod::fromSignal() as follows:
3611
3612 \snippet code/src_corelib_kernel_qobject.cpp 32
3613
3614 \warning This function violates the object-oriented principle of
3615 modularity. However, it might be useful when you need to perform
3616 an expensive operation only if something is connected to a signal.
3617
3618 \warning This function is called from the thread which performs the
3619 connection, which may be a different thread from the thread in which
3620 this object lives. This function may also be called with a QObject internal
3621 mutex locked. It is therefore not allowed to re-enter any QObject
3622 functions, including isSignalConnected(), from your reimplementation. If
3623 you lock a mutex in your reimplementation, make sure that you don't call
3624 QObject functions with that mutex held in other places or it will result in
3625 a deadlock.
3626
3627 \sa connect(), disconnectNotify()
3628*/
3629
3630void QObject::connectNotify(const QMetaMethod &signal)
3631{
3632 Q_UNUSED(signal);
3633}
3634
3635/*!
3636 \since 5.0
3637
3638 This virtual function is called when something has been
3639 disconnected from \a signal in this object.
3640
3641 See connectNotify() for an example of how to compare
3642 \a signal with a specific signal.
3643
3644 If all signals were disconnected from this object (e.g., the
3645 signal argument to disconnect() was \nullptr), disconnectNotify()
3646 is only called once, and the \a signal will be an invalid
3647 QMetaMethod (QMetaMethod::isValid() returns \c false).
3648
3649 \warning This function violates the object-oriented principle of
3650 modularity. However, it might be useful for optimizing access to
3651 expensive resources.
3652
3653 \warning This function is called from the thread which performs the
3654 disconnection, which may be a different thread from the thread in which
3655 this object lives. This function may also be called with a QObject internal
3656 mutex locked. It is therefore not allowed to re-enter any QObject
3657 functions, including isSignalConnected(), from your reimplementation. If
3658 you lock a mutex in your reimplementation, make sure that you don't call
3659 QObject functions with that mutex held in other places or it will result in
3660 a deadlock.
3661
3662 \sa disconnect(), connectNotify()
3663*/
3664
3665void QObject::disconnectNotify(const QMetaMethod &signal)
3666{
3667 Q_UNUSED(signal);
3668}
3669
3670/*
3671 \internal
3672 convert a signal index from the method range to the signal range
3673 */
3674static int methodIndexToSignalIndex(const QMetaObject **base, int signal_index)
3675{
3676 if (signal_index < 0)
3677 return signal_index;
3678 const QMetaObject *metaObject = *base;
3679 while (metaObject && metaObject->methodOffset() > signal_index)
3680 metaObject = metaObject->superClass();
3681
3682 if (metaObject) {
3683 int signalOffset, methodOffset;
3684 computeOffsets(metaObject, &signalOffset, &methodOffset);
3685 if (signal_index < metaObject->methodCount())
3686 signal_index = QMetaObjectPrivate::originalClone(metaObject, signal_index - methodOffset) + signalOffset;
3687 else
3688 signal_index = signal_index - methodOffset + signalOffset;
3689 *base = metaObject;
3690 }
3691 return signal_index;
3692}
3693
3694/*!
3695 \internal
3696 \a types is a 0-terminated vector of meta types for queued
3697 connections.
3698
3699 if \a signal_index is -1, then we effectively connect *all* signals
3700 from the sender to the receiver's slot
3701 */
3702QMetaObject::Connection QMetaObject::connect(const QObject *sender, int signal_index,
3703 const QObject *receiver, int method_index, int type,
3704 int *types)
3705{
3706 const QMetaObject *smeta = sender->metaObject();
3707 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3708 return Connection(QMetaObjectPrivate::connect(sender, signal_index, smeta,
3709 receiver, method_index,
3710 nullptr, //FIXME, we could speed this connection up by computing the relative index
3711 type, types));
3712}
3713
3714/*!
3715 \internal
3716 Same as the QMetaObject::connect, but \a signal_index must be the result of QObjectPrivate::signalIndex
3717
3718 method_index is relative to the rmeta metaobject, if rmeta is \nullptr, then it is absolute index
3719
3720 the QObjectPrivate::Connection* has a refcount of 2, so it must be passed to a QMetaObject::Connection
3721 */
3722QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender,
3723 int signal_index, const QMetaObject *smeta,
3724 const QObject *receiver, int method_index,
3725 const QMetaObject *rmeta, int type, int *types)
3726{
3727 QObject *s = const_cast<QObject *>(sender);
3728 QObject *r = const_cast<QObject *>(receiver);
3729
3730 int method_offset = rmeta ? rmeta->methodOffset() : 0;
3731 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 6);
3732 QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall : nullptr;
3733
3734 QOrderedMutexLocker locker(signalSlotLock(sender),
3735 signalSlotLock(receiver));
3736
3737 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3738 if (type & Qt::UniqueConnection && scd) {
3739 if (scd->signalVectorCount() > signal_index) {
3740 const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
3741
3742 int method_index_absolute = method_index + method_offset;
3743
3744 while (c2) {
3745 if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute)
3746 return nullptr;
3747 c2 = c2->nextConnectionList.loadRelaxed();
3748 }
3749 }
3750 }
3751 type &= ~Qt::UniqueConnection;
3752
3753 const bool isSingleShot = type & Qt::SingleShotConnection;
3754 type &= ~Qt::SingleShotConnection;
3755
3756 Q_ASSERT(type >= 0);
3757 Q_ASSERT(type <= 3);
3758
3759 std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
3760 c->sender = s;
3761 c->signal_index = signal_index;
3762 c->receiver.storeRelaxed(r);
3763 QThreadData *td = r->d_func()->threadData.loadAcquire();
3764 td->ref();
3765 c->receiverThreadData.storeRelaxed(td);
3766 c->method_relative = method_index;
3767 c->method_offset = method_offset;
3768 c->connectionType = type;
3769 c->isSlotObject = false;
3770 c->argumentTypes.storeRelaxed(types);
3771 c->callFunction = callFunction;
3772 c->isSingleShot = isSingleShot;
3773
3774 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
3775
3776 locker.unlock();
3777 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3778 if (smethod.isValid())
3779 s->connectNotify(smethod);
3780
3781 return c.release();
3782}
3783
3784/*!
3785 \internal
3786 */
3787bool QMetaObject::disconnect(const QObject *sender, int signal_index,
3788 const QObject *receiver, int method_index)
3789{
3790 const QMetaObject *smeta = sender->metaObject();
3791 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3792 return QMetaObjectPrivate::disconnect(sender, signal_index, smeta,
3793 receiver, method_index, nullptr);
3794}
3795
3796/*!
3797 \internal
3798
3799Disconnect a single signal connection. If QMetaObject::connect() has been called
3800multiple times for the same sender, signal_index, receiver and method_index only
3801one of these connections will be removed.
3802 */
3803bool QMetaObject::disconnectOne(const QObject *sender, int signal_index,
3804 const QObject *receiver, int method_index)
3805{
3806 const QMetaObject *smeta = sender->metaObject();
3807 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3808 return QMetaObjectPrivate::disconnect(sender, signal_index, smeta,
3809 receiver, method_index, nullptr,
3810 QMetaObjectPrivate::DisconnectOne);
3811}
3812
3813/*!
3814 \internal
3815 Helper function to remove the connection from the senders list and set the receivers to \nullptr
3816 */
3817bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::ConnectionData *connections, int signalIndex,
3818 const QObject *receiver, int method_index, void **slot,
3819 QBasicMutex *senderMutex, DisconnectType disconnectType)
3820{
3821 bool success = false;
3822
3823 auto &connectionList = connections->connectionsForSignal(signalIndex);
3824 auto *c = connectionList.first.loadRelaxed();
3825 while (c) {
3826 QObject *r = c->receiver.loadRelaxed();
3827 if (r && (receiver == nullptr || (r == receiver
3828 && (method_index < 0 || (!c->isSlotObject && c->method() == method_index))
3829 && (slot == nullptr || (c->isSlotObject && c->slotObj->compare(slot)))))) {
3830 bool needToUnlock = false;
3831 QBasicMutex *receiverMutex = nullptr;
3832 if (r) {
3833 receiverMutex = signalSlotLock(r);
3834 // need to relock this receiver and sender in the correct order
3835 needToUnlock = QOrderedMutexLocker::relock(senderMutex, receiverMutex);
3836 }
3837 if (c->receiver.loadRelaxed())
3838 connections->removeConnection(c);
3839
3840 if (needToUnlock)
3841 receiverMutex->unlock();
3842
3843 success = true;
3844
3845 if (disconnectType == DisconnectOne)
3846 return success;
3847 }
3848 c = c->nextConnectionList.loadRelaxed();
3849 }
3850 return success;
3851}
3852
3853/*!
3854 \internal
3855 Same as the QMetaObject::disconnect, but \a signal_index must be the result of QObjectPrivate::signalIndex
3856 */
3857bool QMetaObjectPrivate::disconnect(const QObject *sender,
3858 int signal_index, const QMetaObject *smeta,
3859 const QObject *receiver, int method_index, void **slot,
3860 DisconnectType disconnectType)
3861{
3862 if (!sender)
3863 return false;
3864
3865 QObject *s = const_cast<QObject *>(sender);
3866
3867 QBasicMutex *senderMutex = signalSlotLock(sender);
3868 QMutexLocker locker(senderMutex);
3869
3870 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3871 if (!scd)
3872 return false;
3873
3874 bool success = false;
3875 {
3876 // prevent incoming connections changing the connections->receivers while unlocked
3877 QObjectPrivate::ConnectionDataPointer connections(scd);
3878
3879 if (signal_index < 0) {
3880 // wildcard disconnect - warn if this disconnects destroyed()
3881 if (!receiver && method_index < 0 && sender->d_func()->isSignalConnected(0)) {
3882 qWarning("QObject::disconnect: wildcard call disconnects from destroyed signal of"
3883 " %s::%s", sender->metaObject()->className(),
3884 sender->objectName().isEmpty()
3885 ? "unnamed"
3886 : sender->objectName().toLocal8Bit().data());
3887 }
3888 // remove from all connection lists
3889 for (int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
3890 if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
3891 success = true;
3892 }
3893 } else if (signal_index < scd->signalVectorCount()) {
3894 if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
3895 success = true;
3896 }
3897 }
3898
3899 locker.unlock();
3900 if (success) {
3901 scd->cleanOrphanedConnections(s);
3902
3903 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3904 if (smethod.isValid())
3905 s->disconnectNotify(smethod);
3906 }
3907
3908 return success;
3909}
3910
3911// Helpers for formatting the connect statements of connectSlotsByName()'s debug mode
3912static QByteArray formatConnectionSignature(const char *className, const QMetaMethod &method)
3913{
3914 const auto signature = method.methodSignature();
3915 Q_ASSERT(signature.endsWith(')'));
3916 const qsizetype openParen = signature.indexOf('(');
3917 const bool hasParameters = openParen > 0 && openParen < signature.size() - 2;
3918 QByteArray result;
3919 if (hasParameters) {
3920 const qsizetype len = signature.size() - openParen - 2;
3921 result += "qOverload<" + QByteArrayView{signature}.slice(openParen + 1, len) + ">(";
3922 }
3923 result += '&';
3924 result += className + QByteArrayLiteral("::") + method.name();
3925 if (hasParameters)
3926 result += ')';
3927 return result;
3928}
3929
3930static QByteArray msgConnect(const QMetaObject *senderMo, const QByteArray &senderName,
3931 const QMetaMethod &signal, const QObject *receiver, int receiverIndex)
3932{
3933 const auto receiverMo = receiver->metaObject();
3934 const auto slot = receiverMo->method(receiverIndex);
3935 QByteArray message = QByteArrayLiteral("QObject::connect(")
3936 + senderName + ", " + formatConnectionSignature(senderMo->className(), signal)
3937 + ", " + receiver->objectName().toLatin1() + ", "
3938 + formatConnectionSignature(receiverMo->className(), slot) + ");";
3939 return message;
3940}
3941
3942/*!
3943 \fn void QMetaObject::connectSlotsByName(QObject *object)
3944
3945 Searches recursively for all child objects of the given \a object, and connects
3946 matching signals from them to slots of \a object that follow the following form:
3947
3948 \snippet code/src_corelib_kernel_qobject.cpp 33
3949
3950 Let's assume our object has a child object of type \c{QPushButton} with
3951 the \l{QObject::objectName}{object name} \c{button1}. The slot to catch the
3952 button's \c{clicked()} signal would be:
3953
3954 \snippet code/src_corelib_kernel_qobject.cpp 34
3955
3956 If \a object itself has a properly set object name, its own signals are also
3957 connected to its respective slots.
3958
3959 \sa QObject::setObjectName()
3960 */
3961void QMetaObject::connectSlotsByName(QObject *o)
3962{
3963 if (!o)
3964 return;
3965 const QMetaObject *mo = o->metaObject();
3966 Q_ASSERT(mo);
3967 const QObjectList list = // list of all objects to look for matching signals including...
3968 o->findChildren<QObject *>() // all children of 'o'...
3969 << o; // and the object 'o' itself
3970
3971 // for each method/slot of o ...
3972 for (int i = 0; i < mo->methodCount(); ++i) {
3973 const QByteArray slotSignature = mo->method(i).methodSignature();
3974 const char *slot = slotSignature.constData();
3975 Q_ASSERT(slot);
3976
3977 // ...that starts with "on_", ...
3978 if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
3979 continue;
3980
3981 // ...we check each object in our list, ...
3982 bool foundIt = false;
3983 for (int j = 0; j < list.size(); ++j) {
3984 const QObject *co = list.at(j);
3985 const QByteArray coName = co->objectName().toLatin1();
3986
3987 // ...discarding those whose objectName is not fitting the pattern "on_<objectName>_...", ...
3988 if (coName.isEmpty() || qstrncmp(slot + 3, coName.constData(), coName.size()) || slot[coName.size()+3] != '_')
3989 continue;
3990
3991 const char *signal = slot + coName.size() + 4; // the 'signal' part of the slot name
3992
3993 // ...for the presence of a matching signal "on_<objectName>_<signal>".
3994 const QMetaObject *smeta;
3995 int sigIndex = co->d_func()->signalIndex(signal, &smeta);
3996 if (sigIndex < 0) {
3997 // if no exactly fitting signal (name + complete parameter type list) could be found
3998 // look for just any signal with the correct name and at least the slot's parameter list.
3999 // Note: if more than one of those signals exist, the one that gets connected is
4000 // chosen 'at random' (order of declaration in source file)
4001 QList<QByteArray> compatibleSignals;
4002 const QMetaObject *smo = co->metaObject();
4003 int sigLen = int(qstrlen(signal)) - 1; // ignore the trailing ')'
4004 for (int k = QMetaObjectPrivate::absoluteSignalCount(smo)-1; k >= 0; --k) {
4005 const QMetaMethod method = QMetaObjectPrivate::signal(smo, k);
4006 if (!qstrncmp(method.methodSignature().constData(), signal, sigLen)) {
4007 smeta = method.enclosingMetaObject();
4008 sigIndex = k;
4009 compatibleSignals.prepend(method.methodSignature());
4010 }
4011 }
4012 if (compatibleSignals.size() > 1)
4013 qCWarning(lcConnectSlotsByName) << "QMetaObject::connectSlotsByName: Connecting slot" << slot
4014 << "with the first of the following compatible signals:" << compatibleSignals;
4015 }
4016
4017 if (sigIndex < 0)
4018 continue;
4019
4020 // we connect it...
4021 if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) {
4022 foundIt = true;
4023 qCDebug(lcConnectSlotsByName, "%s",
4024 msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData());
4025 // ...and stop looking for further objects with the same name.
4026 // Note: the Designer will make sure each object name is unique in the above
4027 // 'list' but other code may create two child objects with the same name. In
4028 // this case one is chosen 'at random'.
4029 break;
4030 }
4031 }
4032 if (foundIt) {
4033 // we found our slot, now skip all overloads
4034 while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
4035 ++i;
4036 } else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
4037 // check if the slot has the following signature: "on_..._...(..."
4038 qsizetype iParen = slotSignature.indexOf('(');
4039 qsizetype iLastUnderscore = slotSignature.lastIndexOf('_', iParen - 1);
4040 if (iLastUnderscore > 3)
4041 qCWarning(lcConnectSlotsByName,
4042 "QMetaObject::connectSlotsByName: No matching signal for %s", slot);
4043 }
4044 }
4045}
4046
4047/*!
4048 \fn template<typename PointerToMemberFunction> QMetaObject::Connection QMetaObject::connect(
4049 const QObject *sender, const QMetaMethod &signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type)
4050
4051 \threadsafe
4052 \overload connect()
4053
4054 \since 6.10
4055
4056 Creates a connection of the given \a type from the \a signal in
4057 the \a sender object to the \a method in the \a receiver object.
4058 Returns a handle to the connection that can be used to disconnect
4059 it later.
4060
4061 The Connection handle will be invalid if it cannot create the
4062 connection, for example, the parameters were invalid.
4063 You can check if the QMetaObject::Connection is valid by casting
4064 it to a bool.
4065 Pass the returned handle to QObject::disconnect() to disconnect
4066 the connection.
4067
4068 A slot can be connected to a given signal if the signal has at
4069 least as many arguments as the slot. There must be an exact match
4070 between the corresponding signal and slot arguments, implicit
4071 conversions and type checking are not handled by this function.
4072 Overloaded slots need to be explicitly be resolved with
4073 help of \l qOverload.
4074 \a signal needs to be the meta-method of a signal, otherwise an
4075 invalid connection will be returned.
4076
4077 \sa QObject::connect(), QObject::disconnect()
4078 */
4079
4080/*!
4081 \fn template<typename Functor> QMetaObject::Connection QMetaObject::connect(
4082 const QObject *sender, const QMetaMethod &signal, const QObject *context, Functor functor, Qt::ConnectionType type)
4083
4084 \threadsafe
4085 \overload connect()
4086
4087 \since 6.10
4088
4089 Creates a connection of a given \a type from \a signal in
4090 \a sender object to \a functor to be placed in a specific event
4091 loop of \a context.
4092 Returns a handle to the connection that can be used to disconnect
4093 it later.
4094 This can be useful for connecting a signal retrieved from
4095 meta-object introspection to a lambda capturing local variables.
4096
4097 \note Qt::UniqueConnections do not work for lambdas, non-member
4098 functions and functors; they only apply to member functions.
4099
4100 The slot function can be any function or functor with with equal
4101 or fewer arguments than the signal. There must be an exact match
4102 between the corresponding signal and slot arguments, implicit
4103 conversions and type checking are not handled by this function.
4104 Overloaded functors need to be explicitly be resolved with
4105 help of \l qOverload.
4106 \a signal needs to be the meta-method of a signal, otherwise an
4107 invalid connection will be returned.
4108
4109 The connection will automatically disconnect if the sender or
4110 the context is destroyed.
4111 However, you should take care that any objects used within
4112 the functor are still alive when the signal is emitted.
4113
4114 \sa QObject::connect(), QObject::disconnect()
4115 */
4116QMetaObject::Connection QMetaObject::connectImpl(const QObject *sender, const QMetaMethod &signal,
4117 const QObject *receiver, void **slot,
4118 QtPrivate::QSlotObjectBase *slotObjRaw, Qt::ConnectionType type)
4119{
4120 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
4121
4122 const QMetaObject *senderMetaObject = sender->metaObject();
4123 if (!signal.isValid() || signal.methodType() != QMetaMethod::Signal) {
4124 connectWarning(sender, senderMetaObject, receiver, "invalid signal parameter");
4125 return QMetaObject::Connection();
4126 }
4127
4128 int signal_index;
4129 {
4130 int dummy;
4131 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
4132 }
4133
4134 if (signal_index == -1) {
4135 qCWarning(lcConnect, "QObject::connect: Can't find signal %s on instance of class %s",
4136 signal.methodSignature().constData(), senderMetaObject->className());
4137 return QMetaObject::Connection();
4138 }
4139
4140 return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj.release(), type, nullptr, senderMetaObject);
4141}
4142
4143/*!
4144 \internal
4145 A small RAII helper for QSlotObjectBase.
4146 Calls ref on construction and destroyLastRef in its dtor.
4147 Allows construction from a nullptr in which case it does nothing.
4148 */
4150 SlotObjectGuard() = default;
4151 // move would be fine, but we do not need it currently
4159
4161 { return m_slotObject.get(); }
4162
4165
4166 ~SlotObjectGuard() = default;
4167private:
4168 QtPrivate::SlotObjUniquePtr m_slotObject;
4169};
4170
4171/*!
4172 \internal
4173
4174 \a signal must be in the signal index range (see QObjectPrivate::signalIndex()).
4175*/
4176static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv)
4177{
4178 const int *argumentTypes = c->argumentTypes.loadRelaxed();
4179 if (!argumentTypes) {
4180 QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
4181 argumentTypes = queuedConnectionTypes(m);
4182 if (!argumentTypes) // cannot queue arguments
4183 argumentTypes = &DIRECT_CONNECTION_ONLY;
4184 if (!c->argumentTypes.testAndSetOrdered(nullptr, argumentTypes)) {
4185 if (argumentTypes != &DIRECT_CONNECTION_ONLY)
4186 delete[] argumentTypes;
4187 argumentTypes = c->argumentTypes.loadRelaxed();
4188 }
4189 }
4190 if (argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate
4191 return;
4192 int nargs = 1; // include return type
4193 while (argumentTypes[nargs - 1])
4194 ++nargs;
4195
4196 QMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
4197 QObject *receiver = c->receiver.loadRelaxed();
4198 if (!receiver) {
4199 // the connection has been disconnected before we got the lock
4200 return;
4201 }
4202
4203 SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj : nullptr };
4204 locker.unlock();
4205
4206 QVarLengthArray<const QtPrivate::QMetaTypeInterface *, 16> argTypes;
4207 argTypes.reserve(nargs);
4208 argTypes.emplace_back(nullptr); // return type
4209 for (int n = 1; n < nargs; ++n) {
4210 argTypes.emplace_back(QMetaType(argumentTypes[n - 1]).iface()); // convert type ids to QMetaTypeInterfaces
4211 }
4212
4213 auto ev = c->isSlotObject ?
4214 std::make_unique<QQueuedMetaCallEvent>(c->slotObj,
4215 sender, signal, nargs, argTypes.data(), argv) :
4216 std::make_unique<QQueuedMetaCallEvent>(c->method_offset, c->method_relative, c->callFunction,
4217 sender, signal, nargs, argTypes.data(), argv);
4218
4219 if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) {
4220 return;
4221 }
4222
4223 locker.relock();
4224 if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
4225 // the connection has been disconnected while we were unlocked
4226 locker.unlock();
4227 return;
4228 }
4229
4230 QCoreApplication::postEvent(receiver, ev.release());
4231}
4232
4233template <bool callbacks_enabled>
4234void doActivate(QObject *sender, int signal_index, void **argv)
4235{
4236 QObjectPrivate *sp = QObjectPrivate::get(sender);
4237
4238 if (sp->blockSig)
4239 return;
4240
4241 Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
4242
4243 if (sp->isDeclarativeSignalConnected(signal_index)
4244 && QAbstractDeclarativeData::signalEmitted) {
4245 Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
4246 QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
4247 signal_index, argv);
4248 }
4249
4250 const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() : nullptr;
4251
4252 void *empty_argv[] = { nullptr };
4253 if (!argv)
4254 argv = empty_argv;
4255
4256 if (!sp->maybeSignalConnected(signal_index)) {
4257 // The possible declarative connection is done, and nothing else is connected
4258 if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
4259 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4260 if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
4261 signal_spy_set->signal_end_callback(sender, signal_index);
4262 return;
4263 }
4264
4265 if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
4266 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4267
4268 bool senderDeleted = false;
4269 {
4270 Q_ASSERT(sp->connections.loadRelaxed());
4271 QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadAcquire());
4272 QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();
4273
4274 const QObjectPrivate::ConnectionList *list;
4275 if (signal_index < signalVector->count())
4276 list = &signalVector->at(signal_index);
4277 else
4278 list = &signalVector->at(-1);
4279
4280 Qt::HANDLE currentThreadId = QThread::currentThreadId();
4281 bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
4282
4283 // We need to check against the highest connection id to ensure that signals added
4284 // during the signal emission are not emitted in this emission.
4285 uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
4286 do {
4287 QObjectPrivate::Connection *c = list->first.loadRelaxed();
4288 if (!c)
4289 continue;
4290
4291 do {
4292 QObject * const receiver = c->receiver.loadRelaxed();
4293 if (!receiver)
4294 continue;
4295
4296 QThreadData *td = c->receiverThreadData.loadRelaxed();
4297 if (!td)
4298 continue;
4299
4300 bool receiverInSameThread;
4301 if (inSenderThread) {
4302 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4303 } else {
4304 // need to lock before reading the threadId, because moveToThread() could interfere
4305 QMutexLocker lock(signalSlotLock(receiver));
4306 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4307 }
4308
4309
4310 // determine if this connection should be sent immediately or
4311 // put into the event queue
4312 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
4313 || (c->connectionType == Qt::QueuedConnection)) {
4314 queued_activate(sender, signal_index, c, argv);
4315 continue;
4316#if QT_CONFIG(thread)
4317 } else if (c->connectionType == Qt::BlockingQueuedConnection) {
4318 if (receiverInSameThread) {
4319 qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
4320 "Sender is %s(%p), receiver is %s(%p)",
4321 sender->metaObject()->className(), sender,
4322 receiver->metaObject()->className(), receiver);
4323 }
4324
4325 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4326 continue;
4327
4328 QLatch latch(1);
4329 {
4330 QMutexLocker locker(signalSlotLock(receiver));
4331 if (!c->isSingleShot && !c->receiver.loadAcquire())
4332 continue;
4333 QMetaCallEvent *ev = c->isSlotObject ?
4334 new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &latch) :
4335 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
4336 sender, signal_index, argv, &latch);
4337 QCoreApplication::postEvent(receiver, ev);
4338 }
4339 latch.wait();
4340 continue;
4341#endif
4342 }
4343
4344 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4345 continue;
4346
4347 QObjectPrivate::Sender senderData(
4348 receiverInSameThread ? receiver : nullptr, sender, signal_index,
4349 receiverInSameThread ? QObjectPrivate::get(receiver)->connections.loadAcquire() : nullptr);
4350
4351 if (c->isSlotObject) {
4352 SlotObjectGuard obj{c->slotObj};
4353
4354 {
4355 Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
4356 obj->call(receiver, argv);
4357 }
4358 } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
4359 //we compare the vtable to make sure we are not in the destructor of the object.
4360 const int method_relative = c->method_relative;
4361 const auto callFunction = c->callFunction;
4362 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
4363 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)
4364 signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
4365
4366 {
4367 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
4368 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
4369 }
4370
4371 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
4372 signal_spy_set->slot_end_callback(receiver, methodIndex);
4373 } else {
4374 const int method = c->method_relative + c->method_offset;
4375
4376 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {
4377 signal_spy_set->slot_begin_callback(receiver, method, argv);
4378 }
4379
4380 {
4381 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
4382 QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
4383 }
4384
4385 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
4386 signal_spy_set->slot_end_callback(receiver, method);
4387 }
4388 } while ((c = c->nextConnectionList.loadRelaxed()) != nullptr && c->id <= highestConnectionId);
4389
4390 } while (list != &signalVector->at(-1) &&
4391 //start over for all signals;
4392 ((list = &signalVector->at(-1)), true));
4393
4394 if (connections->currentConnectionId.loadRelaxed() == 0)
4395 senderDeleted = true;
4396 }
4397 if (!senderDeleted) {
4398 sp->connections.loadAcquire()->cleanOrphanedConnections(sender);
4399
4400 if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
4401 signal_spy_set->signal_end_callback(sender, signal_index);
4402 }
4403}
4404
4405/*!
4406 \internal
4407 */
4408void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
4409 void **argv)
4410{
4411 int signal_index = local_signal_index + QMetaObjectPrivate::signalOffset(m);
4412
4413 if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
4414 doActivate<true>(sender, signal_index, argv);
4415 else
4416 doActivate<false>(sender, signal_index, argv);
4417}
4418
4419/*!
4420 \internal
4421 */
4422void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
4423{
4424 int signal_index = signalOffset + local_signal_index;
4425
4426 if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
4427 doActivate<true>(sender, signal_index, argv);
4428 else
4429 doActivate<false>(sender, signal_index, argv);
4430}
4431
4432/*!
4433 \internal
4434 signal_index comes from indexOfMethod()
4435*/
4436void QMetaObject::activate(QObject *sender, int signal_index, void **argv)
4437{
4438 const QMetaObject *mo = sender->metaObject();
4439 while (mo->methodOffset() > signal_index)
4440 mo = mo->superClass();
4441 activate(sender, mo, signal_index - mo->methodOffset(), argv);
4442}
4443
4444/*!
4445 \internal
4446 Returns the signal index used in the internal connections->receivers vector.
4447
4448 It is different from QMetaObject::indexOfSignal(): indexOfSignal is the same as indexOfMethod
4449 while QObjectPrivate::signalIndex is smaller because it doesn't give index to slots.
4450
4451 If \a meta is not \nullptr, it is set to the meta-object where the signal was found.
4452*/
4453int QObjectPrivate::signalIndex(const char *signalName,
4454 const QMetaObject **meta) const
4455{
4456 Q_Q(const QObject);
4457 const QMetaObject *base = q->metaObject();
4458 Q_ASSERT(QMetaObjectPrivate::get(base)->revision >= 7);
4459 QArgumentTypeArray types;
4460 QByteArrayView name = QMetaObjectPrivate::decodeMethodSignature(signalName, types);
4461 int relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, name, types);
4462 if (relative_index < 0)
4463 return relative_index;
4464 relative_index = QMetaObjectPrivate::originalClone(base, relative_index);
4465 if (meta)
4466 *meta = base;
4467 return relative_index + QMetaObjectPrivate::signalOffset(base);
4468}
4469
4470/*****************************************************************************
4471 Properties
4472 *****************************************************************************/
4473
4474/*!
4475 \fn bool QObject::setProperty(const char *name, const QVariant &value)
4476
4477 Sets the value of the object's \a name property to \a value.
4478
4479 If the property is defined in the class using Q_PROPERTY then
4480 true is returned on success and false otherwise. If the property
4481 is not defined using Q_PROPERTY, and therefore not listed in the
4482 meta-object, it is added as a dynamic property and false is returned.
4483
4484 Information about all available properties is provided through the
4485 metaObject() and dynamicPropertyNames().
4486
4487 Dynamic properties can be queried again using property() and can be
4488 removed by setting the property value to an invalid QVariant.
4489 Changing the value of a dynamic property causes a QDynamicPropertyChangeEvent
4490 to be sent to the object.
4491
4492 \b{Note:} Dynamic properties starting with "_q_" are reserved for internal
4493 purposes.
4494
4495 \sa property(), metaObject(), dynamicPropertyNames(), QMetaProperty::write()
4496*/
4497
4498/*!
4499 \fn bool QObject::setProperty(const char *name, QVariant &&value)
4500 \since 6.6
4501 \overload setProperty
4502*/
4503
4504bool QObject::doSetProperty(const char *name, const QVariant &value, QVariant *rvalue)
4505{
4506 Q_D(QObject);
4507 const QMetaObject *meta = metaObject();
4508 if (!name || !meta)
4509 return false;
4510
4511 int id = meta->indexOfProperty(name);
4512 if (id < 0) {
4513 d->ensureExtraData();
4514
4515 const qsizetype idx = d->extraData->propertyNames.indexOf(name);
4516
4517 if (!value.isValid()) {
4518 if (idx == -1)
4519 return false;
4520 d->extraData->propertyNames.removeAt(idx);
4521 d->extraData->propertyValues.removeAt(idx);
4522 } else {
4523 if (idx == -1) {
4524 d->extraData->propertyNames.append(name);
4525 q_choose_append(d->extraData->propertyValues, value, rvalue);
4526 } else {
4527 if (value.userType() == d->extraData->propertyValues.at(idx).userType()
4528 && value == d->extraData->propertyValues.at(idx))
4529 return false;
4530 q_choose_assign(d->extraData->propertyValues[idx], value, rvalue);
4531 }
4532 }
4533
4534 QDynamicPropertyChangeEvent ev(name);
4535 QCoreApplication::sendEvent(this, &ev);
4536
4537 return false;
4538 }
4539 QMetaProperty p = meta->property(id);
4540#ifndef QT_NO_DEBUG
4541 if (!p.isWritable())
4542 qWarning("%s::setProperty: Property \"%s\" invalid,"
4543 " read-only or does not exist", metaObject()->className(), name);
4544#endif
4545 return rvalue ? p.write(this, std::move(*rvalue)) : p.write(this, value);
4546}
4547
4548/*!
4549 Returns the value of the object's \a name property.
4550
4551 If no such property exists, the returned variant is invalid.
4552
4553 Information about all available properties is provided through the
4554 metaObject() and dynamicPropertyNames().
4555
4556 \sa setProperty(), QVariant::isValid(), metaObject(), dynamicPropertyNames()
4557*/
4558QVariant QObject::property(const char *name) const
4559{
4560 Q_D(const QObject);
4561 const QMetaObject *meta = metaObject();
4562 if (!name || !meta)
4563 return QVariant();
4564
4565 int id = meta->indexOfProperty(name);
4566 if (id < 0) {
4567 if (!d->extraData)
4568 return QVariant();
4569 const qsizetype i = d->extraData->propertyNames.indexOf(name);
4570 return d->extraData->propertyValues.value(i);
4571 }
4572 QMetaProperty p = meta->property(id);
4573#ifndef QT_NO_DEBUG
4574 if (!p.isReadable())
4575 qWarning("%s::property: Property \"%s\" invalid or does not exist",
4576 metaObject()->className(), name);
4577#endif
4578 return p.read(this);
4579}
4580
4581/*!
4582 \since 4.2
4583
4584 Returns the names of all properties that were dynamically added to
4585 the object using setProperty().
4586*/
4587QList<QByteArray> QObject::dynamicPropertyNames() const
4588{
4589 Q_D(const QObject);
4590 if (d->extraData)
4591 return d->extraData->propertyNames;
4592 return QList<QByteArray>();
4593}
4594
4595/*****************************************************************************
4596 QObject debugging output routines.
4597 *****************************************************************************/
4598
4599std::string QObjectPrivate::flagsForDumping() const
4600{
4601 return {};
4602}
4603
4604static void dumpRecursive(int level, const QObject *object)
4605{
4606 if (object) {
4607 const int indent = level * 4;
4608 qDebug("%*s%s::%ls %s", indent, "", object->metaObject()->className(),
4609 qUtf16Printable(object->objectName()),
4610 QObjectPrivate::get(object)->flagsForDumping().c_str());
4611 for (auto child : object->children())
4612 dumpRecursive(level + 1, child);
4613 }
4614}
4615
4616
4617/*!
4618 Dumps a tree of children to the debug output.
4619
4620 \note Before Qt 5.9, this function was not const.
4621
4622 \sa dumpObjectInfo()
4623*/
4624
4625void QObject::dumpObjectTree() const
4626{
4627 dumpRecursive(0, this);
4628}
4629
4630/*!
4631 Dumps information about signal connections, etc. for this object
4632 to the debug output.
4633
4634 \note Before Qt 5.9, this function was not const.
4635
4636 \sa dumpObjectTree()
4637*/
4638
4639void QObject::dumpObjectInfo() const
4640{
4641 qDebug("OBJECT %s::%s", metaObject()->className(),
4642 objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
4643
4644 Q_D(const QObject);
4645 QMutexLocker locker(signalSlotLock(this));
4646
4647 // first, look for connections where this object is the sender
4648 qDebug(" SIGNALS OUT");
4649
4650 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
4651 if (cd && cd->signalVectorCount() > 0) {
4652 QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
4653 for (int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
4654 const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
4655 if (!c)
4656 continue;
4657 const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index);
4658 qDebug(" signal: %s", signal.methodSignature().constData());
4659
4660 // receivers
4661 while (c) {
4662 if (!c->receiver.loadRelaxed()) {
4663 qDebug(" <Disconnected receiver>");
4664 c = c->nextConnectionList.loadRelaxed();
4665 continue;
4666 }
4667 if (c->isSlotObject) {
4668 qDebug(" <functor or function pointer>");
4669 c = c->nextConnectionList.loadRelaxed();
4670 continue;
4671 }
4672 const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
4673 const QMetaMethod method = receiverMetaObject->method(c->method());
4674 qDebug(" --> %s::%s %s",
4675 receiverMetaObject->className(),
4676 c->receiver.loadRelaxed()->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
4677 method.methodSignature().constData());
4678 c = c->nextConnectionList.loadRelaxed();
4679 }
4680 }
4681 } else {
4682 qDebug( " <None>" );
4683 }
4684
4685 // now look for connections where this object is the receiver
4686 qDebug(" SIGNALS IN");
4687
4688 if (cd && cd->senders) {
4689 for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
4690 QByteArray slotName = QByteArrayLiteral("<unknown>");
4691 if (!s->isSlotObject) {
4692 const QMetaMethod slot = metaObject()->method(s->method());
4693 slotName = slot.methodSignature();
4694 }
4695 qDebug(" <-- %s::%s %s",
4696 s->sender->metaObject()->className(),
4697 s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()),
4698 slotName.constData());
4699 }
4700 } else {
4701 qDebug(" <None>");
4702 }
4703}
4704
4705
4706#ifndef QT_NO_DEBUG_STREAM
4707void QObjectPrivate::writeToDebugStream(QDebug &dbg) const
4708{
4709 Q_Q(const QObject);
4710 dbg.nospace() << q->metaObject()->className() << '(' << (const void *)q;
4711 if (!q->objectName().isEmpty())
4712 dbg << ", name = " << q->objectName();
4713 dbg << ')';
4714}
4715
4716QDebug operator<<(QDebug dbg, const QObject *o)
4717{
4718 QDebugStateSaver saver(dbg);
4719 if (!o)
4720 return dbg << "QObject(0x0)";
4721
4722 const QObjectPrivate *d = QObjectPrivate::get(o);
4723 d->writeToDebugStream(dbg);
4724 return dbg;
4725}
4726#endif
4727
4728/*!
4729 \macro Q_CLASSINFO(Name, Value)
4730 \relates QObject
4731
4732 This macro associates extra information to the class, which is available
4733 using QObject::metaObject(). The extra information takes the form of a
4734 \a Name string and a \a Value literal string.
4735
4736 Example:
4737
4738 \snippet code/src_corelib_kernel_qobject.cpp 35
4739
4740 Qt makes use of the macro in \l{Qt D-Bus} and \l{Qt Qml} modules.
4741 For instance, when defining \l{QML Object Types} in C++, you can
4742 designate a property as the \e default one:
4743
4744 \snippet code/doc_src_properties.cpp 7
4745
4746 \sa QMetaObject::classInfo()
4747 \sa {Using Qt D-Bus Adaptors}
4748 \sa {Defining QML Types from C++}
4749*/
4750
4751/*!
4752 \macro Q_INTERFACES(...)
4753 \relates QObject
4754
4755 This macro tells Qt which interfaces the class implements. This
4756 is used when implementing plugins.
4757
4758 \sa Q_DECLARE_INTERFACE(), Q_PLUGIN_METADATA(), {How to Create Qt Plugins}
4759*/
4760
4761/*!
4762 \macro Q_PROPERTY(...)
4763 \relates QObject
4764
4765 This macro is used for declaring properties in classes that
4766 inherit QObject. Properties behave like class data members, but
4767 they have additional features accessible through the \l
4768 {Meta-Object System}.
4769
4770 \snippet code/doc_src_properties.cpp 0
4771
4772 The property name and type and the \c READ function are required.
4773 The type can be any type supported by QVariant, or it can be a
4774 user-defined type. The other items are optional, but a \c WRITE
4775 function is common. The attributes default to true except \c USER,
4776 which defaults to false.
4777
4778 For example:
4779
4780 \snippet code/src_corelib_kernel_qobject.cpp 37
4781
4782 For more details about how to use this macro, and a more detailed
4783 example of its use, see the discussion on \l {Qt's Property System}.
4784
4785 \sa {Qt's Property System}
4786*/
4787
4788/*!
4789 \macro Q_ENUMS(...)
4790 \relates QObject
4791 \deprecated
4792
4793 In new code, you should prefer the use of the Q_ENUM() macro, which makes the
4794 type available also to the meta type system.
4795 For instance, QMetaEnum::fromType() will not work with types declared with Q_ENUMS().
4796
4797 This macro registers one or several enum types to the meta-object
4798 system.
4799
4800 If you want to register an enum that is declared in another class,
4801 the enum must be fully qualified with the name of the class
4802 defining it. In addition, the class \e defining the enum has to
4803 inherit QObject as well as declare the enum using Q_ENUMS().
4804
4805 \sa {Qt's Property System}
4806*/
4807
4808/*!
4809 \macro Q_FLAGS(...)
4810 \relates QObject
4811 \deprecated
4812
4813 This macro registers one or several \l{QFlags}{flags types} with the
4814 meta-object system. It is typically used in a class definition to declare
4815 that values of a given enum can be used as flags and combined using the
4816 bitwise OR operator.
4817
4818 \note This macro takes care of registering individual flag values
4819 with the meta-object system, so it is unnecessary to use Q_ENUMS()
4820 in addition to this macro.
4821
4822 In new code, you should prefer the use of the Q_FLAG() macro, which makes the
4823 type available also to the meta type system.
4824
4825 \sa {Qt's Property System}
4826*/
4827
4828/*!
4829 \macro Q_ENUM(...)
4830 \relates QObject
4831 \since 5.5
4832
4833 This macro registers an enum type with the meta-object system.
4834 It must be placed after the enum declaration in a class that has the Q_OBJECT,
4835 Q_GADGET or Q_GADGET_EXPORT macro. For namespaces use \l Q_ENUM_NS() instead.
4836
4837 For example:
4838
4839 \snippet code/src_corelib_kernel_qobject.cpp 38
4840
4841 Enumerations that are declared with Q_ENUM have their QMetaEnum registered in the
4842 enclosing QMetaObject. You can also use QMetaEnum::fromType() to get the QMetaEnum.
4843
4844 Registered enumerations are automatically registered also to the Qt meta
4845 type system, making them known to QMetaType without the need to use
4846 Q_DECLARE_METATYPE(). This will enable useful features; for example, if used
4847 in a QVariant, you can convert them to strings. Likewise, passing them to
4848 QDebug will print out their names.
4849
4850 Mind that the enum values are stored as signed \c int in the meta object system.
4851 Registering enumerations with values outside the range of values valid for \c int
4852 will lead to overflows and potentially undefined behavior when accessing them through
4853 the meta object system. QML, for example, does access registered enumerations through
4854 the meta object system.
4855
4856 \sa {Qt's Property System}
4857*/
4858
4859
4860/*!
4861 \macro Q_FLAG(...)
4862 \relates QObject
4863 \since 5.5
4864
4865 This macro registers a single \l{QFlags}{flags type} with the
4866 meta-object system. It is typically used in a class definition to declare
4867 that values of a given enum can be used as flags and combined using the
4868 bitwise OR operator. For namespaces use \l Q_FLAG_NS() instead.
4869
4870 The macro must be placed after the enum declaration. The declaration of
4871 the flags type is done using the \l Q_DECLARE_FLAGS() macro.
4872
4873 For example, in QItemSelectionModel, the
4874 \l{QItemSelectionModel::SelectionFlags}{SelectionFlags} flag is
4875 declared in the following way:
4876
4877 \quotefromfile itemmodels/qitemselectionmodel.h
4878
4879 \skipto class Q_CORE_EXPORT QItemSelectionModel
4880 \printuntil Q_OBJECT
4881
4882 \dots
4883
4884 \skipto public:
4885 \printuntil Q_FLAG(SelectionFlags)
4886
4887 \skipuntil Q_DISABLE_COPY
4888 \printto Q_DECLARE_OPERATORS_FOR_FLAGS
4889
4890 \note The Q_FLAG macro takes care of registering individual flag values
4891 with the meta-object system, so it is unnecessary to use Q_ENUM()
4892 in addition to this macro.
4893
4894 \sa {Qt's Property System}
4895*/
4896
4897/*!
4898 \macro Q_ENUM_NS(...)
4899 \relates QObject
4900 \since 5.8
4901
4902 This macro registers an enum type with the meta-object system.
4903 It must be placed after the enum declaration in a namespace that
4904 has the Q_NAMESPACE macro. It is the same as \l Q_ENUM but in a
4905 namespace.
4906
4907 Enumerations that are declared with Q_ENUM_NS have their QMetaEnum
4908 registered in the enclosing QMetaObject. You can also use
4909 QMetaEnum::fromType() to get the QMetaEnum.
4910
4911 Registered enumerations are automatically registered also to the Qt meta
4912 type system, making them known to QMetaType without the need to use
4913 Q_DECLARE_METATYPE(). This will enable useful features; for example, if
4914 used in a QVariant, you can convert them to strings. Likewise, passing them
4915 to QDebug will print out their names.
4916
4917 Mind that the enum values are stored as signed \c int in the meta object system.
4918 Registering enumerations with values outside the range of values valid for \c int
4919 will lead to overflows and potentially undefined behavior when accessing them through
4920 the meta object system. QML, for example, does access registered enumerations through
4921 the meta object system.
4922
4923 \sa {Qt's Property System}
4924*/
4925
4926
4927/*!
4928 \macro Q_FLAG_NS(...)
4929 \relates QObject
4930 \since 5.8
4931
4932 This macro registers a single \l{QFlags}{flags type} with the
4933 meta-object system. It is used in a namespace that has the
4934 Q_NAMESPACE macro, to declare that values of a given enum can be
4935 used as flags and combined using the bitwise OR operator.
4936 It is the same as \l Q_FLAG but in a namespace.
4937
4938 The macro must be placed after the enum declaration.
4939
4940 \note The Q_FLAG_NS macro takes care of registering individual flag
4941 values with the meta-object system, so it is unnecessary to use
4942 Q_ENUM_NS() in addition to this macro.
4943
4944 \sa {Qt's Property System}
4945*/
4946
4947/*!
4948 \macro Q_OBJECT
4949 \relates QObject
4950
4951 The Q_OBJECT macro is used to enable meta-object features, such as dynamic
4952 properties, signals, and slots.
4953
4954 You can add the Q_OBJECT macro to any section of a class definition that
4955 declares its own signals and slots or that uses other services provided by
4956 Qt's meta-object system.
4957
4958//! [qobject-macros-private-access-specifier]
4959 \note This macro expansion ends with a \c private: access specifier. If you
4960 declare members immediately after this macro, those members will also be
4961 private. To add public (or protected) members right after the macro, use a
4962 \c {public:} (or \c {protected:}) access specifier.
4963//! [qobject-macros-private-access-specifier]
4964
4965 Example:
4966
4967 \snippet signalsandslots/signalsandslots.h 1
4968 \codeline
4969 \snippet signalsandslots/signalsandslots.h 2
4970 \snippet signalsandslots/signalsandslots.h 3
4971
4972 \note This macro requires the class to be a subclass of QObject. Use
4973 Q_GADGET or Q_GADGET_EXPORT instead of Q_OBJECT to enable the meta object
4974 system's support for enums in a class that is not a QObject subclass.
4975
4976 \sa {Meta-Object System}, {Signals and Slots}, {Qt's Property System}
4977*/
4978
4979/*!
4980 \macro Q_GADGET
4981 \relates QObject
4982
4983 The Q_GADGET macro is a lighter version of the Q_OBJECT macro for classes
4984 that do not inherit from QObject but still want to use some of the
4985 reflection capabilities offered by QMetaObject.
4986
4987 \include qobject.cpp qobject-macros-private-access-specifier
4988
4989 Q_GADGETs can have Q_ENUM, Q_PROPERTY and Q_INVOKABLE, but they cannot have
4990 signals or slots.
4991
4992 Q_GADGET makes a class member, \c{staticMetaObject}, available.
4993 \c{staticMetaObject} is of type QMetaObject and provides access to the
4994 enums declared with Q_ENUM.
4995
4996 \sa Q_GADGET_EXPORT
4997*/
4998
4999/*!
5000 \macro Q_GADGET_EXPORT(EXPORT_MACRO)
5001 \relates QObject
5002 \since 6.3
5003
5004 The Q_GADGET_EXPORT macro works exactly like the Q_GADGET macro.
5005 However, the \c{staticMetaObject} variable that is made available (see
5006 Q_GADGET) is declared with the supplied \a EXPORT_MACRO qualifier. This is
5007 useful if the object needs to be exported from a dynamic library, but the
5008 enclosing class as a whole should not be (e.g. because it consists of mostly
5009 inline functions).
5010
5011 \include qobject.cpp qobject-macros-private-access-specifier
5012
5013 For example:
5014
5015 \code
5016 class Point {
5017 Q_GADGET_EXPORT(EXPORT_MACRO)
5018 Q_PROPERTY(int x MEMBER x)
5019 Q_PROPERTY(int y MEMBER y)
5020 ~~~
5021 \endcode
5022
5023 \sa Q_GADGET, {Creating Shared Libraries}
5024*/
5025
5026/*!
5027 \macro Q_NAMESPACE
5028 \relates QObject
5029 \since 5.8
5030
5031 The Q_NAMESPACE macro can be used to add QMetaObject capabilities
5032 to a namespace.
5033
5034 Q_NAMESPACEs can have Q_CLASSINFO, Q_ENUM_NS, Q_FLAG_NS, but they
5035 cannot have Q_ENUM, Q_FLAG, Q_PROPERTY, Q_INVOKABLE, signals nor slots.
5036
5037 Q_NAMESPACE makes an external variable, \c{staticMetaObject}, available.
5038 \c{staticMetaObject} is of type QMetaObject and provides access to the
5039 enums declared with Q_ENUM_NS/Q_FLAG_NS.
5040
5041 For example:
5042
5043 \code
5044 namespace test {
5045 Q_NAMESPACE
5046 ...
5047 \endcode
5048
5049 \sa Q_NAMESPACE_EXPORT
5050*/
5051
5052/*!
5053 \macro Q_NAMESPACE_EXPORT(EXPORT_MACRO)
5054 \relates QObject
5055 \since 5.14
5056
5057 The Q_NAMESPACE_EXPORT macro can be used to add QMetaObject capabilities
5058 to a namespace.
5059
5060 It works exactly like the Q_NAMESPACE macro. However, the external
5061 \c{staticMetaObject} variable that gets defined in the namespace
5062 is declared with the supplied \a EXPORT_MACRO qualifier. This is
5063 useful if the object needs to be exported from a dynamic library.
5064
5065 For example:
5066
5067 \code
5068 namespace test {
5069 Q_NAMESPACE_EXPORT(EXPORT_MACRO)
5070 ...
5071 \endcode
5072
5073 \sa Q_NAMESPACE, {Creating Shared Libraries}
5074*/
5075
5076/*!
5077 \macro Q_MOC_INCLUDE
5078 \relates QObject
5079 \since 6.0
5080
5081 The Q_MOC_INCLUDE macro can be used within or outside a class, and tell the
5082 \l{moc}{Meta Object Compiler} to add an include.
5083
5084 \code
5085 // Put this in your code and the generated code will include this header.
5086 Q_MOC_INCLUDE("myheader.h")
5087 \endcode
5088
5089 This is useful if the types you use as properties or signal/slots arguments
5090 are forward declared.
5091*/
5092
5093/*!
5094 \macro Q_SIGNALS
5095 \relates QObject
5096
5097 Use this macro to replace the \c signals keyword in class
5098 declarations, when you want to use Qt Signals and Slots with a
5099 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5100
5101 The macro is normally used when \c no_keywords is specified with
5102 the \c CONFIG variable in the \c .pro file, but it can be used
5103 even when \c no_keywords is \e not specified.
5104*/
5105
5106/*!
5107 \macro Q_SIGNAL
5108 \relates QObject
5109
5110 This is an additional macro that allows you to mark a single
5111 function as a signal. It can be quite useful, especially when you
5112 use a 3rd-party source code parser which doesn't understand a \c
5113 signals or \c Q_SIGNALS groups.
5114
5115 Use this macro to replace the \c signals keyword in class
5116 declarations, when you want to use Qt Signals and Slots with a
5117 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5118
5119 The macro is normally used when \c no_keywords is specified with
5120 the \c CONFIG variable in the \c .pro file, but it can be used
5121 even when \c no_keywords is \e not specified.
5122*/
5123
5124/*!
5125 \macro Q_SLOTS
5126 \relates QObject
5127
5128 Use this macro to replace the \c slots keyword in class
5129 declarations, when you want to use Qt Signals and Slots with a
5130 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5131
5132 The macro is normally used when \c no_keywords is specified with
5133 the \c CONFIG variable in the \c .pro file, but it can be used
5134 even when \c no_keywords is \e not specified.
5135*/
5136
5137/*!
5138 \macro Q_SLOT
5139 \relates QObject
5140
5141 This is an additional macro that allows you to mark a single
5142 function as a slot. It can be quite useful, especially when you
5143 use a 3rd-party source code parser which doesn't understand a \c
5144 slots or \c Q_SLOTS groups.
5145
5146 Use this macro to replace the \c slots keyword in class
5147 declarations, when you want to use Qt Signals and Slots with a
5148 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5149
5150 The macro is normally used when \c no_keywords is specified with
5151 the \c CONFIG variable in the \c .pro file, but it can be used
5152 even when \c no_keywords is \e not specified.
5153*/
5154
5155/*!
5156 \macro Q_EMIT
5157 \relates QObject
5158
5159 Use this macro to replace the \c emit keyword for emitting
5160 signals, when you want to use Qt Signals and Slots with a
5161 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5162
5163 The macro is normally used when \c no_keywords is specified with
5164 the \c CONFIG variable in the \c .pro file, but it can be used
5165 even when \c no_keywords is \e not specified.
5166*/
5167
5168/*!
5169 \macro Q_INVOKABLE
5170 \relates QObject
5171
5172 Apply this macro to declarations of member functions to allow them to
5173 be invoked via the meta-object system. The macro is written before
5174 the return type, as shown in the following example:
5175
5176 \snippet qmetaobject-invokable/window.h Window class with invokable method
5177
5178 The \c invokableMethod() function is marked up using Q_INVOKABLE, causing
5179 it to be registered with the meta-object system and enabling it to be
5180 invoked using QMetaObject::invokeMethod().
5181 Since \c normalMethod() function is not registered in this way, it cannot
5182 be invoked using QMetaObject::invokeMethod().
5183
5184 If an invokable member function returns a pointer to a QObject or a
5185 subclass of QObject and it is invoked from QML, special ownership rules
5186 apply. See \l{qtqml-cppintegration-data.html}{Data Type Conversion Between QML and C++}
5187 for more information.
5188*/
5189
5190/*!
5191 \macro Q_REVISION
5192 \relates QObject
5193
5194 Apply this macro to declarations of member functions to tag them with a
5195 revision number in the meta-object system. The macro is written before
5196 the return type, as shown in the following example:
5197
5198 \snippet qmetaobject-revision/window.h Window class with revision
5199
5200 This is useful when using the meta-object system to dynamically expose
5201 objects to another API, as you can match the version expected by multiple
5202 versions of the other API. Consider the following simplified example:
5203
5204 \snippet qmetaobject-revision/main.cpp Window class using revision
5205
5206 Using the same Window class as the previous example, the newProperty and
5207 newMethod would only be exposed in this code when the expected version is
5208 \c{2.1} or greater.
5209
5210 Since all methods are considered to be in revision \c{0} if untagged, a tag
5211 of \c{Q_REVISION(0)} or \c{Q_REVISION(0, 0)} is invalid and ignored.
5212
5213 You can pass one or two integer parameters to \c{Q_REVISION}. If you pass
5214 one parameter, it denotes the minor version only. This means that the major
5215 version is unspecified. If you pass two, the first parameter is the major
5216 version and the second parameter is the minor version.
5217
5218 This tag is not used by the meta-object system itself. Currently this is only
5219 used by the QtQml module.
5220
5221 For a more generic string tag, see \l QMetaMethod::tag()
5222
5223 \sa QMetaMethod::revision()
5224*/
5225
5226/*!
5227 \macro Q_SET_OBJECT_NAME(Object)
5228 \relates QObject
5229 \since 5.0
5230
5231 This macro assigns \a Object the objectName "Object".
5232
5233 It doesn't matter whether \a Object is a pointer or not, the
5234 macro figures that out by itself.
5235
5236 \sa QObject::objectName()
5237*/
5238
5239/*!
5240 \macro QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
5241 \relates QObject
5242 \since 5.8
5243
5244 Defining this macro will disable narrowing and floating-point-to-integral
5245 conversions between the arguments carried by a signal and the arguments
5246 accepted by a slot, when the signal and the slot are connected using the
5247 PMF-based syntax.
5248
5249 \sa QObject::connect
5250*/
5251
5252/*!
5253 \macro QT_NO_CONTEXTLESS_CONNECT
5254 \relates QObject
5255 \since 6.7
5256
5257 Defining this macro will disable the overload of QObject::connect() that
5258 connects a signal to a functor, without also specifying a QObject
5259 as a receiver/context object (that is, the 3-arguments overload
5260 of QObject::connect()).
5261
5262 Using the context-less overload is error prone, because it is easy
5263 to connect to functors that depend on some local state of the
5264 receiving end. If such local state gets destroyed, the connection
5265 does not get automatically disconnected.
5266
5267 Moreover, such connections are always direct connections, which may
5268 cause issues in multithreaded scenarios (for instance, if the
5269 signal is emitted from another thread).
5270
5271 \sa QObject::connect, Qt::ConnectionType
5272*/
5273
5274/*!
5275 \typedef QObjectList
5276 \relates QObject
5277
5278 Synonym for QList<QObject *>.
5279*/
5280
5281/*!
5282 \fn template<typename PointerToMemberFunction> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type)
5283 \overload connect()
5284 \threadsafe
5285
5286 Creates a connection of the given \a type from the \a signal in
5287 the \a sender object to the \a method in the \a receiver object.
5288 Returns a handle to the connection that can be used to disconnect
5289 it later.
5290
5291 The signal must be a function declared as a signal in the header.
5292 The slot function can be any member function that can be connected
5293 to the signal.
5294 A slot can be connected to a given signal if the signal has at
5295 least as many arguments as the slot, and there is an implicit
5296 conversion between the types of the corresponding arguments in the
5297 signal and the slot.
5298
5299 Example:
5300
5301 \snippet code/src_corelib_kernel_qobject.cpp 44
5302
5303 This example ensures that the label always displays the current
5304 line edit text.
5305
5306 A signal can be connected to many slots and signals. Many signals
5307 can be connected to one slot.
5308
5309 If a signal is connected to several slots, the slots are activated
5310 in the same order as the order the connection was made, when the
5311 signal is emitted
5312
5313 The function returns an handle to a connection if it successfully
5314 connects the signal to the slot. The Connection handle will be invalid
5315 if it cannot create the connection, for example, if QObject is unable
5316 to verify the existence of \a signal (if it was not declared as a signal)
5317 You can check if the QMetaObject::Connection is valid by casting it to a bool.
5318
5319 By default, a signal is emitted for every connection you make;
5320 two signals are emitted for duplicate connections. You can break
5321 all of these connections with a single disconnect() call.
5322 If you pass the Qt::UniqueConnection \a type, the connection will only
5323 be made if it is not a duplicate. If there is already a duplicate
5324 (exact same signal to the exact same slot on the same objects),
5325 the connection will fail and connect will return an invalid QMetaObject::Connection.
5326
5327 The optional \a type parameter describes the type of connection
5328 to establish. In particular, it determines whether a particular
5329 signal is delivered to a slot immediately or queued for delivery
5330 at a later time. If the signal is queued, the parameters must be
5331 of types that are known to Qt's meta-object system, because Qt
5332 needs to copy the arguments to store them in an event behind the
5333 scenes. If you try to use a queued connection and get the error
5334 message
5335
5336 \snippet code/src_corelib_kernel_qobject.cpp 25
5337
5338 make sure to declare the argument type with Q_DECLARE_METATYPE
5339
5340 Overloaded functions can be resolved with help of \l qOverload.
5341
5342 \sa {Differences between String-Based and Functor-Based Connections}
5343 */
5344
5345/*!
5346 \fn template<typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
5347
5348 \threadsafe
5349 \overload connect()
5350
5351 Creates a connection from \a signal in
5352 \a sender object to \a functor, and returns a handle to the connection
5353
5354 The signal must be a function declared as a signal in the header.
5355 The slot function can be any function or functor that can be connected
5356 to the signal.
5357 A slot function can be connected to a given signal if the signal has at
5358 least as many arguments as the slot function. There must exist implicit
5359 conversion between the types of the corresponding arguments in the
5360 signal and the slot.
5361
5362 Example:
5363
5364 \snippet code/src_corelib_kernel_qobject.cpp 45
5365
5366 Lambda expressions can also be used:
5367
5368 \snippet code/src_corelib_kernel_qobject.cpp 46
5369
5370 The connection will automatically disconnect if the sender is destroyed.
5371 However, you should take care that any objects used within the functor
5372 are still alive when the signal is emitted.
5373
5374 For this reason, it is recommended to use the overload of connect()
5375 that also takes a QObject as a receiver/context. It is possible
5376 to disable the usage of the context-less overload by defining the
5377 \c{QT_NO_CONTEXTLESS_CONNECT} macro.
5378
5379 Overloaded functions can be resolved with help of \l qOverload.
5380
5381 */
5382
5383/*!
5384 \fn template<typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type)
5385
5386 \threadsafe
5387 \overload connect()
5388
5389 \since 5.2
5390
5391 Creates a connection of a given \a type from \a signal in
5392 \a sender object to \a functor to be placed in a specific event
5393 loop of \a context, and returns a handle to the connection.
5394
5395 \note Qt::UniqueConnections do not work for lambdas, non-member functions
5396 and functors; they only apply to connecting to member functions.
5397
5398 The signal must be a function declared as a signal in the header.
5399 The slot function can be any function or functor that can be connected
5400 to the signal.
5401 A slot function can be connected to a given signal if the signal has at
5402 least as many arguments as the slot function. There must exist implicit
5403 conversion between the types of the corresponding arguments in the
5404 signal and the slot.
5405
5406 Example:
5407
5408 \snippet code/src_corelib_kernel_qobject.cpp 50_someFunction
5409 \snippet code/src_corelib_kernel_qobject.cpp 50
5410
5411 Lambda expressions can also be used:
5412
5413 \snippet code/src_corelib_kernel_qobject.cpp 51
5414
5415 The connection will automatically disconnect if the sender or the context
5416 is destroyed.
5417 However, you should take care that any objects used within the functor
5418 are still alive when the signal is emitted.
5419
5420 Overloaded functions can be resolved with help of \l qOverload.
5421 */
5422
5423/*!
5424 \internal
5425
5426 Implementation of the template version of connect
5427
5428 \a sender is the sender object
5429 \a signal is a pointer to a pointer to a member signal of the sender
5430 \a receiver is the receiver object, may not be \nullptr, will be equal to sender when
5431 connecting to a static function or a functor
5432 \a slot a pointer only used when using Qt::UniqueConnection
5433 \a type the Qt::ConnectionType passed as argument to connect
5434 \a types an array of integer with the metatype id of the parameter of the signal
5435 to be used with queued connection
5436 must stay valid at least for the whole time of the connection, this function
5437 do not take ownership. typically static data.
5438 If \nullptr, then the types will be computed when the signal is emit in a queued
5439 connection from the types from the signature.
5440 \a senderMetaObject is the metaobject used to lookup the signal, the signal must be in
5441 this metaobject
5442 */
5443QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,
5444 const QObject *receiver, void **slot,
5445 QtPrivate::QSlotObjectBase *slotObjRaw, Qt::ConnectionType type,
5446 const int *types, const QMetaObject *senderMetaObject)
5447{
5448 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5449 if (!signal) {
5450 connectWarning(sender, senderMetaObject, receiver, "invalid nullptr parameter");
5451 return QMetaObject::Connection();
5452 }
5453
5454 int signal_index = -1;
5455 void *args[] = { &signal_index, signal };
5456 for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
5457 senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
5458 if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
5459 break;
5460 }
5461 if (!senderMetaObject) {
5462 connectWarning(sender, senderMetaObject, receiver, "signal not found");
5463 return QMetaObject::Connection(nullptr);
5464 }
5465 signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
5466 return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj.release(), type, types, senderMetaObject);
5467}
5468
5469/*!
5470 \internal
5471
5472 Internal version of connect used by the template version of QObject::connect (called via connectImpl) and
5473 also used by the QObjectPrivate::connect version used by QML. The signal_index is expected to be relative
5474 to the number of signals.
5475 */
5476QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index,
5477 const QObject *receiver, void **slot,
5478 QtPrivate::QSlotObjectBase *slotObjRaw, int type,
5479 const int *types, const QMetaObject *senderMetaObject)
5480{
5481 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5482
5483 if (!sender || !receiver || !slotObj || !senderMetaObject) {
5484 connectWarning(sender, senderMetaObject, receiver, "invalid nullptr parameter");
5485 return QMetaObject::Connection();
5486 }
5487
5488 if (type & Qt::UniqueConnection && !slot) {
5489 connectWarning(sender, senderMetaObject, receiver, "unique connections require a pointer to member function of a QObject subclass");
5490 return QMetaObject::Connection();
5491 }
5492
5493 QObject *s = const_cast<QObject *>(sender);
5494 QObject *r = const_cast<QObject *>(receiver);
5495
5496 QOrderedMutexLocker locker(signalSlotLock(sender),
5497 signalSlotLock(receiver));
5498
5499 if (type & Qt::UniqueConnection) {
5500 QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
5501 if (connections && connections->signalVectorCount() > signal_index) {
5502 const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
5503
5504 while (c2) {
5505 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot))
5506 return QMetaObject::Connection();
5507 c2 = c2->nextConnectionList.loadRelaxed();
5508 }
5509 }
5510 }
5511 type &= ~Qt::UniqueConnection;
5512
5513 const bool isSingleShot = type & Qt::SingleShotConnection;
5514 type &= ~Qt::SingleShotConnection;
5515
5516 Q_ASSERT(type >= 0);
5517 Q_ASSERT(type <= 3);
5518
5519 std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
5520 c->sender = s;
5521 c->signal_index = signal_index;
5522 QThreadData *td = r->d_func()->threadData.loadAcquire();
5523 td->ref();
5524 c->receiverThreadData.storeRelaxed(td);
5525 c->receiver.storeRelaxed(r);
5526 c->connectionType = type;
5527 c->isSlotObject = true;
5528 c->slotObj = slotObj.release();
5529 if (types) {
5530 c->argumentTypes.storeRelaxed(types);
5531 c->ownArgumentTypes = false;
5532 }
5533 c->isSingleShot = isSingleShot;
5534
5535 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
5536 QMetaObject::Connection ret(c.release());
5537 locker.unlock();
5538
5539 QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
5540 Q_ASSERT(method.isValid());
5541 s->connectNotify(method);
5542
5543 return ret;
5544}
5545
5546/*!
5547 Disconnect a connection.
5548
5549 If the \a connection is invalid or has already been disconnected, do nothing
5550 and return false.
5551
5552 \sa connect()
5553 */
5554bool QObject::disconnect(const QMetaObject::Connection &connection)
5555{
5556 QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(connection.d_ptr);
5557 if (!c)
5558 return false;
5559 const bool disconnected = QObjectPrivate::removeConnection(c);
5560 const_cast<QMetaObject::Connection &>(connection).d_ptr = nullptr;
5561 c->deref(); // has been removed from the QMetaObject::Connection object
5562 return disconnected;
5563}
5564
5565/*! \fn template<typename PointerToMemberFunction> bool QObject::disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method)
5566 \overload disconnect()
5567 \threadsafe
5568
5569 Disconnects \a signal in object \a sender from \a method in object
5570 \a receiver. Returns \c true if the connection is successfully broken;
5571 otherwise returns \c false.
5572
5573 A signal-slot connection is removed when either of the objects
5574 involved are destroyed.
5575
5576 disconnect() is typically used in three ways, as the following
5577 examples demonstrate.
5578 \list 1
5579 \li Disconnect everything connected to an object's signals:
5580
5581 \snippet code/src_corelib_kernel_qobject.cpp 26
5582
5583 \li Disconnect everything connected to a specific signal:
5584
5585 \snippet code/src_corelib_kernel_qobject.cpp 47
5586
5587 \li Disconnect a specific receiver:
5588
5589 \snippet code/src_corelib_kernel_qobject.cpp 30
5590
5591 \li Disconnect a connection from one specific signal to a specific slot:
5592
5593 \snippet code/src_corelib_kernel_qobject.cpp 48
5594
5595
5596 \endlist
5597
5598 \nullptr may be used as a wildcard, meaning "any signal", "any receiving
5599 object", or "any slot in the receiving object", respectively.
5600
5601 The \a sender may never be \nullptr. (You cannot disconnect signals
5602 from more than one object in a single call.)
5603
5604 If \a signal is \nullptr, it disconnects \a receiver and \a method from
5605 any signal. If not, only the specified signal is disconnected.
5606
5607 If \a receiver is \nullptr, it disconnects anything connected to \a
5608 signal. If not, only slots in the specified receiver are disconnected.
5609 disconnect() with a non-null \a receiver also disconnects slot functions
5610 that were connected with \a receiver as their context object.
5611
5612 If \a method is \nullptr, it disconnects anything that is connected to \a
5613 receiver. If not, only slots named \a method will be disconnected,
5614 and all other slots are left alone. The \a method must be \nullptr
5615 if \a receiver is left out, so you cannot disconnect a
5616 specifically-named slot on all objects.
5617
5618 \note It is not possible to use this overload to disconnect signals
5619 connected to functors or lambda expressions. That is because it is not
5620 possible to compare them. Instead, use the overload that takes a
5621 QMetaObject::Connection.
5622
5623 \note Unless \a method is \nullptr, this function will also not break
5624 connections that were made using the string-based version of connect(). To
5625 break such connections, use the corresponding string-based overload of
5626 disconnect().
5627
5628 \sa connect()
5629*/
5630
5631bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot, const QMetaObject *senderMetaObject)
5632{
5633 if (sender == nullptr || (receiver == nullptr && slot != nullptr)) {
5634 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
5635 return false;
5636 }
5637
5638 int signal_index = -1;
5639 if (signal) {
5640 void *args[] = { &signal_index, signal };
5641 for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
5642 senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
5643 if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
5644 break;
5645 }
5646 if (!senderMetaObject) {
5647 qCWarning(lcConnect, "QObject::disconnect: signal not found in %s", sender->metaObject()->className());
5648 return false;
5649 }
5650 signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
5651 }
5652
5653 return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1, slot);
5654}
5655
5656/*!
5657 \internal
5658 Used by QML to connect a signal by index to a slot implemented in JavaScript
5659 (wrapped in a custom QSlotObjectBase subclass).
5660
5661 This version of connect assumes that sender and receiver are the same object.
5662
5663 The signal_index is an index relative to the number of methods.
5664 */
5665QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type)
5666{
5667 return QObjectPrivate::connect(sender, signal_index, sender, slotObj, type);
5668}
5669
5670/*!
5671 \internal
5672 Used by QML to connect a signal by index to a slot implemented in JavaScript
5673 (wrapped in a custom QSlotObjectBase subclass).
5674
5675 This is an overload that should be used when \a sender and \a receiver are
5676 different objects.
5677
5678 The signal_index is an index relative to the number of methods.
5679 */
5680QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index,
5681 const QObject *receiver,
5682 QtPrivate::QSlotObjectBase *slotObjRaw,
5683 Qt::ConnectionType type)
5684{
5685 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5686 if (!sender) {
5687 connectWarning(sender, nullptr, receiver, "invalid nullptr parameter");
5688 return QMetaObject::Connection();
5689 }
5690 const QMetaObject *senderMetaObject = sender->metaObject();
5691 signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
5692
5693 return connectImpl(sender, signal_index, receiver, /*slot*/ nullptr, slotObj.release(),
5694 type, /*types*/ nullptr, senderMetaObject);
5695}
5696
5697/*!
5698 \internal
5699 Used by QML to disconnect a signal by index that's connected to a slot implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass)
5700 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
5701 required for the disconnect.
5702
5703 This version of disconnect assumes that sender and receiver are the same object.
5704 */
5705bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, void **slot)
5706{
5707 return QObjectPrivate::disconnect(sender, signal_index, sender, slot);
5708}
5709
5710/*!
5711 \internal
5712
5713 Used by QML to disconnect a signal by index that's connected to a slot
5714 implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass) In the
5715 QML case the slot is not a pointer to a pointer to the function to disconnect,
5716 but instead it is a pointer to an array of internal values required for the
5717 disconnect.
5718
5719 This is an overload that should be used when \a sender and \a receiver are
5720 different objects.
5721 */
5722bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, const QObject *receiver,
5723 void **slot)
5724{
5725 const QMetaObject *senderMetaObject = sender->metaObject();
5726 signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
5727
5728 return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1,
5729 slot);
5730}
5731
5732/*!
5733 \internal
5734 \threadsafe
5735*/
5736inline bool QObjectPrivate::removeConnection(QObjectPrivate::Connection *c)
5737{
5738 if (!c)
5739 return false;
5740 QObject *receiver = c->receiver.loadRelaxed();
5741 if (!receiver)
5742 return false;
5743
5744 QBasicMutex *senderMutex = signalSlotLock(c->sender);
5745 QBasicMutex *receiverMutex = signalSlotLock(receiver);
5746
5747 QObjectPrivate::ConnectionData *connections;
5748 {
5749 QOrderedMutexLocker locker(senderMutex, receiverMutex);
5750
5751 // load receiver once again and recheck to ensure nobody else has removed the connection in the meantime
5752 receiver = c->receiver.loadRelaxed();
5753 if (!receiver)
5754 return false;
5755
5756 connections = QObjectPrivate::get(c->sender)->connections.loadRelaxed();
5757 Q_ASSERT(connections);
5758 connections->removeConnection(c);
5759
5760 c->sender->disconnectNotify(QMetaObjectPrivate::signal(c->sender->metaObject(), c->signal_index));
5761 // We must not hold the receiver mutex, else we risk dead-locking; we also only need the sender mutex
5762 // It is however vital to hold the senderMutex before calling cleanOrphanedConnections, as otherwise
5763 // another thread might modify/delete the connection
5764 if (receiverMutex != senderMutex) {
5765 receiverMutex->unlock();
5766 }
5767 connections->cleanOrphanedConnections(c->sender, ConnectionData::AlreadyLockedAndTemporarilyReleasingLock);
5768 senderMutex->unlock(); // now both sender and receiver mutex have been manually unlocked
5769 locker.dismiss(); // so we dismiss the QOrderedMutexLocker
5770 }
5771
5772 return true;
5773}
5774
5775/*!
5776 \internal
5777
5778 Used by QPropertyAdaptorSlotObject to get an existing instance for a property, if available
5779 */
5780QtPrivate::QPropertyAdaptorSlotObject *
5781QObjectPrivate::getPropertyAdaptorSlotObject(const QMetaProperty &property)
5782{
5783 if (auto conns = connections.loadAcquire()) {
5784 Q_Q(QObject);
5785 const QMetaObject *metaObject = q->metaObject();
5786 int signal_index = methodIndexToSignalIndex(&metaObject, property.notifySignalIndex());
5787 if (signal_index >= conns->signalVectorCount())
5788 return nullptr;
5789 const auto &connectionList = conns->connectionsForSignal(signal_index);
5790 for (auto c = connectionList.first.loadRelaxed(); c;
5791 c = c->nextConnectionList.loadRelaxed()) {
5792 if (c->isSlotObject) {
5793 if (auto p = QtPrivate::QPropertyAdaptorSlotObject::cast(c->slotObj,
5794 property.propertyIndex()))
5795 return p;
5796 }
5797 }
5798 }
5799 return nullptr;
5800}
5801
5802/*! \class QMetaObject::Connection
5803 \inmodule QtCore
5804 Represents a handle to a signal-slot (or signal-functor) connection.
5805
5806 It can be used to check if the connection is valid and to disconnect it using
5807 QObject::disconnect(). For a signal-functor connection without a context object,
5808 it is the only way to selectively disconnect that connection.
5809
5810 As Connection is just a handle, the underlying signal-slot connection is unaffected
5811 when Connection is destroyed or reassigned.
5812 */
5813
5814/*!
5815 Create a copy of the handle to the \a other connection
5816 */
5817QMetaObject::Connection::Connection(const QMetaObject::Connection &other) : d_ptr(other.d_ptr)
5818{
5819 if (d_ptr)
5820 static_cast<QObjectPrivate::Connection *>(d_ptr)->ref();
5821}
5822
5823/*!
5824 Assigns \a other to this connection and returns a reference to this connection.
5825*/
5826QMetaObject::Connection &QMetaObject::Connection::operator=(const QMetaObject::Connection &other)
5827{
5828 if (other.d_ptr != d_ptr) {
5829 if (d_ptr)
5830 static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
5831 d_ptr = other.d_ptr;
5832 if (other.d_ptr)
5833 static_cast<QObjectPrivate::Connection *>(other.d_ptr)->ref();
5834 }
5835 return *this;
5836}
5837
5838/*!
5839 Creates a Connection instance.
5840*/
5841
5842QMetaObject::Connection::Connection() : d_ptr(nullptr) {}
5843
5844/*!
5845 Destructor for QMetaObject::Connection.
5846*/
5847QMetaObject::Connection::~Connection()
5848{
5849 if (d_ptr)
5850 static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
5851}
5852
5853/*! \internal Returns true if the object is still connected */
5854bool QMetaObject::Connection::isConnected_helper() const
5855{
5856 Q_ASSERT(d_ptr); // we're only called from operator RestrictedBool() const
5857 QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(d_ptr);
5858
5859 return c->receiver.loadRelaxed();
5860}
5861
5862
5863/*!
5864 \fn QMetaObject::Connection::operator bool() const
5865
5866 Returns \c true if the connection is valid.
5867
5868 The connection is valid if the call to QObject::connect succeeded.
5869 The connection is invalid if QObject::connect was not able to find
5870 the signal or the slot, or if the arguments do not match.
5871 */
5872
5873QT_END_NAMESPACE
5874
5875#include "moc_qobject.cpp"
Combined button and popup list for selecting options.
Q_TRACE_POINT(qtcore, QCoreApplication_postEvent_exit)
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)
static void check_and_warn_compat(const QMetaObject *sender, const QMetaMethod &signal, const QMetaObject *receiver, const QMetaMethod &method)
Definition qobject.cpp:2978
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:3674
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 Q_DECL_COLD_FUNCTION void connectWarning(const QObject *sender, const QMetaObject *senderMetaObject, const QObject *receiver, const char *message)
Definition qobject.cpp:2719
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