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 != QThreadData::current())) {
1954 qWarning("QObject::startTimer: Timers cannot be started from another thread");
1955 return 0;
1956 }
1957
1958 auto dispatcher = thisThreadData->eventDispatcher.loadRelaxed();
1959 if (Q_UNLIKELY(!dispatcher)) {
1960 qWarning("QObject::startTimer: current thread's event dispatcher has already been destroyed");
1961 return 0;
1962 }
1963
1964 Qt::TimerId timerId = dispatcher->registerTimer(interval, timerType, this);
1965 d->ensureExtraData();
1966 d->extraData->runningTimers.append(timerId);
1967 return int(timerId);
1968}
1969
1970/*!
1971 Kills the timer with timer identifier, \a id.
1972
1973 The timer identifier is returned by startTimer() when a timer
1974 event is started.
1975
1976 \sa timerEvent(), startTimer()
1977*/
1978
1979void QObject::killTimer(int id)
1980{
1981 killTimer(Qt::TimerId{id});
1982}
1983
1984/*!
1985 \since 6.8
1986 \overload
1987*/
1988void QObject::killTimer(Qt::TimerId id)
1989{
1990 Q_D(QObject);
1991 if (Q_UNLIKELY(thread() != QThread::currentThread())) {
1992 qWarning("QObject::killTimer: Timers cannot be stopped from another thread");
1993 return;
1994 }
1995 if (id > Qt::TimerId::Invalid) {
1996 qsizetype at = d->extraData ? d->extraData->runningTimers.indexOf(id) : -1;
1997 if (at == -1) {
1998 // timer isn't owned by this object
1999 qWarning("QObject::killTimer(): Error: timer id %d is not valid for object %p (%s, %ls), timer has not been killed",
2000 qToUnderlying(id),
2001 this,
2002 metaObject()->className(),
2003 qUtf16Printable(objectName()));
2004 return;
2005 }
2006
2007 auto thisThreadData = d->threadData.loadRelaxed();
2008 if (thisThreadData->hasEventDispatcher())
2009 thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimer(id);
2010
2011 d->extraData->runningTimers.remove(at);
2012 QAbstractEventDispatcherPrivate::releaseTimerId(id);
2013 }
2014}
2015
2016/*!
2017 \fn QObject *QObject::parent() const
2018
2019 Returns a pointer to the parent object.
2020
2021 \sa children()
2022*/
2023
2024/*!
2025 \fn const QObjectList &QObject::children() const
2026
2027 Returns a list of child objects.
2028 The QObjectList class is defined in the \c{<QObject>} header
2029 file as the following:
2030
2031 \quotefromfile kernel/qobject.h
2032 \skipto /typedef .*QObjectList/
2033 \printuntil QObjectList
2034
2035 The first child added is the \l{QList::first()}{first} object in
2036 the list and the last child added is the \l{QList::last()}{last}
2037 object in the list, i.e. new children are appended at the end.
2038
2039 Note that the list order changes when QWidget children are
2040 \l{QWidget::raise()}{raised} or \l{QWidget::lower()}{lowered}. A
2041 widget that is raised becomes the last object in the list, and a
2042 widget that is lowered becomes the first object in the list.
2043
2044 \sa findChild(), findChildren(), parent(), setParent()
2045*/
2046
2047
2048/*!
2049 \fn template<typename T> T *QObject::findChild(QAnyStringView name, Qt::FindChildOptions options) const
2050
2051 Returns the child of this object that can be cast into type T and
2052 that is called \a name, or \nullptr if there is no such object.
2053 A null \a name argument causes all objects to be matched. An empty,
2054 non-null \a name matches only objects whose \l objectName is empty.
2055 The search is performed recursively, unless \a options specifies the
2056 option FindDirectChildrenOnly.
2057
2058 If there is more than one child matching the search, the most-direct
2059 ancestor is returned. If there are several most-direct ancestors, the
2060 first child in children() will be returned. In that case, it's better
2061 to use findChildren() to get the complete list of all children.
2062
2063 This example returns a child \c{QPushButton} of \c{parentWidget}
2064 named \c{"button1"}, even if the button isn't a direct child of
2065 the parent:
2066
2067 \snippet code/src_corelib_kernel_qobject.cpp 10
2068
2069 This example returns a \c{QListWidget} child of \c{parentWidget}:
2070
2071 \snippet code/src_corelib_kernel_qobject.cpp 11
2072
2073 This example returns a child \c{QPushButton} of \c{parentWidget}
2074 (its direct parent) named \c{"button1"}:
2075
2076 \snippet code/src_corelib_kernel_qobject.cpp 41
2077
2078 This example returns a \c{QListWidget} child of \c{parentWidget},
2079 its direct parent:
2080
2081 \snippet code/src_corelib_kernel_qobject.cpp 42
2082
2083 \note In Qt versions prior to 6.7, this function took \a name as
2084 \c{QString}, not \c{QAnyStringView}.
2085
2086 \sa findChildren()
2087*/
2088
2089/*!
2090 \fn template<typename T> T *QObject::findChild(Qt::FindChildOptions options) const
2091 \overload
2092 \since 6.7
2093
2094 Returns the child of this object that can be cast into type T, or
2095 \nullptr if there is no such object.
2096 The search is performed recursively, unless \a options specifies the
2097 option FindDirectChildrenOnly.
2098
2099 If there is more than one child matching the search, the most-direct ancestor
2100 is returned. If there are several most-direct ancestors, the first child in
2101 children() will be returned. In that case, it's better to use findChildren()
2102 to get the complete list of all children.
2103
2104 \sa findChildren()
2105*/
2106
2107/*!
2108 \fn template<typename T> QList<T> QObject::findChildren(QAnyStringView name, Qt::FindChildOptions options) const
2109
2110 Returns all children of this object with the given \a name that can be
2111 cast to type T, or an empty list if there are no such objects.
2112 A null \a name argument causes all objects to be matched, an empty one
2113 only those whose objectName is empty.
2114 The search is performed recursively, unless \a options specifies the
2115 option FindDirectChildrenOnly.
2116
2117 The following example shows how to find a list of child \c{QWidget}s of
2118 the specified \c{parentWidget} named \c{widgetname}:
2119
2120 \snippet code/src_corelib_kernel_qobject.cpp 12
2121
2122 This example returns all \c{QPushButton}s that are children of \c{parentWidget}:
2123
2124 \snippet code/src_corelib_kernel_qobject.cpp 13
2125
2126 This example returns all \c{QPushButton}s that are immediate children of \c{parentWidget}:
2127
2128 \snippet code/src_corelib_kernel_qobject.cpp 43
2129
2130 \note In Qt versions prior to 6.7, this function took \a name as
2131 \c{QString}, not \c{QAnyStringView}.
2132
2133 \sa findChild()
2134*/
2135
2136/*!
2137 \fn template<typename T> QList<T> QObject::findChildren(Qt::FindChildOptions options) const
2138 \overload
2139 \since 6.3
2140
2141 Returns all children of this object that can be cast to type T, or
2142 an empty list if there are no such objects.
2143 The search is performed recursively, unless \a options specifies the
2144 option FindDirectChildrenOnly.
2145
2146 \sa findChild()
2147*/
2148
2149/*!
2150 \fn template<typename T> QList<T> QObject::findChildren(const QRegularExpression &re, Qt::FindChildOptions options) const
2151 \overload findChildren()
2152
2153 \since 5.0
2154
2155 Returns the children of this object that can be cast to type T
2156 and that have names matching the regular expression \a re,
2157 or an empty list if there are no such objects.
2158 The search is performed recursively, unless \a options specifies the
2159 option FindDirectChildrenOnly.
2160*/
2161
2162/*!
2163 \fn template<typename T> T qFindChild(const QObject *obj, const QString &name)
2164 \relates QObject
2165 \overload qFindChildren()
2166 \deprecated
2167
2168 This function is equivalent to
2169 \a{obj}->\l{QObject::findChild()}{findChild}<T>(\a name).
2170
2171 \note This function was provided as a workaround for MSVC 6
2172 which did not support member template functions. It is advised
2173 to use the other form in new code.
2174
2175 \sa QObject::findChild()
2176*/
2177
2178/*!
2179 \fn template<typename T> QList<T> qFindChildren(const QObject *obj, const QString &name)
2180 \relates QObject
2181 \overload qFindChildren()
2182 \deprecated
2183
2184 This function is equivalent to
2185 \a{obj}->\l{QObject::findChildren()}{findChildren}<T>(\a name).
2186
2187 \note This function was provided as a workaround for MSVC 6
2188 which did not support member template functions. It is advised
2189 to use the other form in new code.
2190
2191 \sa QObject::findChildren()
2192*/
2193
2194static bool matches_objectName_non_null(QObject *obj, QAnyStringView name)
2195{
2196 if (auto ext = QObjectPrivate::get(obj)->extraData)
2197 return ext ->objectName.valueBypassingBindings() == name;
2198 return name.isEmpty();
2199}
2200
2201/*!
2202 \internal
2203*/
2204void qt_qFindChildren_helper(const QObject *parent, QAnyStringView name,
2205 const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
2206{
2207 Q_ASSERT(parent);
2208 Q_ASSERT(list);
2209 for (QObject *obj : parent->children()) {
2210 if (mo.cast(obj) && (name.isNull() || matches_objectName_non_null(obj, name)))
2211 list->append(obj);
2212 if (options & Qt::FindChildrenRecursively)
2213 qt_qFindChildren_helper(obj, name, mo, list, options);
2214 }
2215}
2216
2217#if QT_CONFIG(regularexpression)
2218/*!
2219 \internal
2220*/
2221void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re,
2222 const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
2223{
2224 Q_ASSERT(parent);
2225 Q_ASSERT(list);
2226 for (QObject *obj : parent->children()) {
2227 if (mo.cast(obj)) {
2228 QRegularExpressionMatch m = re.match(obj->objectName());
2229 if (m.hasMatch())
2230 list->append(obj);
2231 }
2232 if (options & Qt::FindChildrenRecursively)
2233 qt_qFindChildren_helper(obj, re, mo, list, options);
2234 }
2235}
2236#endif // QT_CONFIG(regularexpression)
2237
2238/*!
2239 \internal
2240*/
2241QObject *qt_qFindChild_helper(const QObject *parent, QAnyStringView name, const QMetaObject &mo, Qt::FindChildOptions options)
2242{
2243 Q_ASSERT(parent);
2244 for (QObject *obj : parent->children()) {
2245 if (mo.cast(obj) && (name.isNull() || matches_objectName_non_null(obj, name)))
2246 return obj;
2247 }
2248 if (options & Qt::FindChildrenRecursively) {
2249 for (QObject *child : parent->children()) {
2250 if (QObject *obj = qt_qFindChild_helper(child, name, mo, options))
2251 return obj;
2252 }
2253 }
2254 return nullptr;
2255}
2256
2257/*!
2258 Makes the object a child of \a parent.
2259
2260 \sa parent(), children()
2261*/
2262void QObject::setParent(QObject *parent)
2263{
2264 Q_D(QObject);
2265 Q_ASSERT(!d->isWidget);
2266 d->setParent_helper(parent);
2267}
2268
2269void QObjectPrivate::deleteChildren()
2270{
2271 Q_ASSERT_X(!isDeletingChildren, "QObjectPrivate::deleteChildren()", "isDeletingChildren already set, did this function recurse?");
2272 isDeletingChildren = true;
2273 // delete children objects
2274 // don't use qDeleteAll as the destructor of the child might
2275 // delete siblings
2276 for (int i = 0; i < children.size(); ++i) {
2277 currentChildBeingDeleted = children.at(i);
2278 children[i] = nullptr;
2279 delete currentChildBeingDeleted;
2280 }
2281 children.clear();
2282 currentChildBeingDeleted = nullptr;
2283 isDeletingChildren = false;
2284}
2285
2286void QObjectPrivate::setParent_helper(QObject *o)
2287{
2288 Q_Q(QObject);
2289 Q_ASSERT_X(q != o, Q_FUNC_INFO, "Cannot parent a QObject to itself");
2290#ifdef QT_DEBUG
2291 const auto checkForParentChildLoops = qScopeGuard([&](){
2292 int depth = 0;
2293 auto p = parent;
2294 while (p) {
2295 if (++depth == CheckForParentChildLoopsWarnDepth) {
2296 qWarning("QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
2297 "this is undefined behavior",
2298 q, q->metaObject()->className(), qPrintable(q->objectName()));
2299 }
2300 p = p->parent();
2301 }
2302 });
2303#endif
2304
2305 if (o == parent)
2306 return;
2307
2308 if (parent) {
2309 QObjectPrivate *parentD = parent->d_func();
2310 if (parentD->isDeletingChildren && wasDeleted
2311 && parentD->currentChildBeingDeleted == q) {
2312 // don't do anything since QObjectPrivate::deleteChildren() already
2313 // cleared our entry in parentD->children.
2314 } else {
2315 const qsizetype index = parentD->children.indexOf(q);
2316 if (index < 0) {
2317 // we're probably recursing into setParent() from a ChildRemoved event, don't do anything
2318 } else if (parentD->isDeletingChildren) {
2319 parentD->children[index] = nullptr;
2320 } else {
2321 parentD->children.removeAt(index);
2322 if (sendChildEvents && parentD->receiveChildEvents) {
2323 QChildEvent e(QEvent::ChildRemoved, q);
2324 QCoreApplication::sendEvent(parent, &e);
2325 }
2326 }
2327 }
2328 }
2329
2330 if (receiveParentEvents) {
2331 Q_ASSERT(!isWidget); // Handled in QWidget
2332 QEvent e(QEvent::ParentAboutToChange);
2333 QCoreApplication::sendEvent(q, &e);
2334 }
2335
2336 parent = o;
2337
2338 if (parent) {
2339 // object hierarchies are constrained to a single thread
2340 if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) {
2341 qWarning("QObject::setParent: Cannot set parent, new parent is in a different thread");
2342 parent = nullptr;
2343 return;
2344 }
2345 parent->d_func()->children.append(q);
2346 if (sendChildEvents && parent->d_func()->receiveChildEvents) {
2347 if (!isWidget) {
2348 QChildEvent e(QEvent::ChildAdded, q);
2349 QCoreApplication::sendEvent(parent, &e);
2350 }
2351 }
2352 }
2353
2354 if (receiveParentEvents) {
2355 Q_ASSERT(!isWidget); // Handled in QWidget
2356 QEvent e(QEvent::ParentChange);
2357 QCoreApplication::sendEvent(q, &e);
2358 }
2359}
2360
2361/*!
2362 \fn void QObject::installEventFilter(QObject *filterObj)
2363
2364 Installs an event filter \a filterObj on this object. For example:
2365 \snippet code/src_corelib_kernel_qobject.cpp 14
2366
2367 An event filter is an object that receives all events that are
2368 sent to this object. The filter can either stop the event or
2369 forward it to this object. The event filter \a filterObj receives
2370 events via its eventFilter() function. The eventFilter() function
2371 must return true if the event should be filtered, (i.e. stopped);
2372 otherwise it must return false.
2373
2374 If multiple event filters are installed on a single object, the
2375 filter that was installed last is activated first.
2376
2377 If \a filterObj has already been installed for this object,
2378 this function moves it so it acts as if it was installed last.
2379
2380 Here's a \c KeyPressEater class that eats the key presses of its
2381 monitored objects:
2382
2383 \snippet code/src_corelib_kernel_qobject.cpp 15
2384
2385 And here's how to install it on two widgets:
2386
2387 \snippet code/src_corelib_kernel_qobject.cpp 16
2388
2389 The QShortcut class, for example, uses this technique to intercept
2390 shortcut key presses.
2391
2392 \warning If you delete the receiver object in your eventFilter()
2393 function, be sure to return true. If you return false, Qt sends
2394 the event to the deleted object and the program will crash.
2395
2396 Note that the filtering object must be in the same thread as this
2397 object. If \a filterObj is in a different thread, this function does
2398 nothing. If either \a filterObj or this object are moved to a different
2399 thread after calling this function, the event filter will not be
2400 called until both objects have the same thread affinity again (it
2401 is \e not removed).
2402
2403 \sa removeEventFilter(), eventFilter(), event()
2404*/
2405
2406void QObject::installEventFilter(QObject *obj)
2407{
2408 Q_D(QObject);
2409 if (!obj)
2410 return;
2411 if (d->threadData.loadRelaxed() != obj->d_func()->threadData.loadRelaxed()) {
2412 qWarning("QObject::installEventFilter(): Cannot filter events for objects in a different thread.");
2413 return;
2414 }
2415
2416 d->ensureExtraData();
2417
2418 // clean up unused items in the list along the way:
2419 auto isNullOrEquals = [](auto obj) { return [obj](const auto &p) { return !p || p == obj; }; };
2420 d->extraData->eventFilters.removeIf(isNullOrEquals(obj));
2421 d->extraData->eventFilters.prepend(obj);
2422}
2423
2424/*!
2425 Removes an event filter object \a obj from this object. The
2426 request is ignored if such an event filter has not been installed.
2427
2428 All event filters for this object are automatically removed when
2429 this object is destroyed.
2430
2431 It is always safe to remove an event filter, even during event
2432 filter activation (i.e. from the eventFilter() function).
2433
2434 \sa installEventFilter(), eventFilter(), event()
2435*/
2436
2437void QObject::removeEventFilter(QObject *obj)
2438{
2439 Q_D(QObject);
2440 if (d->extraData) {
2441 for (auto &filter : d->extraData->eventFilters) {
2442 if (filter == obj) {
2443 filter = nullptr;
2444 break;
2445 }
2446 }
2447 }
2448}
2449
2450/*!
2451 \fn void QObject::destroyed(QObject *obj)
2452
2453 This signal is emitted immediately before the object \a obj is
2454 destroyed, after any instances of QPointer have been notified,
2455 and cannot be blocked.
2456
2457 All the objects's children are destroyed immediately after this
2458 signal is emitted.
2459
2460 \sa deleteLater(), QPointer
2461*/
2462
2463/*!
2464 \threadsafe
2465
2466 Schedules this object for deletion.
2467
2468 The object will be deleted when control returns to the event
2469 loop. If the event loop is not running when this function is
2470 called (e.g. deleteLater() is called on an object before
2471 QCoreApplication::exec()), the object will be deleted once the
2472 event loop is started. If deleteLater() is called after the main event loop
2473 has stopped, the object will not be deleted.
2474 If deleteLater() is called on an object that lives in a
2475 thread with no running event loop, the object will be destroyed when the
2476 thread finishes.
2477
2478 A common pattern when using a worker \c QObject in a \c QThread
2479 is to connect the thread's \c finished() signal to the worker's
2480 \c deleteLater() slot to ensure it is safely deleted:
2481
2482 \code
2483 connect(thread, &QThread::finished, worker, &QObject::deleteLater);
2484 \endcode
2485
2486 Note that entering and leaving a new event loop (e.g., by opening a modal
2487 dialog) will \e not perform the deferred deletion; for the object to be
2488 deleted, the control must return to the event loop from which deleteLater()
2489 was called. This does not apply to objects deleted while a previous, nested
2490 event loop was still running: the Qt event loop will delete those objects
2491 as soon as the new nested event loop starts.
2492
2493 In situations where Qt is not driving the event dispatcher via e.g.
2494 QCoreApplication::exec() or QEventLoop::exec(), deferred deletes
2495 will not be processed automatically. To ensure deferred deletion in
2496 this scenario, the following workaround can be used:
2497
2498 \code
2499 const auto *eventDispatcher = QThread::currentThread()->eventDispatcher();
2500 QObject::connect(eventDispatcher, &QAbstractEventDispatcher::aboutToBlock,
2501 QThread::currentThread(), []{
2502 if (QThread::currentThread()->loopLevel() == 0)
2503 QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
2504 }
2505 );
2506 \endcode
2507
2508 \sa destroyed(), QPointer
2509*/
2510void QObject::deleteLater()
2511{
2512#ifdef QT_DEBUG
2513 if (qApp == this)
2514 qWarning("You are deferring the delete of QCoreApplication, this may not work as expected.");
2515#endif
2516
2517
2518 // De-bounce QDeferredDeleteEvents. Use the post event list mutex
2519 // to guard access to deleteLaterCalled, so we don't need a separate
2520 // mutex in QObjectData.
2521 auto eventListLocker = QCoreApplicationPrivate::lockThreadPostEventList(this);
2522 if (!eventListLocker.threadData)
2523 return;
2524
2525 // FIXME: The deleteLaterCalled flag is part of a bit field,
2526 // so we likely have data races here, even with the mutex above,
2527 // as long as we're not guarding every access to the bit field.
2528
2529 Q_D(QObject);
2530 if (d->deleteLaterCalled)
2531 return;
2532
2533 d->deleteLaterCalled = true;
2534
2535 int loopLevel = 0;
2536 int scopeLevel = 0;
2537
2538 auto *objectThreadData = eventListLocker.threadData;
2539 if (objectThreadData == QThreadData::current()) {
2540 // Remember the current running eventloop for deleteLater
2541 // calls in the object's own thread.
2542
2543 // Events sent by non-Qt event handlers (such as glib) may not
2544 // have the scopeLevel set correctly. The scope level makes sure that
2545 // code like this:
2546 // foo->deleteLater();
2547 // qApp->processEvents(); // without passing QEvent::DeferredDelete
2548 // will not cause "foo" to be deleted before returning to the event loop.
2549
2550 loopLevel = objectThreadData->loopLevel;
2551 scopeLevel = objectThreadData->scopeLevel;
2552
2553 // If the scope level is 0 while loopLevel != 0, we are called from a
2554 // non-conformant code path, and our best guess is that the scope level
2555 // should be 1. (Loop level 0 is special: it means that no event loops
2556 // are running.)
2557 if (scopeLevel == 0 && loopLevel != 0)
2558 scopeLevel = 1;
2559 }
2560
2561 eventListLocker.unlock();
2562 QCoreApplication::postEvent(this,
2563 new QDeferredDeleteEvent(loopLevel, scopeLevel));
2564}
2565
2566/*!
2567 \fn QString QObject::tr(const char *sourceText, const char *disambiguation, int n)
2568 \reentrant
2569
2570 Returns a translated version of \a sourceText, optionally based on a
2571 \a disambiguation string and value of \a n for strings containing plurals;
2572 otherwise returns QString::fromUtf8(\a sourceText) if no appropriate
2573 translated string is available.
2574
2575 Example:
2576 \snippet ../widgets/itemviews/spreadsheet/spreadsheet.cpp implicit tr context
2577 \dots
2578
2579 If the same \a sourceText is used in different roles within the
2580 same context, an additional identifying string may be passed in
2581 \a disambiguation (\nullptr by default).
2582
2583 Example:
2584
2585 \snippet code/src_corelib_kernel_qobject.cpp 17
2586 \dots
2587
2588 See \l{Writing Source Code for Translation} for a detailed description of
2589 Qt's translation mechanisms in general, and the
2590 \l{Writing Source Code for Translation#Disambiguate Identical Text}
2591 {Disambiguate Identical Text} section for information on disambiguation.
2592
2593 \warning This method is reentrant only if all translators are
2594 installed \e before calling this method. Installing or removing
2595 translators while performing translations is not supported. Doing
2596 so will probably result in crashes or other undesirable behavior.
2597
2598 \sa QCoreApplication::translate(), {Internationalization with Qt}
2599*/
2600
2601/*****************************************************************************
2602 Signals and slots
2603 *****************************************************************************/
2604
2605namespace {
2606// This class provides (per-thread) storage for qFlagLocation()
2607class FlaggedDebugSignatures
2608{
2609 uint idx = 0;
2610 std::array<const char *, 2> locations = {}; // one for the SIGNAL, one for the SLOT
2611
2612public:
2613 void store(const char* method) noexcept
2614 { locations[idx++ % locations.size()] = method; }
2615
2616 bool contains(const char *method) const noexcept
2617 { return std::find(locations.begin(), locations.end(), method) != locations.end(); }
2618};
2619
2620Q_CONSTINIT static thread_local FlaggedDebugSignatures flaggedSignatures = {};
2621} // unnamed namespace
2622
2623const char *qFlagLocation(const char *method)
2624{
2625 flaggedSignatures.store(method);
2626 return method;
2627}
2628
2629static int extract_code(const char *member)
2630{
2631 // extract code, ensure QMETHOD_CODE <= code <= QSIGNAL_CODE
2632 return (((int)(*member) - '0') & 0x3);
2633}
2634
2635static const char *extract_location(const char *member)
2636{
2637 if (flaggedSignatures.contains(member)) {
2638 // signature includes location information after the first null-terminator
2639 const char *location = member + qstrlen(member) + 1;
2640 if (*location != '\0')
2641 return location;
2642 }
2643 return nullptr;
2644}
2645
2646static bool check_signal_macro(const QObject *sender, const char *signal,
2647 const char *func, const char *op)
2648{
2649 int sigcode = extract_code(signal);
2650 if (sigcode != QSIGNAL_CODE) {
2651 if (sigcode == QSLOT_CODE)
2652 qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s", func, op,
2653 sender->metaObject()->className(), signal + 1);
2654 else
2655 qCWarning(lcConnect, "QObject::%s: Use the SIGNAL macro to %s %s::%s", func, op,
2656 sender->metaObject()->className(), signal);
2657 return false;
2658 }
2659 return true;
2660}
2661
2662static bool check_method_code(int code, const QObject *object, const char *method, const char *func)
2663{
2664 if (code != QSLOT_CODE && code != QSIGNAL_CODE) {
2665 qCWarning(lcConnect,
2666 "QObject::%s: Use the SLOT or SIGNAL macro to "
2667 "%s %s::%s",
2668 func, func, object->metaObject()->className(), method);
2669 return false;
2670 }
2671 return true;
2672}
2673
2674#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
2675static void check_and_warn_non_slot(const char *func, const char *method, int membcode,
2676 const QMetaObject *rmeta, const QMetaMethod &rmethod)
2677{
2678 if (membcode == QSLOT_CODE && rmethod.methodType() != QMetaMethod::Slot) {
2679 // In Qt7 QMetaObject::indexOfSlot{,relative} will return -1 if `method`
2680 // isn't a slot.
2681 qCWarning(lcConnect,
2682 "QObject::%s: the SLOT() macro is used with a non-slot function: %s::%s. "
2683 "This currently works due to backwards-compatibility reasons. In Qt7 the "
2684 "SLOT() macro will work only for methods marked as slots.",
2685 func, rmeta->className(), method);
2686 }
2687}
2688#endif // QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
2689
2691static void err_method_notfound(const QObject *object,
2692 const char *method, const char *func)
2693{
2694 const char *type = "method";
2695 switch (extract_code(method)) {
2696 case QSLOT_CODE: type = "slot"; break;
2697 case QSIGNAL_CODE: type = "signal"; break;
2698 }
2699 const char *loc = extract_location(method);
2700 const char *err;
2701 if (strchr(method, ')') == nullptr) // common typing mistake
2702 err = "Parentheses expected,";
2703 else
2704 err = "No such";
2705 qCWarning(lcConnect, "QObject::%s: %s %s %s::%s%s%s", func, err, type,
2706 object->metaObject()->className(), method + 1, loc ? " in " : "", loc ? loc : "");
2707}
2708
2709enum class ConnectionEnd : bool { Sender, Receiver };
2711static void err_info_about_object(const char *func, const QObject *o, ConnectionEnd end)
2712{
2713 if (!o)
2714 return;
2715 const QString name = o->objectName();
2716 if (name.isEmpty())
2717 return;
2718 const bool sender = end == ConnectionEnd::Sender;
2719 qCWarning(lcConnect, "QObject::%s: (%s name:%*s'%ls')",
2720 func,
2721 sender ? "sender" : "receiver",
2722 sender ? 3 : 1, // ← length of generated whitespace
2723 "",
2724 qUtf16Printable(name));
2725}
2726
2728static void err_info_about_objects(const char *func, const QObject *sender, const QObject *receiver)
2729{
2732}
2733
2735static void connectWarning(const QObject *sender,
2736 const QMetaObject *senderMetaObject,
2737 const QObject *receiver,
2738 const char *message)
2739{
2740 const char *senderString = sender ? sender->metaObject()->className()
2741 : senderMetaObject ? senderMetaObject->className()
2742 : "Unknown";
2743 const char *receiverString = receiver ? receiver->metaObject()->className()
2744 : "Unknown";
2745 qCWarning(lcConnect, "QObject::connect(%s, %s): %s", senderString, receiverString, message);
2746}
2747
2748/*!
2749 Returns a pointer to the object that sent the signal, if called in
2750 a slot activated by a signal; otherwise it returns \nullptr. The pointer
2751 is valid only during the execution of the slot that calls this
2752 function from this object's thread context.
2753
2754 The pointer returned by this function becomes invalid if the
2755 sender is destroyed, or if the slot is disconnected from the
2756 sender's signal.
2757
2758 \warning This function violates the object-oriented principle of
2759 modularity. However, getting access to the sender might be useful
2760 when many signals are connected to a single slot.
2761
2762 \warning As mentioned above, the return value of this function is
2763 not valid when the slot is called via a Qt::DirectConnection from
2764 a thread different from this object's thread. Do not use this
2765 function in this type of scenario.
2766
2767 \sa senderSignalIndex()
2768*/
2769
2770QObject *QObject::sender() const
2771{
2772 Q_D(const QObject);
2773
2774 QMutexLocker locker(signalSlotLock(this));
2775 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2776 if (!cd || !cd->currentSender)
2777 return nullptr;
2778
2779 for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2780 if (c->sender == cd->currentSender->sender)
2781 return cd->currentSender->sender;
2782 }
2783
2784 return nullptr;
2785}
2786
2787/*!
2788 \since 4.8
2789
2790 Returns the meta-method index of the signal that called the currently
2791 executing slot, which is a member of the class returned by sender().
2792 If called outside of a slot activated by a signal, -1 is returned.
2793
2794 For signals with default parameters, this function will always return
2795 the index with all parameters, regardless of which was used with
2796 connect(). For example, the signal \c {destroyed(QObject *obj = \nullptr)}
2797 will have two different indexes (with and without the parameter), but
2798 this function will always return the index with a parameter. This does
2799 not apply when overloading signals with different parameters.
2800
2801 \warning This function violates the object-oriented principle of
2802 modularity. However, getting access to the signal index might be useful
2803 when many signals are connected to a single slot.
2804
2805 \warning The return value of this function is not valid when the slot
2806 is called via a Qt::DirectConnection from a thread different from this
2807 object's thread. Do not use this function in this type of scenario.
2808
2809 \sa sender(), QMetaObject::indexOfSignal(), QMetaObject::method()
2810*/
2811
2812int QObject::senderSignalIndex() const
2813{
2814 Q_D(const QObject);
2815
2816 QMutexLocker locker(signalSlotLock(this));
2817 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2818 if (!cd || !cd->currentSender)
2819 return -1;
2820
2821 for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2822 if (c->sender == cd->currentSender->sender) {
2823 // Convert from signal range to method range
2824 return QMetaObjectPrivate::signal(c->sender->metaObject(), cd->currentSender->signal).methodIndex();
2825 }
2826 }
2827
2828 return -1;
2829}
2830
2831/*!
2832 Returns the number of receivers connected to the \a signal.
2833
2834 Since both slots and signals can be used as receivers for signals,
2835 and the same connections can be made many times, the number of
2836 receivers is the same as the number of connections made from this
2837 signal.
2838
2839 When calling this function, you can use the \c SIGNAL() macro to
2840 pass a specific signal:
2841
2842 \snippet code/src_corelib_kernel_qobject.cpp 21
2843
2844 As the code snippet above illustrates, you can use this function to avoid
2845 expensive operations or emitting a signal that nobody listens to.
2846
2847 \warning In a multithreaded application, consecutive calls to this
2848 function are not guaranteed to yield the same results.
2849
2850 \warning This function violates the object-oriented principle of
2851 modularity. In particular, this function must not be called from an
2852 override of connectNotify() or disconnectNotify(), as those might get
2853 called from any thread.
2854
2855 \sa isSignalConnected()
2856*/
2857
2858int QObject::receivers(const char *signal) const
2859{
2860 Q_D(const QObject);
2861 int receivers = 0;
2862 if (signal) {
2863 QByteArray signal_name = QMetaObject::normalizedSignature(signal);
2864 signal = signal_name;
2865#ifndef QT_NO_DEBUG
2866 if (!check_signal_macro(this, signal, "receivers", "bind"))
2867 return 0;
2868#endif
2869 signal++; // skip code
2870 int signal_index = d->signalIndex(signal);
2871 if (signal_index < 0) {
2872#ifndef QT_NO_DEBUG
2873 err_method_notfound(this, signal - 1, "receivers");
2874#endif
2875 return 0;
2876 }
2877
2878 if (!d->isSignalConnected(signal_index))
2879 return receivers;
2880
2881 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::receivers) {
2882 receivers += QAbstractDeclarativeData::receivers(d->declarativeData, this,
2883 signal_index);
2884 }
2885
2886 QMutexLocker locker(signalSlotLock(this));
2887 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2888 if (cd && signal_index < cd->signalVectorCount()) {
2889 const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
2890 while (c) {
2891 receivers += c->receiver.loadRelaxed() ? 1 : 0;
2892 c = c->nextConnectionList.loadRelaxed();
2893 }
2894 }
2895 }
2896 return receivers;
2897}
2898
2899/*!
2900 \since 5.0
2901 Returns \c true if the \a signal is connected to at least one receiver,
2902 otherwise returns \c false.
2903
2904 \a signal must be a signal member of this object, otherwise the behaviour
2905 is undefined.
2906
2907 \snippet code/src_corelib_kernel_qobject.cpp 49
2908
2909 As the code snippet above illustrates, you can use this function to avoid
2910 expensive operations or emitting a signal that nobody listens to.
2911
2912 \warning In a multithreaded application, consecutive calls to this
2913 function are not guaranteed to yield the same results.
2914
2915 \warning This function violates the object-oriented principle of
2916 modularity. In particular, this function must not be called from an
2917 override of connectNotify() or disconnectNotify(), as those might get
2918 called from any thread.
2919
2920 \sa receivers()
2921*/
2922bool QObject::isSignalConnected(const QMetaMethod &signal) const
2923{
2924 Q_D(const QObject);
2925 if (!signal.mobj)
2926 return false;
2927
2928 Q_ASSERT_X(signal.mobj->cast(this) && signal.methodType() == QMetaMethod::Signal,
2929 "QObject::isSignalConnected" , "the parameter must be a signal member of the object");
2930 uint signalIndex = signal.relativeMethodIndex();
2931
2932 if (signal.data.flags() & MethodCloned)
2933 signalIndex = QMetaObjectPrivate::originalClone(signal.mobj, signalIndex);
2934
2935 signalIndex += QMetaObjectPrivate::signalOffset(signal.mobj);
2936
2937 QMutexLocker locker(signalSlotLock(this));
2938 return d->isSignalConnected(signalIndex, true);
2939}
2940
2941/*!
2942 \internal
2943
2944 This helper function calculates signal and method index for the given
2945 member in the specified class.
2946
2947 \list
2948 \li If member.mobj is \nullptr then both signalIndex and methodIndex are set to -1.
2949
2950 \li If specified member is not a member of obj instance class (or one of
2951 its parent classes) then both signalIndex and methodIndex are set to -1.
2952 \endlist
2953
2954 This function is used by QObject::connect and QObject::disconnect which
2955 are working with QMetaMethod.
2956
2957 \a signalIndex is set to the signal index of member. If the member
2958 specified is not signal this variable is set to -1.
2959
2960 \a methodIndex is set to the method index of the member. If the
2961 member is not a method of the object specified by the \a obj argument this
2962 variable is set to -1.
2963*/
2964void QMetaObjectPrivate::memberIndexes(const QObject *obj,
2965 const QMetaMethod &member,
2966 int *signalIndex, int *methodIndex)
2967{
2968 *signalIndex = -1;
2969 *methodIndex = -1;
2970 if (!obj || !member.mobj)
2971 return;
2972 const QMetaObject *m = obj->metaObject();
2973 // Check that member is member of obj class
2974 while (m != nullptr && m != member.mobj)
2975 m = m->d.superdata;
2976 if (!m)
2977 return;
2978 *signalIndex = *methodIndex = member.relativeMethodIndex();
2979
2980 int signalOffset;
2981 int methodOffset;
2982 computeOffsets(m, &signalOffset, &methodOffset);
2983
2984 *methodIndex += methodOffset;
2985 if (member.methodType() == QMetaMethod::Signal) {
2986 *signalIndex = originalClone(m, *signalIndex);
2987 *signalIndex += signalOffset;
2988 } else {
2989 *signalIndex = -1;
2990 }
2991}
2992
2993#ifndef QT_NO_DEBUG
2994static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaMethod &signal,
2995 const QMetaObject *receiver, const QMetaMethod &method)
2996{
2997 if (signal.attributes() & QMetaMethod::Compatibility) {
2998 if (!(method.attributes() & QMetaMethod::Compatibility))
2999 qCWarning(lcConnect, "QObject::connect: Connecting from COMPAT signal (%s::%s)",
3000 sender->className(), signal.methodSignature().constData());
3001 } else if ((method.attributes() & QMetaMethod::Compatibility)
3002 && method.methodType() == QMetaMethod::Signal) {
3003 qCWarning(lcConnect, "QObject::connect: Connecting from %s::%s to COMPAT slot (%s::%s)",
3004 sender->className(), signal.methodSignature().constData(), receiver->className(),
3005 method.methodSignature().constData());
3006 }
3007}
3008#endif
3009
3010/*!
3011 \threadsafe
3012
3013 Creates a connection of the given \a type from the \a signal in
3014 the \a sender object to the \a method in the \a receiver object.
3015 Returns a handle to the connection that can be used to disconnect
3016 it later.
3017
3018 You must use the \c SIGNAL() and \c SLOT() macros when specifying
3019 the \a signal and the \a method, for example:
3020
3021 \snippet code/src_corelib_kernel_qobject.cpp 22
3022
3023 This example ensures that the label always displays the current
3024 scroll bar value. Note that the signal and slots parameters must not
3025 contain any variable names, only the type. E.g. the following would
3026 not work and return false:
3027
3028 \snippet code/src_corelib_kernel_qobject.cpp 23
3029
3030 A signal can also be connected to another signal:
3031
3032 \snippet code/src_corelib_kernel_qobject.cpp 24
3033
3034 In this example, the \c MyWidget constructor relays a signal from
3035 a private member variable, and makes it available under a name
3036 that relates to \c MyWidget.
3037
3038 A signal can be connected to many slots and signals. Many signals
3039 can be connected to one slot.
3040
3041 If a signal is connected to several slots, the slots are activated
3042 in the same order in which the connections were made, when the
3043 signal is emitted.
3044
3045 The function returns a QMetaObject::Connection that represents
3046 a handle to a connection if it successfully
3047 connects the signal to the slot. The connection handle will be invalid
3048 if it cannot create the connection, for example, if QObject is unable
3049 to verify the existence of either \a signal or \a method, or if their
3050 signatures aren't compatible.
3051 You can check if the handle is valid by casting it to a bool.
3052
3053 By default, a signal is emitted for every connection you make;
3054 two signals are emitted for duplicate connections. You can break
3055 all of these connections with a single disconnect() call.
3056 If you pass the Qt::UniqueConnection \a type, the connection will only
3057 be made if it is not a duplicate. If there is already a duplicate
3058 (exact same signal to the exact same slot on the same objects),
3059 the connection will fail and connect will return an invalid QMetaObject::Connection.
3060
3061 \note Qt::UniqueConnections do not work for lambdas, non-member functions
3062 and functors; they only apply to connecting to member functions.
3063
3064 The optional \a type parameter describes the type of connection
3065 to establish. In particular, it determines whether a particular
3066 signal is delivered to a slot immediately or queued for delivery
3067 at a later time. If the signal is queued, the parameters must be
3068 of types that are known to Qt's meta-object system, because Qt
3069 needs to copy the arguments to store them in an event behind the
3070 scenes. If you try to use a queued connection and get the error
3071 message
3072
3073 \snippet code/src_corelib_kernel_qobject.cpp 25
3074
3075 call qRegisterMetaType() to register the data type before you
3076 establish the connection.
3077
3078 \sa disconnect(), sender(), qRegisterMetaType(), Q_DECLARE_METATYPE(),
3079 {Differences between String-Based and Functor-Based Connections}
3080*/
3081QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal,
3082 const QObject *receiver, const char *method,
3083 Qt::ConnectionType type)
3084{
3085 if (sender == nullptr || receiver == nullptr || signal == nullptr || method == nullptr) {
3086 qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
3087 sender ? sender->metaObject()->className() : "(nullptr)",
3088 (signal && *signal) ? signal + 1 : "(nullptr)",
3089 receiver ? receiver->metaObject()->className() : "(nullptr)",
3090 (method && *method) ? method + 1 : "(nullptr)");
3091 return QMetaObject::Connection(nullptr);
3092 }
3093
3094 if (!check_signal_macro(sender, signal, "connect", "bind"))
3095 return QMetaObject::Connection(nullptr);
3096
3097 int membcode = extract_code(method);
3098 if (!check_method_code(membcode, receiver, method, "connect"))
3099 return QMetaObject::Connection(nullptr);
3100
3101 QByteArray pinnedSignal;
3102 const QMetaObject *smeta = sender->metaObject();
3103 const char *signal_arg = signal;
3104 ++signal; // skip code
3105 QByteArrayView signalView{signal}; // after skipping code
3106 QArgumentTypeArray signalTypes;
3107 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3108 QByteArrayView signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3109 int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3110 if (signal_index < 0) {
3111 // check for normalized signatures
3112 pinnedSignal = QMetaObjectPrivate::normalizedSignature(signalView);
3113 signalView = pinnedSignal;
3114
3115 signalTypes.clear();
3116 signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3117 smeta = sender->metaObject();
3118 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3119 }
3120 if (signal_index < 0) {
3121 err_method_notfound(sender, signal_arg, "connect");
3122 err_info_about_objects("connect", sender, receiver);
3123 return QMetaObject::Connection(nullptr);
3124 }
3125 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3126 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3127
3128 QByteArray pinnedMethod;
3129 const char *method_arg = method;
3130 ++method; // skip code
3131 QByteArrayView methodView{method}; // after skipping code
3132
3133 QArgumentTypeArray methodTypes;
3134 QByteArrayView methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3135 const QMetaObject *rmeta = receiver->metaObject();
3136 int method_index_relative = -1;
3137 Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
3138 switch (membcode) {
3139 case QSLOT_CODE:
3140 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3141 &rmeta, methodName, methodTypes);
3142 break;
3143 case QSIGNAL_CODE:
3144 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3145 &rmeta, methodName, methodTypes);
3146 break;
3147 }
3148
3149 if (method_index_relative < 0) {
3150 // check for normalized methods
3151 pinnedMethod = QMetaObjectPrivate::normalizedSignature(methodView);
3152 methodView = pinnedMethod;
3153
3154 methodTypes.clear();
3155 methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3156 // rmeta may have been modified above
3157 rmeta = receiver->metaObject();
3158 switch (membcode) {
3159 case QSLOT_CODE:
3160 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3161 &rmeta, methodName, methodTypes);
3162 break;
3163 case QSIGNAL_CODE:
3164 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3165 &rmeta, methodName, methodTypes);
3166 break;
3167 }
3168 }
3169
3170 if (method_index_relative < 0) {
3171 err_method_notfound(receiver, method_arg, "connect");
3172 err_info_about_objects("connect", sender, receiver);
3173 return QMetaObject::Connection(nullptr);
3174 }
3175
3176 if (!QMetaObjectPrivate::checkConnectArgs(signalTypes, methodTypes)) {
3177 qCWarning(lcConnect,
3178 "QObject::connect: Incompatible sender/receiver arguments"
3179 "\n %s::%s --> %s::%s",
3180 sender->metaObject()->className(), signalView.constData(),
3181 receiver->metaObject()->className(), methodView.constData());
3182 return QMetaObject::Connection(nullptr);
3183 }
3184
3185 // ### Future work: attempt get the metatypes from the meta object first
3186 // because it's possible they're all registered.
3187 int *types = nullptr;
3188 if (type == Qt::QueuedConnection && !(types = queuedConnectionTypes(signalTypes))) {
3189 return QMetaObject::Connection(nullptr);
3190 }
3191
3192 QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
3193#ifndef QT_NO_DEBUG
3194 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3195 check_and_warn_compat(smeta, smethod, rmeta, rmethod);
3196#endif
3197
3198#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
3199 check_and_warn_non_slot("connect", method, membcode, rmeta, rmethod);
3200#endif
3201
3202 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3203 sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
3204 return handle;
3205}
3206
3207/*!
3208 \since 4.8
3209
3210 Creates a connection of the given \a type from the \a signal in
3211 the \a sender object to the \a method in the \a receiver object.
3212 Returns a handle to the connection that can be used to disconnect
3213 it later.
3214
3215 The Connection handle will be invalid if it cannot create the
3216 connection, for example, the parameters were invalid.
3217 You can check if the QMetaObject::Connection is valid by casting it to a bool.
3218
3219 This function works in the same way as
3220 \c {connect(const QObject *sender, const char *signal,
3221 const QObject *receiver, const char *method,
3222 Qt::ConnectionType type)}
3223 but it uses QMetaMethod to specify signal and method.
3224
3225 \sa connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
3226 */
3227QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMethod &signal,
3228 const QObject *receiver, const QMetaMethod &method,
3229 Qt::ConnectionType type)
3230{
3231 if (sender == nullptr
3232 || receiver == nullptr
3233 || signal.methodType() != QMetaMethod::Signal
3234 || method.methodType() == QMetaMethod::Constructor) {
3235 qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
3236 sender ? sender->metaObject()->className() : "(nullptr)",
3237 signal.methodSignature().constData(),
3238 receiver ? receiver->metaObject()->className() : "(nullptr)",
3239 method.methodSignature().constData());
3240 return QMetaObject::Connection(nullptr);
3241 }
3242
3243 int signal_index;
3244 int method_index;
3245 {
3246 int dummy;
3247 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3248 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3249 }
3250
3251 const QMetaObject *smeta = sender->metaObject();
3252 const QMetaObject *rmeta = receiver->metaObject();
3253 if (signal_index == -1) {
3254 qCWarning(lcConnect, "QObject::connect: Can't find signal %s on instance of class %s",
3255 signal.methodSignature().constData(), smeta->className());
3256 return QMetaObject::Connection(nullptr);
3257 }
3258 if (method_index == -1) {
3259 qCWarning(lcConnect, "QObject::connect: Can't find method %s on instance of class %s",
3260 method.methodSignature().constData(), rmeta->className());
3261 return QMetaObject::Connection(nullptr);
3262 }
3263
3264 if (!QMetaObject::checkConnectArgs(signal.methodSignature().constData(),
3265 method.methodSignature().constData())) {
3266 qCWarning(lcConnect,
3267 "QObject::connect: Incompatible sender/receiver arguments"
3268 "\n %s::%s --> %s::%s",
3269 smeta->className(), signal.methodSignature().constData(), rmeta->className(),
3270 method.methodSignature().constData());
3271 return QMetaObject::Connection(nullptr);
3272 }
3273
3274 int *types = nullptr;
3275 if ((type == Qt::QueuedConnection) && !(types = queuedConnectionTypes(signal)))
3276 return QMetaObject::Connection(nullptr);
3277
3278#ifndef QT_NO_DEBUG
3279 check_and_warn_compat(smeta, signal, rmeta, method);
3280#endif
3281 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3282 sender, signal_index, signal.enclosingMetaObject(), receiver, method_index, nullptr, type, types));
3283 return handle;
3284}
3285
3286/*!
3287 \fn bool QObject::connect(const QObject *sender, const char *signal, const char *method, Qt::ConnectionType type) const
3288 \overload connect()
3289 \threadsafe
3290
3291 Connects \a signal from the \a sender object to this object's \a
3292 method.
3293
3294 Equivalent to connect(\a sender, \a signal, \c this, \a method, \a type).
3295
3296 Every connection you make emits a signal, so duplicate connections emit
3297 two signals. You can break a connection using disconnect().
3298
3299 \sa disconnect()
3300*/
3301
3302/*!
3303 \threadsafe
3304
3305 Disconnects \a signal in object \a sender from \a method in object
3306 \a receiver. Returns \c true if the connection is successfully broken;
3307 otherwise returns \c false.
3308
3309 A signal-slot connection is removed when either of the objects
3310 involved are destroyed.
3311
3312 disconnect() is typically used in three ways, as the following
3313 examples demonstrate.
3314 \list 1
3315 \li Disconnect everything connected to an object's signals:
3316
3317 \snippet code/src_corelib_kernel_qobject.cpp 26
3318
3319 equivalent to the non-static overloaded function
3320
3321 \snippet code/src_corelib_kernel_qobject.cpp 27
3322
3323 \li Disconnect everything connected to a specific signal:
3324
3325 \snippet code/src_corelib_kernel_qobject.cpp 28
3326
3327 equivalent to the non-static overloaded function
3328
3329 \snippet code/src_corelib_kernel_qobject.cpp 29
3330
3331 \li Disconnect a specific receiver:
3332
3333 \snippet code/src_corelib_kernel_qobject.cpp 30
3334
3335 equivalent to the non-static overloaded function
3336
3337 \snippet code/src_corelib_kernel_qobject.cpp 31
3338
3339 \endlist
3340
3341 \include includes/qobject.qdocinc disconnect-mismatch
3342 \include includes/qobject.qdocinc disconnect-queued
3343
3344 \nullptr may be used as a wildcard, meaning "any signal", "any receiving
3345 object", or "any slot in the receiving object", respectively.
3346
3347 The \a sender may never be \nullptr. (You cannot disconnect signals
3348 from more than one object in a single call.)
3349
3350 If \a signal is \nullptr, it disconnects \a receiver and \a method from
3351 any signal. If not, only the specified signal is disconnected.
3352
3353 If \a receiver is \nullptr, it disconnects anything connected to \a
3354 signal. If not, slots in objects other than \a receiver are not
3355 disconnected.
3356
3357 If \a method is \nullptr, it disconnects anything that is connected to \a
3358 receiver. If not, only slots named \a method will be disconnected,
3359 and all other slots are left alone. The \a method must be \nullptr
3360 if \a receiver is left out, so you cannot disconnect a
3361 specifically-named slot on all objects.
3362
3363 \include includes/qobject.qdocinc disconnect-all
3364
3365 \sa connect()
3366*/
3367bool QObject::disconnect(const QObject *sender, const char *signal,
3368 const QObject *receiver, const char *method)
3369{
3370 if (sender == nullptr || (receiver == nullptr && method != nullptr)) {
3371 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
3372 return false;
3373 }
3374
3375 const char *signal_arg = signal;
3376 if (signal) {
3377 if (!check_signal_macro(sender, signal, "disconnect", "unbind"))
3378 return false;
3379 ++signal; // skip code
3380 }
3381
3382 const char *method_arg = method;
3383 int membcode = -1;
3384 if (method) {
3385 membcode = extract_code(method);
3386 if (!check_method_code(membcode, receiver, method, "disconnect"))
3387 return false;
3388 ++method; // skip code
3389 }
3390
3391 QByteArray pinnedSignal;
3392 const QMetaObject *smeta = sender->metaObject();
3393 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3394 int signal_index = -1;
3395 QByteArrayView signalName;
3396 QArgumentTypeArray signalTypes;
3397 if (signal) {
3398 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3399 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3400 if (signal_index == -1) {
3401 pinnedSignal = QMetaObject::normalizedSignature(signal);
3402 signal = pinnedSignal.constData();
3403 signalTypes.clear();
3404 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3405 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3406 signalTypes);
3407 }
3408 if (signal_index == -1) {
3409 err_method_notfound(sender, signal_arg, "disconnect");
3410 err_info_about_objects("disconnect", sender, receiver);
3411 return false;
3412 }
3413 }
3414
3415 auto getMethodIndex = [](int code, const QMetaObject *mo, QByteArrayView name,
3416 const QArgumentTypeArray &types) {
3417 switch (code) {
3418 case QSLOT_CODE:
3419 return QMetaObjectPrivate::indexOfSlot(mo, name, types);
3420 case QSIGNAL_CODE:
3421 return QMetaObjectPrivate::indexOfSignal(mo, name, types);
3422 }
3423 return -1;
3424 };
3425
3426 QByteArray pinnedMethod;
3427 const QMetaObject *rmeta = receiver ? receiver->metaObject() : nullptr;
3428 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 7);
3429 int method_index = -1;
3430 QByteArrayView methodName;
3431 QArgumentTypeArray methodTypes;
3432 if (method) {
3433 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3434 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3435 if (method_index == -1) {
3436 pinnedMethod = QMetaObject::normalizedSignature(method);
3437 method = pinnedMethod.constData();
3438 methodTypes.clear();
3439 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3440 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3441 }
3442 if (method_index == -1) {
3443 err_method_notfound(receiver, method_arg, "disconnect");
3444 err_info_about_objects("disconnect", sender, receiver);
3445 return false;
3446 }
3447 }
3448
3449 /* We now iterate through all the sender's and receiver's meta
3450 * objects in order to also disconnect possibly shadowed signals
3451 * and slots with the same signature.
3452 */
3453 bool res = false;
3454 do {
3455 if (signal) {
3456 // Already computed the signal_index for `smeta` above
3457 if (smeta != sender->metaObject()) {
3458 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3459 signalTypes);
3460 }
3461 if (signal_index < 0)
3462 break;
3463 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3464 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3465 }
3466
3467 if (!method) {
3468 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1, nullptr);
3469 } else {
3470 do {
3471 // Already computed the method_index for receiver->metaObject() above
3472 if (rmeta != receiver->metaObject())
3473 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3474 if (method_index >= 0) {
3475#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
3476 check_and_warn_non_slot("disconnect", method, membcode, rmeta,
3477 rmeta->method(method_index));
3478#endif
3479 while (method_index < rmeta->methodOffset())
3480 rmeta = rmeta->superClass();
3481 }
3482 if (method_index < 0)
3483 break;
3484 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index, nullptr);
3485 } while ((rmeta = rmeta->superClass()));
3486 }
3487 } while (signal && (smeta = smeta->superClass()));
3488
3489 if (res) {
3490 if (!signal)
3491 const_cast<QObject *>(sender)->disconnectNotify(QMetaMethod());
3492 }
3493 return res;
3494}
3495
3496/*!
3497 \since 4.8
3498
3499 Disconnects \a signal in object \a sender from \a method in object
3500 \a receiver. Returns \c true if the connection is successfully broken;
3501 otherwise returns \c false.
3502
3503 This function provides the same possibilities like
3504 \c {disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method) }
3505 but uses QMetaMethod to represent the signal and the method to be disconnected.
3506
3507 Additionally this function returns false and no signals and slots disconnected
3508 if:
3509 \list 1
3510
3511 \li \a signal is not a member of sender class or one of its parent classes.
3512
3513 \li \a method is not a member of receiver class or one of its parent classes.
3514
3515 \li \a signal instance represents not a signal.
3516
3517 \endlist
3518
3519 \include includes/qobject.qdocinc disconnect-mismatch
3520 \include includes/qobject.qdocinc disconnect-queued
3521
3522 QMetaMethod() may be used as wildcard in the meaning "any signal" or "any slot in receiving object".
3523 In the same way \nullptr can be used for \a receiver in the meaning "any receiving object".
3524 In this case method should also be QMetaMethod(). \a sender parameter should be never \nullptr.
3525
3526 \include includes/qobject.qdocinc disconnect-all
3527
3528 \sa disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
3529 */
3530bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal,
3531 const QObject *receiver, const QMetaMethod &method)
3532{
3533 if (sender == nullptr || (receiver == nullptr && method.mobj != nullptr)) {
3534 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
3535 return false;
3536 }
3537 if (signal.mobj) {
3538 if (signal.methodType() != QMetaMethod::Signal) {
3539 qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s",
3540 "disconnect","unbind",
3541 sender->metaObject()->className(), signal.methodSignature().constData());
3542 return false;
3543 }
3544 }
3545 if (method.mobj) {
3546 if (method.methodType() == QMetaMethod::Constructor) {
3547 qCWarning(lcConnect, "QObject::disconnect: cannot use constructor as argument %s::%s",
3548 receiver->metaObject()->className(), method.methodSignature().constData());
3549 return false;
3550 }
3551 }
3552
3553 int signal_index;
3554 int method_index;
3555 {
3556 int dummy;
3557 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3558 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3559 }
3560 // If we are here sender is not nullptr. If signal is not nullptr while signal_index
3561 // is -1 then this signal is not a member of sender.
3562 if (signal.mobj && signal_index == -1) {
3563 qCWarning(lcConnect, "QObject::disconnect: signal %s not found on class %s",
3564 signal.methodSignature().constData(), sender->metaObject()->className());
3565 return false;
3566 }
3567 // If this condition is true then method is not a member of receiver.
3568 if (receiver && method.mobj && method_index == -1) {
3569 qCWarning(lcConnect, "QObject::disconnect: method %s not found on class %s",
3570 method.methodSignature().constData(), receiver->metaObject()->className());
3571 return false;
3572 }
3573
3574 if (!QMetaObjectPrivate::disconnect(sender, signal_index, signal.mobj, receiver, method_index, nullptr))
3575 return false;
3576
3577 if (!signal.isValid()) {
3578 // The signal is a wildcard, meaning all signals were disconnected.
3579 // QMetaObjectPrivate::disconnect() doesn't call disconnectNotify()
3580 // per connection in this case. Call it once now, with an invalid
3581 // QMetaMethod as argument, as documented.
3582 const_cast<QObject *>(sender)->disconnectNotify(signal);
3583 }
3584 return true;
3585}
3586
3587/*!
3588 \threadsafe
3589
3590 \fn bool QObject::disconnect(const char *signal, const QObject *receiver, const char *method) const
3591 \overload disconnect()
3592
3593 Disconnects \a signal from \a method of \a receiver.
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 \include includes/qobject.qdocinc disconnect-all
3602*/
3603
3604/*!
3605 \fn bool QObject::disconnect(const QObject *receiver, const char *method) const
3606 \overload disconnect()
3607
3608 Disconnects all signals in this object from \a receiver's \a
3609 method.
3610
3611 \include includes/qobject.qdocinc disconnect-mismatch
3612 \include includes/qobject.qdocinc disconnect-queued
3613
3614 A signal-slot connection is removed when either of the objects
3615 involved are destroyed.
3616*/
3617
3618
3619/*!
3620 \since 5.0
3621
3622 This virtual function is called when something has been connected
3623 to \a signal in this object.
3624
3625 If you want to compare \a signal with a specific signal, you can
3626 use QMetaMethod::fromSignal() as follows:
3627
3628 \snippet code/src_corelib_kernel_qobject.cpp 32
3629
3630 \warning This function violates the object-oriented principle of
3631 modularity. However, it might be useful when you need to perform
3632 an expensive operation only if something is connected to a signal.
3633
3634 \warning This function is called from the thread which performs the
3635 connection, which may be a different thread from the thread in which
3636 this object lives. This function may also be called with a QObject internal
3637 mutex locked. It is therefore not allowed to re-enter any QObject
3638 functions, including isSignalConnected(), from your reimplementation. If
3639 you lock a mutex in your reimplementation, make sure that you don't call
3640 QObject functions with that mutex held in other places or it will result in
3641 a deadlock.
3642
3643 \sa connect(), disconnectNotify()
3644*/
3645
3646void QObject::connectNotify(const QMetaMethod &signal)
3647{
3648 Q_UNUSED(signal);
3649}
3650
3651/*!
3652 \since 5.0
3653
3654 This virtual function is called when something has been
3655 disconnected from \a signal in this object.
3656
3657 See connectNotify() for an example of how to compare
3658 \a signal with a specific signal.
3659
3660 If all signals were disconnected from this object (e.g., the
3661 signal argument to disconnect() was \nullptr), disconnectNotify()
3662 is only called once, and the \a signal will be an invalid
3663 QMetaMethod (QMetaMethod::isValid() returns \c false).
3664
3665 \warning This function violates the object-oriented principle of
3666 modularity. However, it might be useful for optimizing access to
3667 expensive resources.
3668
3669 \warning This function is called from the thread which performs the
3670 disconnection, which may be a different thread from the thread in which
3671 this object lives. This function may also be called with a QObject internal
3672 mutex locked. It is therefore not allowed to re-enter any QObject
3673 functions, including isSignalConnected(), from your reimplementation. If
3674 you lock a mutex in your reimplementation, make sure that you don't call
3675 QObject functions with that mutex held in other places or it will result in
3676 a deadlock.
3677
3678 \sa disconnect(), connectNotify()
3679*/
3680
3681void QObject::disconnectNotify(const QMetaMethod &signal)
3682{
3683 Q_UNUSED(signal);
3684}
3685
3686/*
3687 \internal
3688 convert a signal index from the method range to the signal range
3689 */
3690static int methodIndexToSignalIndex(const QMetaObject **base, int signal_index)
3691{
3692 if (signal_index < 0)
3693 return signal_index;
3694 const QMetaObject *metaObject = *base;
3695 while (metaObject && metaObject->methodOffset() > signal_index)
3696 metaObject = metaObject->superClass();
3697
3698 if (metaObject) {
3699 int signalOffset, methodOffset;
3700 computeOffsets(metaObject, &signalOffset, &methodOffset);
3701 if (signal_index < metaObject->methodCount())
3702 signal_index = QMetaObjectPrivate::originalClone(metaObject, signal_index - methodOffset) + signalOffset;
3703 else
3704 signal_index = signal_index - methodOffset + signalOffset;
3705 *base = metaObject;
3706 }
3707 return signal_index;
3708}
3709
3710/*!
3711 \internal
3712 \a types is a 0-terminated vector of meta types for queued
3713 connections.
3714
3715 if \a signal_index is -1, then we effectively connect *all* signals
3716 from the sender to the receiver's slot
3717 */
3718QMetaObject::Connection QMetaObject::connect(const QObject *sender, int signal_index,
3719 const QObject *receiver, int method_index, int type,
3720 int *types)
3721{
3722 const QMetaObject *smeta = sender->metaObject();
3723 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3724 return Connection(QMetaObjectPrivate::connect(sender, signal_index, smeta,
3725 receiver, method_index,
3726 nullptr, //FIXME, we could speed this connection up by computing the relative index
3727 type, types));
3728}
3729
3730/*!
3731 \internal
3732 Same as the QMetaObject::connect, but \a signal_index must be the result of QObjectPrivate::signalIndex
3733
3734 method_index is relative to the rmeta metaobject, if rmeta is \nullptr, then it is absolute index
3735
3736 the QObjectPrivate::Connection* has a refcount of 2, so it must be passed to a QMetaObject::Connection
3737 */
3738QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender,
3739 int signal_index, const QMetaObject *smeta,
3740 const QObject *receiver, int method_index,
3741 const QMetaObject *rmeta, int type, int *types)
3742{
3743 QObject *s = const_cast<QObject *>(sender);
3744 QObject *r = const_cast<QObject *>(receiver);
3745
3746 int method_offset = rmeta ? rmeta->methodOffset() : 0;
3747 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 6);
3748 QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall : nullptr;
3749
3750 QOrderedMutexLocker locker(signalSlotLock(sender),
3751 signalSlotLock(receiver));
3752
3753 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3754 if (type & Qt::UniqueConnection && scd) {
3755 if (scd->signalVectorCount() > signal_index) {
3756 const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
3757
3758 int method_index_absolute = method_index + method_offset;
3759
3760 while (c2) {
3761 if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute)
3762 return nullptr;
3763 c2 = c2->nextConnectionList.loadRelaxed();
3764 }
3765 }
3766 }
3767 type &= ~Qt::UniqueConnection;
3768
3769 const bool isSingleShot = type & Qt::SingleShotConnection;
3770 type &= ~Qt::SingleShotConnection;
3771
3772 Q_ASSERT(type >= 0);
3773 Q_ASSERT(type <= 3);
3774
3775 std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
3776 c->sender = s;
3777 c->signal_index = signal_index;
3778 c->receiver.storeRelaxed(r);
3779 QThreadData *td = r->d_func()->threadData.loadAcquire();
3780 td->ref();
3781 c->receiverThreadData.storeRelaxed(td);
3782 c->method_relative = method_index;
3783 c->method_offset = method_offset;
3784 c->connectionType = type;
3785 c->isSlotObject = false;
3786 c->argumentTypes.storeRelaxed(types);
3787 c->callFunction = callFunction;
3788 c->isSingleShot = isSingleShot;
3789
3790 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
3791
3792 locker.unlock();
3793 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3794 if (smethod.isValid())
3795 s->connectNotify(smethod);
3796
3797 return c.release();
3798}
3799
3800/*!
3801 \internal
3802 */
3803bool QMetaObject::disconnect(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}
3811
3812/*!
3813 \internal
3814
3815Disconnect a single signal connection. If QMetaObject::connect() has been called
3816multiple times for the same sender, signal_index, receiver and method_index only
3817one of these connections will be removed.
3818 */
3819bool QMetaObject::disconnectOne(const QObject *sender, int signal_index,
3820 const QObject *receiver, int method_index)
3821{
3822 const QMetaObject *smeta = sender->metaObject();
3823 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3824 return QMetaObjectPrivate::disconnect(sender, signal_index, smeta,
3825 receiver, method_index, nullptr,
3826 QMetaObjectPrivate::DisconnectOne);
3827}
3828
3829/*!
3830 \internal
3831 Helper function to remove the connection from the senders list and set the receivers to \nullptr
3832 */
3833bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::ConnectionData *connections, int signalIndex,
3834 const QObject *receiver, int method_index, void **slot,
3835 QBasicMutex *senderMutex, DisconnectType disconnectType)
3836{
3837 bool success = false;
3838
3839 auto &connectionList = connections->connectionsForSignal(signalIndex);
3840 auto *c = connectionList.first.loadRelaxed();
3841 while (c) {
3842 QObject *r = c->receiver.loadRelaxed();
3843 if (r && (receiver == nullptr || (r == receiver
3844 && (method_index < 0 || (!c->isSlotObject && c->method() == method_index))
3845 && (slot == nullptr || (c->isSlotObject && c->slotObj->compare(slot)))))) {
3846 bool needToUnlock = false;
3847 QBasicMutex *receiverMutex = nullptr;
3848 if (r) {
3849 receiverMutex = signalSlotLock(r);
3850 // need to relock this receiver and sender in the correct order
3851 needToUnlock = QOrderedMutexLocker::relock(senderMutex, receiverMutex);
3852 }
3853 if (c->receiver.loadRelaxed())
3854 connections->removeConnection(c);
3855
3856 if (needToUnlock)
3857 receiverMutex->unlock();
3858
3859 success = true;
3860
3861 if (disconnectType == DisconnectOne)
3862 return success;
3863 }
3864 c = c->nextConnectionList.loadRelaxed();
3865 }
3866 return success;
3867}
3868
3869/*!
3870 \internal
3871 Same as the QMetaObject::disconnect, but \a signal_index must be the result of QObjectPrivate::signalIndex
3872 */
3873bool QMetaObjectPrivate::disconnect(const QObject *sender,
3874 int signal_index, const QMetaObject *smeta,
3875 const QObject *receiver, int method_index, void **slot,
3876 DisconnectType disconnectType)
3877{
3878 if (!sender)
3879 return false;
3880
3881 QObject *s = const_cast<QObject *>(sender);
3882
3883 QBasicMutex *senderMutex = signalSlotLock(sender);
3884 QMutexLocker locker(senderMutex);
3885
3886 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3887 if (!scd)
3888 return false;
3889
3890 bool success = false;
3891 {
3892 // prevent incoming connections changing the connections->receivers while unlocked
3893 QObjectPrivate::ConnectionDataPointer connections(scd);
3894
3895 if (signal_index < 0) {
3896 // wildcard disconnect - warn if this disconnects destroyed()
3897 if (!receiver && method_index < 0 && sender->d_func()->isSignalConnected(0)) {
3898 qWarning("QObject::disconnect: wildcard call disconnects from destroyed signal of"
3899 " %s::%s", sender->metaObject()->className(),
3900 sender->objectName().isEmpty()
3901 ? "unnamed"
3902 : sender->objectName().toLocal8Bit().data());
3903 }
3904 // remove from all connection lists
3905 for (int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
3906 if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
3907 success = true;
3908 }
3909 } else if (signal_index < scd->signalVectorCount()) {
3910 if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
3911 success = true;
3912 }
3913 }
3914
3915 locker.unlock();
3916 if (success) {
3917 scd->cleanOrphanedConnections(s);
3918
3919 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3920 if (smethod.isValid())
3921 s->disconnectNotify(smethod);
3922 }
3923
3924 return success;
3925}
3926
3927// Helpers for formatting the connect statements of connectSlotsByName()'s debug mode
3928static QByteArray formatConnectionSignature(const char *className, const QMetaMethod &method)
3929{
3930 const auto signature = method.methodSignature();
3931 Q_ASSERT(signature.endsWith(')'));
3932 const qsizetype openParen = signature.indexOf('(');
3933 const bool hasParameters = openParen > 0 && openParen < signature.size() - 2;
3934 QByteArray result;
3935 if (hasParameters) {
3936 const qsizetype len = signature.size() - openParen - 2;
3937 result += "qOverload<" + QByteArrayView{signature}.slice(openParen + 1, len) + ">(";
3938 }
3939 result += '&';
3940 result += className + QByteArrayLiteral("::") + method.name();
3941 if (hasParameters)
3942 result += ')';
3943 return result;
3944}
3945
3946static QByteArray msgConnect(const QMetaObject *senderMo, const QByteArray &senderName,
3947 const QMetaMethod &signal, const QObject *receiver, int receiverIndex)
3948{
3949 const auto receiverMo = receiver->metaObject();
3950 const auto slot = receiverMo->method(receiverIndex);
3951 QByteArray message = QByteArrayLiteral("QObject::connect(")
3952 + senderName + ", " + formatConnectionSignature(senderMo->className(), signal)
3953 + ", " + receiver->objectName().toLatin1() + ", "
3954 + formatConnectionSignature(receiverMo->className(), slot) + ");";
3955 return message;
3956}
3957
3958/*!
3959 \fn void QMetaObject::connectSlotsByName(QObject *object)
3960
3961 Searches recursively for all child objects of the given \a object, and connects
3962 matching signals from them to slots of \a object that follow the following form:
3963
3964 \snippet code/src_corelib_kernel_qobject.cpp 33
3965
3966 Let's assume our object has a child object of type \c{QPushButton} with
3967 the \l{QObject::objectName}{object name} \c{button1}. The slot to catch the
3968 button's \c{clicked()} signal would be:
3969
3970 \snippet code/src_corelib_kernel_qobject.cpp 34
3971
3972 If \a object itself has a properly set object name, its own signals are also
3973 connected to its respective slots.
3974
3975 \sa QObject::setObjectName()
3976 */
3977void QMetaObject::connectSlotsByName(QObject *o)
3978{
3979 if (!o)
3980 return;
3981 const QMetaObject *mo = o->metaObject();
3982 Q_ASSERT(mo);
3983 const QObjectList list = // list of all objects to look for matching signals including...
3984 o->findChildren<QObject *>() // all children of 'o'...
3985 << o; // and the object 'o' itself
3986
3987 // for each method/slot of o ...
3988 for (int i = 0; i < mo->methodCount(); ++i) {
3989 const QByteArray slotSignature = mo->method(i).methodSignature();
3990 const char *slot = slotSignature.constData();
3991 Q_ASSERT(slot);
3992
3993 // ...that starts with "on_", ...
3994 if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
3995 continue;
3996
3997 // ...we check each object in our list, ...
3998 bool foundIt = false;
3999 for (int j = 0; j < list.size(); ++j) {
4000 const QObject *co = list.at(j);
4001 const QByteArray coName = co->objectName().toLatin1();
4002
4003 // ...discarding those whose objectName is not fitting the pattern "on_<objectName>_...", ...
4004 if (coName.isEmpty() || qstrncmp(slot + 3, coName.constData(), coName.size()) || slot[coName.size()+3] != '_')
4005 continue;
4006
4007 const char *signal = slot + coName.size() + 4; // the 'signal' part of the slot name
4008
4009 // ...for the presence of a matching signal "on_<objectName>_<signal>".
4010 const QMetaObject *smeta;
4011 int sigIndex = co->d_func()->signalIndex(signal, &smeta);
4012 if (sigIndex < 0) {
4013 // if no exactly fitting signal (name + complete parameter type list) could be found
4014 // look for just any signal with the correct name and at least the slot's parameter list.
4015 // Note: if more than one of those signals exist, the one that gets connected is
4016 // chosen 'at random' (order of declaration in source file)
4017 QList<QByteArray> compatibleSignals;
4018 const QMetaObject *smo = co->metaObject();
4019 int sigLen = int(qstrlen(signal)) - 1; // ignore the trailing ')'
4020 for (int k = QMetaObjectPrivate::absoluteSignalCount(smo)-1; k >= 0; --k) {
4021 const QMetaMethod method = QMetaObjectPrivate::signal(smo, k);
4022 if (!qstrncmp(method.methodSignature().constData(), signal, sigLen)) {
4023 smeta = method.enclosingMetaObject();
4024 sigIndex = k;
4025 compatibleSignals.prepend(method.methodSignature());
4026 }
4027 }
4028 if (compatibleSignals.size() > 1)
4029 qCWarning(lcConnectSlotsByName) << "QMetaObject::connectSlotsByName: Connecting slot" << slot
4030 << "with the first of the following compatible signals:" << compatibleSignals;
4031 }
4032
4033 if (sigIndex < 0)
4034 continue;
4035
4036 // we connect it...
4037 if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) {
4038 foundIt = true;
4039 qCDebug(lcConnectSlotsByName, "%s",
4040 msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData());
4041 // ...and stop looking for further objects with the same name.
4042 // Note: the Designer will make sure each object name is unique in the above
4043 // 'list' but other code may create two child objects with the same name. In
4044 // this case one is chosen 'at random'.
4045 break;
4046 }
4047 }
4048 if (foundIt) {
4049 // we found our slot, now skip all overloads
4050 while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
4051 ++i;
4052 } else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
4053 // check if the slot has the following signature: "on_..._...(..."
4054 qsizetype iParen = slotSignature.indexOf('(');
4055 qsizetype iLastUnderscore = slotSignature.lastIndexOf('_', iParen - 1);
4056 if (iLastUnderscore > 3)
4057 qCWarning(lcConnectSlotsByName,
4058 "QMetaObject::connectSlotsByName: No matching signal for %s", slot);
4059 }
4060 }
4061}
4062
4063/*!
4064 \fn template<typename PointerToMemberFunction> QMetaObject::Connection QMetaObject::connect(
4065 const QObject *sender, const QMetaMethod &signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type)
4066
4067 \threadsafe
4068 \overload connect()
4069
4070 \since 6.10
4071
4072 Creates a connection of the given \a type from the \a signal in
4073 the \a sender object to the \a method in the \a receiver object.
4074 Returns a handle to the connection that can be used to disconnect
4075 it later.
4076
4077 The Connection handle will be invalid if it cannot create the
4078 connection, for example, the parameters were invalid.
4079 You can check if the QMetaObject::Connection is valid by casting
4080 it to a bool.
4081 Pass the returned handle to QObject::disconnect() to disconnect
4082 the connection.
4083
4084 A slot can be connected to a given signal if the signal has at
4085 least as many arguments as the slot. There must be an exact match
4086 between the corresponding signal and slot arguments, implicit
4087 conversions and type checking are not handled by this function.
4088 Overloaded slots need to be explicitly be resolved with
4089 help of \l qOverload.
4090 \a signal needs to be the meta-method of a signal, otherwise an
4091 invalid connection will be returned.
4092
4093 \sa QObject::connect(), QObject::disconnect()
4094 */
4095
4096/*!
4097 \fn template<typename Functor> QMetaObject::Connection QMetaObject::connect(
4098 const QObject *sender, const QMetaMethod &signal, const QObject *context, Functor functor, Qt::ConnectionType type)
4099
4100 \threadsafe
4101 \overload connect()
4102
4103 \since 6.10
4104
4105 Creates a connection of a given \a type from \a signal in
4106 \a sender object to \a functor to be placed in a specific event
4107 loop of \a context.
4108 Returns a handle to the connection that can be used to disconnect
4109 it later.
4110 This can be useful for connecting a signal retrieved from
4111 meta-object introspection to a lambda capturing local variables.
4112
4113 \note Qt::UniqueConnections do not work for lambdas, non-member
4114 functions and functors; they only apply to member functions.
4115
4116 The slot function can be any function or functor with with equal
4117 or fewer arguments than the signal. There must be an exact match
4118 between the corresponding signal and slot arguments, implicit
4119 conversions and type checking are not handled by this function.
4120 Overloaded functors need to be explicitly be resolved with
4121 help of \l qOverload.
4122 \a signal needs to be the meta-method of a signal, otherwise an
4123 invalid connection will be returned.
4124
4125 The connection will automatically disconnect if the sender or
4126 the context is destroyed.
4127 However, you should take care that any objects used within
4128 the functor are still alive when the signal is emitted.
4129
4130 \sa QObject::connect(), QObject::disconnect()
4131 */
4132QMetaObject::Connection QMetaObject::connectImpl(const QObject *sender, const QMetaMethod &signal,
4133 const QObject *receiver, void **slot,
4134 QtPrivate::QSlotObjectBase *slotObjRaw, Qt::ConnectionType type)
4135{
4136 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
4137
4138 const QMetaObject *senderMetaObject = sender->metaObject();
4139 if (!signal.isValid() || signal.methodType() != QMetaMethod::Signal) {
4140 connectWarning(sender, senderMetaObject, receiver, "invalid signal parameter");
4141 return QMetaObject::Connection();
4142 }
4143
4144 int signal_index;
4145 {
4146 int dummy;
4147 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
4148 }
4149
4150 if (signal_index == -1) {
4151 qCWarning(lcConnect, "QObject::connect: Can't find signal %s on instance of class %s",
4152 signal.methodSignature().constData(), senderMetaObject->className());
4153 return QMetaObject::Connection();
4154 }
4155
4156 return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj.release(), type, nullptr, senderMetaObject);
4157}
4158
4159/*!
4160 \internal
4161 A small RAII helper for QSlotObjectBase.
4162 Calls ref on construction and destroyLastRef in its dtor.
4163 Allows construction from a nullptr in which case it does nothing.
4164 */
4166 SlotObjectGuard() = default;
4167 // move would be fine, but we do not need it currently
4175
4177 { return m_slotObject.get(); }
4178
4181
4182 ~SlotObjectGuard() = default;
4183private:
4184 QtPrivate::SlotObjUniquePtr m_slotObject;
4185};
4186
4187/*!
4188 \internal
4189
4190 \a signal must be in the signal index range (see QObjectPrivate::signalIndex()).
4191*/
4192static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv)
4193{
4194 const int *argumentTypes = c->argumentTypes.loadRelaxed();
4195 if (!argumentTypes) {
4196 QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
4197 argumentTypes = queuedConnectionTypes(m);
4198 if (!argumentTypes) // cannot queue arguments
4199 argumentTypes = &DIRECT_CONNECTION_ONLY;
4200 if (!c->argumentTypes.testAndSetOrdered(nullptr, argumentTypes)) {
4201 if (argumentTypes != &DIRECT_CONNECTION_ONLY)
4202 delete[] argumentTypes;
4203 argumentTypes = c->argumentTypes.loadRelaxed();
4204 }
4205 }
4206 if (argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate
4207 return;
4208 int nargs = 1; // include return type
4209 while (argumentTypes[nargs - 1])
4210 ++nargs;
4211
4212 QMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
4213 QObject *receiver = c->receiver.loadRelaxed();
4214 if (!receiver) {
4215 // the connection has been disconnected before we got the lock
4216 return;
4217 }
4218
4219 SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj : nullptr };
4220 locker.unlock();
4221
4222 QVarLengthArray<const QtPrivate::QMetaTypeInterface *, 16> argTypes;
4223 argTypes.reserve(nargs);
4224 argTypes.emplace_back(nullptr); // return type
4225 for (int n = 1; n < nargs; ++n) {
4226 argTypes.emplace_back(QMetaType(argumentTypes[n - 1]).iface()); // convert type ids to QMetaTypeInterfaces
4227 }
4228
4229 auto ev = c->isSlotObject ?
4230 std::make_unique<QQueuedMetaCallEvent>(c->slotObj,
4231 sender, signal, nargs, argTypes.data(), argv) :
4232 std::make_unique<QQueuedMetaCallEvent>(c->method_offset, c->method_relative, c->callFunction,
4233 sender, signal, nargs, argTypes.data(), argv);
4234
4235 if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) {
4236 return;
4237 }
4238
4239 locker.relock();
4240 if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
4241 // the connection has been disconnected while we were unlocked
4242 locker.unlock();
4243 return;
4244 }
4245
4246 QCoreApplication::postEvent(receiver, ev.release());
4247}
4248
4249template <bool callbacks_enabled>
4250void doActivate(QObject *sender, int signal_index, void **argv)
4251{
4252 QObjectPrivate *sp = QObjectPrivate::get(sender);
4253
4254 if (sp->blockSig)
4255 return;
4256
4257 Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
4258
4259 if (sp->isDeclarativeSignalConnected(signal_index)
4260 && QAbstractDeclarativeData::signalEmitted) {
4261 Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
4262 QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
4263 signal_index, argv);
4264 }
4265
4266 const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() : nullptr;
4267
4268 void *empty_argv[] = { nullptr };
4269 if (!argv)
4270 argv = empty_argv;
4271
4272 if (!sp->maybeSignalConnected(signal_index)) {
4273 // The possible declarative connection is done, and nothing else is connected
4274 if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
4275 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4276 if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
4277 signal_spy_set->signal_end_callback(sender, signal_index);
4278 return;
4279 }
4280
4281 if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
4282 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4283
4284 bool senderDeleted = false;
4285 {
4286 Q_ASSERT(sp->connections.loadRelaxed());
4287 QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadAcquire());
4288 QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();
4289
4290 const QObjectPrivate::ConnectionList *list;
4291 if (signal_index < signalVector->count())
4292 list = &signalVector->at(signal_index);
4293 else
4294 list = &signalVector->at(-1);
4295
4296 Qt::HANDLE currentThreadId = QThread::currentThreadId();
4297 bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
4298
4299 // We need to check against the highest connection id to ensure that signals added
4300 // during the signal emission are not emitted in this emission.
4301 uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
4302 do {
4303 QObjectPrivate::Connection *c = list->first.loadRelaxed();
4304 if (!c)
4305 continue;
4306
4307 do {
4308 QObject * const receiver = c->receiver.loadRelaxed();
4309 if (!receiver)
4310 continue;
4311
4312 QThreadData *td = c->receiverThreadData.loadRelaxed();
4313 if (!td)
4314 continue;
4315
4316 bool receiverInSameThread;
4317 if (inSenderThread) {
4318 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4319 } else {
4320 // need to lock before reading the threadId, because moveToThread() could interfere
4321 QMutexLocker lock(signalSlotLock(receiver));
4322 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4323 }
4324
4325
4326 // determine if this connection should be sent immediately or
4327 // put into the event queue
4328 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
4329 || (c->connectionType == Qt::QueuedConnection)) {
4330 queued_activate(sender, signal_index, c, argv);
4331 continue;
4332#if QT_CONFIG(thread)
4333 } else if (c->connectionType == Qt::BlockingQueuedConnection) {
4334 if (receiverInSameThread) {
4335 qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
4336 "Sender is %s(%p), receiver is %s(%p)",
4337 sender->metaObject()->className(), sender,
4338 receiver->metaObject()->className(), receiver);
4339 }
4340
4341 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4342 continue;
4343
4344 QLatch latch(1);
4345 {
4346 QMutexLocker locker(signalSlotLock(receiver));
4347 if (!c->isSingleShot && !c->receiver.loadAcquire())
4348 continue;
4349 QMetaCallEvent *ev = c->isSlotObject ?
4350 new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &latch) :
4351 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
4352 sender, signal_index, argv, &latch);
4353 QCoreApplication::postEvent(receiver, ev);
4354 }
4355 latch.wait();
4356 continue;
4357#endif
4358 }
4359
4360 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4361 continue;
4362
4363 QObjectPrivate::Sender senderData(
4364 receiverInSameThread ? receiver : nullptr, sender, signal_index,
4365 receiverInSameThread ? QObjectPrivate::get(receiver)->connections.loadAcquire() : nullptr);
4366
4367 if (c->isSlotObject) {
4368 SlotObjectGuard obj{c->slotObj};
4369
4370 {
4371 Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
4372 obj->call(receiver, argv);
4373 }
4374 } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
4375 //we compare the vtable to make sure we are not in the destructor of the object.
4376 const int method_relative = c->method_relative;
4377 const auto callFunction = c->callFunction;
4378 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
4379 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)
4380 signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
4381
4382 {
4383 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
4384 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
4385 }
4386
4387 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
4388 signal_spy_set->slot_end_callback(receiver, methodIndex);
4389 } else {
4390 const int method = c->method_relative + c->method_offset;
4391
4392 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {
4393 signal_spy_set->slot_begin_callback(receiver, method, argv);
4394 }
4395
4396 {
4397 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
4398 QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
4399 }
4400
4401 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
4402 signal_spy_set->slot_end_callback(receiver, method);
4403 }
4404 } while ((c = c->nextConnectionList.loadRelaxed()) != nullptr && c->id <= highestConnectionId);
4405
4406 } while (list != &signalVector->at(-1) &&
4407 //start over for all signals;
4408 ((list = &signalVector->at(-1)), true));
4409
4410 if (connections->currentConnectionId.loadRelaxed() == 0)
4411 senderDeleted = true;
4412 }
4413 if (!senderDeleted) {
4414 sp->connections.loadAcquire()->cleanOrphanedConnections(sender);
4415
4416 if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
4417 signal_spy_set->signal_end_callback(sender, signal_index);
4418 }
4419}
4420
4421/*!
4422 \internal
4423 */
4424void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
4425 void **argv)
4426{
4427 int signal_index = local_signal_index + QMetaObjectPrivate::signalOffset(m);
4428
4429 if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
4430 doActivate<true>(sender, signal_index, argv);
4431 else
4432 doActivate<false>(sender, signal_index, argv);
4433}
4434
4435/*!
4436 \internal
4437 */
4438void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
4439{
4440 int signal_index = signalOffset + local_signal_index;
4441
4442 if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
4443 doActivate<true>(sender, signal_index, argv);
4444 else
4445 doActivate<false>(sender, signal_index, argv);
4446}
4447
4448/*!
4449 \internal
4450 signal_index comes from indexOfMethod()
4451*/
4452void QMetaObject::activate(QObject *sender, int signal_index, void **argv)
4453{
4454 const QMetaObject *mo = sender->metaObject();
4455 while (mo->methodOffset() > signal_index)
4456 mo = mo->superClass();
4457 activate(sender, mo, signal_index - mo->methodOffset(), argv);
4458}
4459
4460/*!
4461 \internal
4462 Returns the signal index used in the internal connections->receivers vector.
4463
4464 It is different from QMetaObject::indexOfSignal(): indexOfSignal is the same as indexOfMethod
4465 while QObjectPrivate::signalIndex is smaller because it doesn't give index to slots.
4466
4467 If \a meta is not \nullptr, it is set to the meta-object where the signal was found.
4468*/
4469int QObjectPrivate::signalIndex(const char *signalName,
4470 const QMetaObject **meta) const
4471{
4472 Q_Q(const QObject);
4473 const QMetaObject *base = q->metaObject();
4474 Q_ASSERT(QMetaObjectPrivate::get(base)->revision >= 7);
4475 QArgumentTypeArray types;
4476 QByteArrayView name = QMetaObjectPrivate::decodeMethodSignature(signalName, types);
4477 int relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, name, types);
4478 if (relative_index < 0)
4479 return relative_index;
4480 relative_index = QMetaObjectPrivate::originalClone(base, relative_index);
4481 if (meta)
4482 *meta = base;
4483 return relative_index + QMetaObjectPrivate::signalOffset(base);
4484}
4485
4486/*****************************************************************************
4487 Properties
4488 *****************************************************************************/
4489
4490/*!
4491 \fn bool QObject::setProperty(const char *name, const QVariant &value)
4492
4493 Sets the value of the object's \a name property to \a value.
4494
4495 If the property is defined in the class using Q_PROPERTY then
4496 true is returned on success and false otherwise. If the property
4497 is not defined using Q_PROPERTY, and therefore not listed in the
4498 meta-object, it is added as a dynamic property and false is returned.
4499
4500 Information about all available properties is provided through the
4501 metaObject() and dynamicPropertyNames().
4502
4503 Dynamic properties can be queried again using property() and can be
4504 removed by setting the property value to an invalid QVariant.
4505 Changing the value of a dynamic property causes a QDynamicPropertyChangeEvent
4506 to be sent to the object.
4507
4508 \b{Note:} Dynamic properties starting with "_q_" are reserved for internal
4509 purposes.
4510
4511 \sa property(), metaObject(), dynamicPropertyNames(), QMetaProperty::write()
4512*/
4513
4514/*!
4515 \fn bool QObject::setProperty(const char *name, QVariant &&value)
4516 \since 6.6
4517 \overload setProperty
4518*/
4519
4520bool QObject::doSetProperty(const char *name, const QVariant &value, QVariant *rvalue)
4521{
4522 Q_D(QObject);
4523 const QMetaObject *meta = metaObject();
4524 if (!name || !meta)
4525 return false;
4526
4527 int id = meta->indexOfProperty(name);
4528 if (id < 0) {
4529 d->ensureExtraData();
4530
4531 const qsizetype idx = d->extraData->propertyNames.indexOf(name);
4532
4533 if (!value.isValid()) {
4534 if (idx == -1)
4535 return false;
4536 d->extraData->propertyNames.removeAt(idx);
4537 d->extraData->propertyValues.removeAt(idx);
4538 } else {
4539 if (idx == -1) {
4540 d->extraData->propertyNames.append(name);
4541 q_choose_append(d->extraData->propertyValues, value, rvalue);
4542 } else {
4543 if (value.userType() == d->extraData->propertyValues.at(idx).userType()
4544 && value == d->extraData->propertyValues.at(idx))
4545 return false;
4546 q_choose_assign(d->extraData->propertyValues[idx], value, rvalue);
4547 }
4548 }
4549
4550 QDynamicPropertyChangeEvent ev(name);
4551 QCoreApplication::sendEvent(this, &ev);
4552
4553 return false;
4554 }
4555 QMetaProperty p = meta->property(id);
4556#ifndef QT_NO_DEBUG
4557 if (!p.isWritable())
4558 qWarning("%s::setProperty: Property \"%s\" invalid,"
4559 " read-only or does not exist", metaObject()->className(), name);
4560#endif
4561 return rvalue ? p.write(this, std::move(*rvalue)) : p.write(this, value);
4562}
4563
4564/*!
4565 Returns the value of the object's \a name property.
4566
4567 If no such property exists, the returned variant is invalid.
4568
4569 Information about all available properties is provided through the
4570 metaObject() and dynamicPropertyNames().
4571
4572 \sa setProperty(), QVariant::isValid(), metaObject(), dynamicPropertyNames()
4573*/
4574QVariant QObject::property(const char *name) const
4575{
4576 Q_D(const QObject);
4577 const QMetaObject *meta = metaObject();
4578 if (!name || !meta)
4579 return QVariant();
4580
4581 int id = meta->indexOfProperty(name);
4582 if (id < 0) {
4583 if (!d->extraData)
4584 return QVariant();
4585 const qsizetype i = d->extraData->propertyNames.indexOf(name);
4586 return d->extraData->propertyValues.value(i);
4587 }
4588 QMetaProperty p = meta->property(id);
4589#ifndef QT_NO_DEBUG
4590 if (!p.isReadable())
4591 qWarning("%s::property: Property \"%s\" invalid or does not exist",
4592 metaObject()->className(), name);
4593#endif
4594 return p.read(this);
4595}
4596
4597/*!
4598 \since 4.2
4599
4600 Returns the names of all properties that were dynamically added to
4601 the object using setProperty().
4602*/
4603QList<QByteArray> QObject::dynamicPropertyNames() const
4604{
4605 Q_D(const QObject);
4606 if (d->extraData)
4607 return d->extraData->propertyNames;
4608 return QList<QByteArray>();
4609}
4610
4611/*****************************************************************************
4612 QObject debugging output routines.
4613 *****************************************************************************/
4614
4615std::string QObjectPrivate::flagsForDumping() const
4616{
4617 return {};
4618}
4619
4620static void dumpRecursive(int level, const QObject *object)
4621{
4622 if (object) {
4623 const int indent = level * 4;
4624 qDebug("%*s%s::%ls %s", indent, "", object->metaObject()->className(),
4625 qUtf16Printable(object->objectName()),
4626 QObjectPrivate::get(object)->flagsForDumping().c_str());
4627 for (auto child : object->children())
4628 dumpRecursive(level + 1, child);
4629 }
4630}
4631
4632
4633/*!
4634 Dumps a tree of children to the debug output.
4635
4636 \note Before Qt 5.9, this function was not const.
4637
4638 \sa dumpObjectInfo()
4639*/
4640
4641void QObject::dumpObjectTree() const
4642{
4643 dumpRecursive(0, this);
4644}
4645
4646/*!
4647 Dumps information about signal connections, etc. for this object
4648 to the debug output.
4649
4650 \note Before Qt 5.9, this function was not const.
4651
4652 \sa dumpObjectTree()
4653*/
4654
4655void QObject::dumpObjectInfo() const
4656{
4657 qDebug("OBJECT %s::%s", metaObject()->className(),
4658 objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
4659
4660 Q_D(const QObject);
4661 QMutexLocker locker(signalSlotLock(this));
4662
4663 // first, look for connections where this object is the sender
4664 qDebug(" SIGNALS OUT");
4665
4666 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
4667 if (cd && cd->signalVectorCount() > 0) {
4668 QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
4669 for (int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
4670 const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
4671 if (!c)
4672 continue;
4673 const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index);
4674 qDebug(" signal: %s", signal.methodSignature().constData());
4675
4676 // receivers
4677 while (c) {
4678 if (!c->receiver.loadRelaxed()) {
4679 qDebug(" <Disconnected receiver>");
4680 c = c->nextConnectionList.loadRelaxed();
4681 continue;
4682 }
4683 if (c->isSlotObject) {
4684 qDebug(" <functor or function pointer>");
4685 c = c->nextConnectionList.loadRelaxed();
4686 continue;
4687 }
4688 const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
4689 const QMetaMethod method = receiverMetaObject->method(c->method());
4690 qDebug(" --> %s::%s %s",
4691 receiverMetaObject->className(),
4692 c->receiver.loadRelaxed()->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
4693 method.methodSignature().constData());
4694 c = c->nextConnectionList.loadRelaxed();
4695 }
4696 }
4697 } else {
4698 qDebug( " <None>" );
4699 }
4700
4701 // now look for connections where this object is the receiver
4702 qDebug(" SIGNALS IN");
4703
4704 if (cd && cd->senders) {
4705 for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
4706 QByteArray slotName = QByteArrayLiteral("<unknown>");
4707 if (!s->isSlotObject) {
4708 const QMetaMethod slot = metaObject()->method(s->method());
4709 slotName = slot.methodSignature();
4710 }
4711 qDebug(" <-- %s::%s %s",
4712 s->sender->metaObject()->className(),
4713 s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()),
4714 slotName.constData());
4715 }
4716 } else {
4717 qDebug(" <None>");
4718 }
4719}
4720
4721
4722#ifndef QT_NO_DEBUG_STREAM
4723void QObjectPrivate::writeToDebugStream(QDebug &dbg) const
4724{
4725 Q_Q(const QObject);
4726 dbg.nospace() << q->metaObject()->className() << '(' << (const void *)q;
4727 if (!q->objectName().isEmpty())
4728 dbg << ", name = " << q->objectName();
4729 dbg << ')';
4730}
4731
4732QDebug operator<<(QDebug dbg, const QObject *o)
4733{
4734 QDebugStateSaver saver(dbg);
4735 if (!o)
4736 return dbg << "QObject(0x0)";
4737
4738 const QObjectPrivate *d = QObjectPrivate::get(o);
4739 d->writeToDebugStream(dbg);
4740 return dbg;
4741}
4742#endif
4743
4744/*!
4745 \macro Q_CLASSINFO(Name, Value)
4746 \relates QObject
4747
4748 This macro associates extra information to the class, which is available
4749 using QObject::metaObject(). The extra information takes the form of a
4750 \a Name string and a \a Value literal string.
4751
4752 Example:
4753
4754 \snippet code/src_corelib_kernel_qobject.cpp 35
4755
4756 Qt makes use of the macro in \l{Qt D-Bus} and \l{Qt Qml} modules.
4757 For instance, when defining \l{QML Object Types} in C++, you can
4758 designate a property as the \e default one:
4759
4760 \snippet code/doc_src_properties.cpp 7
4761
4762 \sa QMetaObject::classInfo()
4763 \sa {Using Qt D-Bus Adaptors}
4764 \sa {Defining QML Types from C++}
4765*/
4766
4767/*!
4768 \macro Q_INTERFACES(...)
4769 \relates QObject
4770
4771 This macro tells Qt which interfaces the class implements. This
4772 is used when implementing plugins.
4773
4774 \sa Q_DECLARE_INTERFACE(), Q_PLUGIN_METADATA(), {How to Create Qt Plugins}
4775*/
4776
4777/*!
4778 \macro Q_PROPERTY(...)
4779 \relates QObject
4780
4781 This macro is used for declaring properties in classes that
4782 inherit QObject. Properties behave like class data members, but
4783 they have additional features accessible through the \l
4784 {Meta-Object System}.
4785
4786 \snippet code/doc_src_properties.cpp 0
4787
4788 The property name and type and the \c READ function are required.
4789 The type can be any type supported by QVariant, or it can be a
4790 user-defined type. The other items are optional, but a \c WRITE
4791 function is common. The attributes default to true except \c USER,
4792 which defaults to false.
4793
4794 For example:
4795
4796 \snippet code/src_corelib_kernel_qobject.cpp 37
4797
4798 For more details about how to use this macro, and a more detailed
4799 example of its use, see the discussion on \l {Qt's Property System}.
4800
4801 \sa {Qt's Property System}
4802*/
4803
4804/*!
4805 \macro Q_ENUMS(...)
4806 \relates QObject
4807 \deprecated
4808
4809 In new code, you should prefer the use of the Q_ENUM() macro, which makes the
4810 type available also to the meta type system.
4811 For instance, QMetaEnum::fromType() will not work with types declared with Q_ENUMS().
4812
4813 This macro registers one or several enum types to the meta-object
4814 system.
4815
4816 If you want to register an enum that is declared in another class,
4817 the enum must be fully qualified with the name of the class
4818 defining it. In addition, the class \e defining the enum has to
4819 inherit QObject as well as declare the enum using Q_ENUMS().
4820
4821 \sa {Qt's Property System}
4822*/
4823
4824/*!
4825 \macro Q_FLAGS(...)
4826 \relates QObject
4827 \deprecated
4828
4829 This macro registers one or several \l{QFlags}{flags types} with the
4830 meta-object system. It is typically used in a class definition to declare
4831 that values of a given enum can be used as flags and combined using the
4832 bitwise OR operator.
4833
4834 \note This macro takes care of registering individual flag values
4835 with the meta-object system, so it is unnecessary to use Q_ENUMS()
4836 in addition to this macro.
4837
4838 In new code, you should prefer the use of the Q_FLAG() macro, which makes the
4839 type available also to the meta type system.
4840
4841 \sa {Qt's Property System}
4842*/
4843
4844/*!
4845 \macro Q_ENUM(...)
4846 \relates QObject
4847 \since 5.5
4848
4849 This macro registers an enum type with the meta-object system.
4850 It must be placed after the enum declaration in a class that has the Q_OBJECT,
4851 Q_GADGET or Q_GADGET_EXPORT macro. For namespaces use \l Q_ENUM_NS() instead.
4852
4853 For example:
4854
4855 \snippet code/src_corelib_kernel_qobject.cpp 38
4856
4857 Enumerations that are declared with Q_ENUM have their QMetaEnum registered in the
4858 enclosing QMetaObject. You can also use QMetaEnum::fromType() to get the QMetaEnum.
4859
4860 Registered enumerations are automatically registered also to the Qt meta
4861 type system, making them known to QMetaType without the need to use
4862 Q_DECLARE_METATYPE(). This will enable useful features; for example, if used
4863 in a QVariant, you can convert them to strings. Likewise, passing them to
4864 QDebug will print out their names.
4865
4866 Mind that the enum values are stored as signed \c int in the meta object system.
4867 Registering enumerations with values outside the range of values valid for \c int
4868 will lead to overflows and potentially undefined behavior when accessing them through
4869 the meta object system. QML, for example, does access registered enumerations through
4870 the meta object system.
4871
4872 \sa {Qt's Property System}
4873*/
4874
4875
4876/*!
4877 \macro Q_FLAG(...)
4878 \relates QObject
4879 \since 5.5
4880
4881 This macro registers a single \l{QFlags}{flags type} with the
4882 meta-object system. It is typically used in a class definition to declare
4883 that values of a given enum can be used as flags and combined using the
4884 bitwise OR operator. For namespaces use \l Q_FLAG_NS() instead.
4885
4886 The macro must be placed after the enum declaration. The declaration of
4887 the flags type is done using the \l Q_DECLARE_FLAGS() macro.
4888
4889 For example, in QItemSelectionModel, the
4890 \l{QItemSelectionModel::SelectionFlags}{SelectionFlags} flag is
4891 declared in the following way:
4892
4893 \quotefromfile itemmodels/qitemselectionmodel.h
4894
4895 \skipto class Q_CORE_EXPORT QItemSelectionModel
4896 \printuntil Q_OBJECT
4897
4898 \dots
4899
4900 \skipto public:
4901 \printuntil Q_FLAG(SelectionFlags)
4902
4903 \skipuntil Q_DISABLE_COPY
4904 \printto Q_DECLARE_OPERATORS_FOR_FLAGS
4905
4906 \note The Q_FLAG macro takes care of registering individual flag values
4907 with the meta-object system, so it is unnecessary to use Q_ENUM()
4908 in addition to this macro.
4909
4910 \sa {Qt's Property System}
4911*/
4912
4913/*!
4914 \macro Q_ENUM_NS(...)
4915 \relates QObject
4916 \since 5.8
4917
4918 This macro registers an enum type with the meta-object system.
4919 It must be placed after the enum declaration in a namespace that
4920 has the Q_NAMESPACE macro. It is the same as \l Q_ENUM but in a
4921 namespace.
4922
4923 Enumerations that are declared with Q_ENUM_NS have their QMetaEnum
4924 registered in the enclosing QMetaObject. You can also use
4925 QMetaEnum::fromType() to get the QMetaEnum.
4926
4927 Registered enumerations are automatically registered also to the Qt meta
4928 type system, making them known to QMetaType without the need to use
4929 Q_DECLARE_METATYPE(). This will enable useful features; for example, if
4930 used in a QVariant, you can convert them to strings. Likewise, passing them
4931 to QDebug will print out their names.
4932
4933 Mind that the enum values are stored as signed \c int in the meta object system.
4934 Registering enumerations with values outside the range of values valid for \c int
4935 will lead to overflows and potentially undefined behavior when accessing them through
4936 the meta object system. QML, for example, does access registered enumerations through
4937 the meta object system.
4938
4939 \sa {Qt's Property System}
4940*/
4941
4942
4943/*!
4944 \macro Q_FLAG_NS(...)
4945 \relates QObject
4946 \since 5.8
4947
4948 This macro registers a single \l{QFlags}{flags type} with the
4949 meta-object system. It is used in a namespace that has the
4950 Q_NAMESPACE macro, to declare that values of a given enum can be
4951 used as flags and combined using the bitwise OR operator.
4952 It is the same as \l Q_FLAG but in a namespace.
4953
4954 The macro must be placed after the enum declaration.
4955
4956 \note The Q_FLAG_NS macro takes care of registering individual flag
4957 values with the meta-object system, so it is unnecessary to use
4958 Q_ENUM_NS() in addition to this macro.
4959
4960 \sa {Qt's Property System}
4961*/
4962
4963/*!
4964 \macro Q_OBJECT
4965 \relates QObject
4966
4967 The Q_OBJECT macro is used to enable meta-object features, such as dynamic
4968 properties, signals, and slots.
4969
4970 You can add the Q_OBJECT macro to any section of a class definition that
4971 declares its own signals and slots or that uses other services provided by
4972 Qt's meta-object system.
4973
4974//! [qobject-macros-private-access-specifier]
4975 \note This macro expansion ends with a \c private: access specifier. If you
4976 declare members immediately after this macro, those members will also be
4977 private. To add public (or protected) members right after the macro, use a
4978 \c {public:} (or \c {protected:}) access specifier.
4979//! [qobject-macros-private-access-specifier]
4980
4981 Example:
4982
4983 \snippet signalsandslots/signalsandslots.h 1
4984 \codeline
4985 \snippet signalsandslots/signalsandslots.h 2
4986 \snippet signalsandslots/signalsandslots.h 3
4987
4988 \note This macro requires the class to be a subclass of QObject. Use
4989 Q_GADGET or Q_GADGET_EXPORT instead of Q_OBJECT to enable the meta object
4990 system's support for enums in a class that is not a QObject subclass.
4991
4992 \sa {Meta-Object System}, {Signals and Slots}, {Qt's Property System}
4993*/
4994
4995/*!
4996 \macro Q_GADGET
4997 \relates QObject
4998
4999 The Q_GADGET macro is a lighter version of the Q_OBJECT macro for classes
5000 that do not inherit from QObject but still want to use some of the
5001 reflection capabilities offered by QMetaObject.
5002
5003 \include qobject.cpp qobject-macros-private-access-specifier
5004
5005 Q_GADGETs can have Q_ENUM, Q_PROPERTY and Q_INVOKABLE, but they cannot have
5006 signals or slots.
5007
5008 Q_GADGET makes a class member, \c{staticMetaObject}, available.
5009 \c{staticMetaObject} is of type QMetaObject and provides access to the
5010 enums declared with Q_ENUM.
5011
5012 \sa Q_GADGET_EXPORT
5013*/
5014
5015/*!
5016 \macro Q_GADGET_EXPORT(EXPORT_MACRO)
5017 \relates QObject
5018 \since 6.3
5019
5020 The Q_GADGET_EXPORT macro works exactly like the Q_GADGET macro.
5021 However, the \c{staticMetaObject} variable that is made available (see
5022 Q_GADGET) is declared with the supplied \a EXPORT_MACRO qualifier. This is
5023 useful if the object needs to be exported from a dynamic library, but the
5024 enclosing class as a whole should not be (e.g. because it consists of mostly
5025 inline functions).
5026
5027 \include qobject.cpp qobject-macros-private-access-specifier
5028
5029 For example:
5030
5031 \code
5032 class Point {
5033 Q_GADGET_EXPORT(EXPORT_MACRO)
5034 Q_PROPERTY(int x MEMBER x)
5035 Q_PROPERTY(int y MEMBER y)
5036 ~~~
5037 \endcode
5038
5039 \sa Q_GADGET, {Creating Shared Libraries}
5040*/
5041
5042/*!
5043 \macro Q_NAMESPACE
5044 \relates QObject
5045 \since 5.8
5046
5047 The Q_NAMESPACE macro can be used to add QMetaObject capabilities
5048 to a namespace.
5049
5050 Q_NAMESPACEs can have Q_CLASSINFO, Q_ENUM_NS, Q_FLAG_NS, but they
5051 cannot have Q_ENUM, Q_FLAG, Q_PROPERTY, Q_INVOKABLE, signals nor slots.
5052
5053 Q_NAMESPACE makes an external variable, \c{staticMetaObject}, available.
5054 \c{staticMetaObject} is of type QMetaObject and provides access to the
5055 enums declared with Q_ENUM_NS/Q_FLAG_NS.
5056
5057 For example:
5058
5059 \code
5060 namespace test {
5061 Q_NAMESPACE
5062 ...
5063 \endcode
5064
5065 \sa Q_NAMESPACE_EXPORT
5066*/
5067
5068/*!
5069 \macro Q_NAMESPACE_EXPORT(EXPORT_MACRO)
5070 \relates QObject
5071 \since 5.14
5072
5073 The Q_NAMESPACE_EXPORT macro can be used to add QMetaObject capabilities
5074 to a namespace.
5075
5076 It works exactly like the Q_NAMESPACE macro. However, the external
5077 \c{staticMetaObject} variable that gets defined in the namespace
5078 is declared with the supplied \a EXPORT_MACRO qualifier. This is
5079 useful if the object needs to be exported from a dynamic library.
5080
5081 For example:
5082
5083 \code
5084 namespace test {
5085 Q_NAMESPACE_EXPORT(EXPORT_MACRO)
5086 ...
5087 \endcode
5088
5089 \sa Q_NAMESPACE, {Creating Shared Libraries}
5090*/
5091
5092/*!
5093 \macro Q_MOC_INCLUDE
5094 \relates QObject
5095 \since 6.0
5096
5097 The Q_MOC_INCLUDE macro can be used within or outside a class, and tell the
5098 \l{moc}{Meta Object Compiler} to add an include.
5099
5100 \code
5101 // Put this in your code and the generated code will include this header.
5102 Q_MOC_INCLUDE("myheader.h")
5103 \endcode
5104
5105 This is useful if the types you use as properties or signal/slots arguments
5106 are forward declared.
5107*/
5108
5109/*!
5110 \macro Q_SIGNALS
5111 \relates QObject
5112
5113 Use this macro to replace the \c signals keyword in class
5114 declarations, when you want to use Qt Signals and Slots with a
5115 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5116
5117 The macro is normally used when \c no_keywords is specified with
5118 the \c CONFIG variable in the \c .pro file, but it can be used
5119 even when \c no_keywords is \e not specified.
5120*/
5121
5122/*!
5123 \macro Q_SIGNAL
5124 \relates QObject
5125
5126 This is an additional macro that allows you to mark a single
5127 function as a signal. It can be quite useful, especially when you
5128 use a 3rd-party source code parser which doesn't understand a \c
5129 signals or \c Q_SIGNALS groups.
5130
5131 Use this macro to replace the \c signals keyword in class
5132 declarations, when you want to use Qt Signals and Slots with a
5133 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5134
5135 The macro is normally used when \c no_keywords is specified with
5136 the \c CONFIG variable in the \c .pro file, but it can be used
5137 even when \c no_keywords is \e not specified.
5138*/
5139
5140/*!
5141 \macro Q_SLOTS
5142 \relates QObject
5143
5144 Use this macro to replace the \c slots keyword in class
5145 declarations, when you want to use Qt Signals and Slots with a
5146 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5147
5148 The macro is normally used when \c no_keywords is specified with
5149 the \c CONFIG variable in the \c .pro file, but it can be used
5150 even when \c no_keywords is \e not specified.
5151*/
5152
5153/*!
5154 \macro Q_SLOT
5155 \relates QObject
5156
5157 This is an additional macro that allows you to mark a single
5158 function as a slot. It can be quite useful, especially when you
5159 use a 3rd-party source code parser which doesn't understand a \c
5160 slots or \c Q_SLOTS groups.
5161
5162 Use this macro to replace the \c slots keyword in class
5163 declarations, when you want to use Qt Signals and Slots with a
5164 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5165
5166 The macro is normally used when \c no_keywords is specified with
5167 the \c CONFIG variable in the \c .pro file, but it can be used
5168 even when \c no_keywords is \e not specified.
5169*/
5170
5171/*!
5172 \macro Q_EMIT
5173 \relates QObject
5174
5175 Use this macro to replace the \c emit keyword for emitting
5176 signals, when you want to use Qt Signals and Slots with a
5177 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5178
5179 The macro is normally used when \c no_keywords is specified with
5180 the \c CONFIG variable in the \c .pro file, but it can be used
5181 even when \c no_keywords is \e not specified.
5182*/
5183
5184/*!
5185 \macro Q_INVOKABLE
5186 \relates QObject
5187
5188 Apply this macro to declarations of member functions to allow them to
5189 be invoked via the meta-object system. The macro is written before
5190 the return type, as shown in the following example:
5191
5192 \snippet qmetaobject-invokable/window.h Window class with invokable method
5193
5194 The \c invokableMethod() function is marked up using Q_INVOKABLE, causing
5195 it to be registered with the meta-object system and enabling it to be
5196 invoked using QMetaObject::invokeMethod().
5197 Since \c normalMethod() function is not registered in this way, it cannot
5198 be invoked using QMetaObject::invokeMethod().
5199
5200 If an invokable member function returns a pointer to a QObject or a
5201 subclass of QObject and it is invoked from QML, special ownership rules
5202 apply. See \l{qtqml-cppintegration-data.html}{Data Type Conversion Between QML and C++}
5203 for more information.
5204*/
5205
5206/*!
5207 \macro Q_REVISION
5208 \relates QObject
5209
5210 Apply this macro to declarations of member functions to tag them with a
5211 revision number in the meta-object system. The macro is written before
5212 the return type, as shown in the following example:
5213
5214 \snippet qmetaobject-revision/window.h Window class with revision
5215
5216 This is useful when using the meta-object system to dynamically expose
5217 objects to another API, as you can match the version expected by multiple
5218 versions of the other API. Consider the following simplified example:
5219
5220 \snippet qmetaobject-revision/main.cpp Window class using revision
5221
5222 Using the same Window class as the previous example, the newProperty and
5223 newMethod would only be exposed in this code when the expected version is
5224 \c{2.1} or greater.
5225
5226 Since all methods are considered to be in revision \c{0} if untagged, a tag
5227 of \c{Q_REVISION(0)} or \c{Q_REVISION(0, 0)} is invalid and ignored.
5228
5229 You can pass one or two integer parameters to \c{Q_REVISION}. If you pass
5230 one parameter, it denotes the minor version only. This means that the major
5231 version is unspecified. If you pass two, the first parameter is the major
5232 version and the second parameter is the minor version.
5233
5234 This tag is not used by the meta-object system itself. Currently this is only
5235 used by the QtQml module.
5236
5237 For a more generic string tag, see \l QMetaMethod::tag()
5238
5239 \sa QMetaMethod::revision()
5240*/
5241
5242/*!
5243 \macro Q_SET_OBJECT_NAME(Object)
5244 \relates QObject
5245 \since 5.0
5246
5247 This macro assigns \a Object the objectName "Object".
5248
5249 It doesn't matter whether \a Object is a pointer or not, the
5250 macro figures that out by itself.
5251
5252 \sa QObject::objectName()
5253*/
5254
5255/*!
5256 \macro QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
5257 \relates QObject
5258 \since 5.8
5259
5260 Defining this macro will disable narrowing and floating-point-to-integral
5261 conversions between the arguments carried by a signal and the arguments
5262 accepted by a slot, when the signal and the slot are connected using the
5263 PMF-based syntax.
5264
5265 \sa QObject::connect
5266*/
5267
5268/*!
5269 \macro QT_NO_CONTEXTLESS_CONNECT
5270 \relates QObject
5271 \since 6.7
5272
5273 Defining this macro will disable the overload of QObject::connect() that
5274 connects a signal to a functor, without also specifying a QObject
5275 as a receiver/context object (that is, the 3-arguments overload
5276 of QObject::connect()).
5277
5278 Using the context-less overload is error prone, because it is easy
5279 to connect to functors that depend on some local state of the
5280 receiving end. If such local state gets destroyed, the connection
5281 does not get automatically disconnected.
5282
5283 Moreover, such connections are always direct connections, which may
5284 cause issues in multithreaded scenarios (for instance, if the
5285 signal is emitted from another thread).
5286
5287 \sa QObject::connect, Qt::ConnectionType
5288*/
5289
5290/*!
5291 \typedef QObjectList
5292 \relates QObject
5293
5294 Synonym for QList<QObject *>.
5295*/
5296
5297/*!
5298 \fn template<typename PointerToMemberFunction> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type)
5299 \overload connect()
5300 \threadsafe
5301
5302 Creates a connection of the given \a type from the \a signal in
5303 the \a sender object to the \a method in the \a receiver object.
5304 Returns a handle to the connection that can be used to disconnect
5305 it later.
5306
5307 The signal must be a function declared as a signal in the header.
5308 The slot function can be any member function that can be connected
5309 to the signal.
5310 A slot can be connected to a given signal if the signal has at
5311 least as many arguments as the slot, and there is an implicit
5312 conversion between the types of the corresponding arguments in the
5313 signal and the slot.
5314
5315 Example:
5316
5317 \snippet code/src_corelib_kernel_qobject.cpp 44
5318
5319 This example ensures that the label always displays the current
5320 line edit text.
5321
5322 A signal can be connected to many slots and signals. Many signals
5323 can be connected to one slot.
5324
5325 If a signal is connected to several slots, the slots are activated
5326 in the same order as the order the connection was made, when the
5327 signal is emitted
5328
5329 The function returns an handle to a connection if it successfully
5330 connects the signal to the slot. The Connection handle will be invalid
5331 if it cannot create the connection, for example, if QObject is unable
5332 to verify the existence of \a signal (if it was not declared as a signal)
5333 You can check if the QMetaObject::Connection is valid by casting it to a bool.
5334
5335 By default, a signal is emitted for every connection you make;
5336 two signals are emitted for duplicate connections. You can break
5337 all of these connections with a single disconnect() call.
5338 If you pass the Qt::UniqueConnection \a type, the connection will only
5339 be made if it is not a duplicate. If there is already a duplicate
5340 (exact same signal to the exact same slot on the same objects),
5341 the connection will fail and connect will return an invalid QMetaObject::Connection.
5342
5343 The optional \a type parameter describes the type of connection
5344 to establish. In particular, it determines whether a particular
5345 signal is delivered to a slot immediately or queued for delivery
5346 at a later time. If the signal is queued, the parameters must be
5347 of types that are known to Qt's meta-object system, because Qt
5348 needs to copy the arguments to store them in an event behind the
5349 scenes. If you try to use a queued connection and get the error
5350 message
5351
5352 \snippet code/src_corelib_kernel_qobject.cpp 25
5353
5354 make sure to declare the argument type with Q_DECLARE_METATYPE
5355
5356 Overloaded functions can be resolved with help of \l qOverload.
5357
5358 \sa {Differences between String-Based and Functor-Based Connections}
5359 */
5360
5361/*!
5362 \fn template<typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
5363
5364 \threadsafe
5365 \overload connect()
5366
5367 Creates a connection from \a signal in
5368 \a sender object to \a functor, and returns a handle to the connection
5369
5370 The signal must be a function declared as a signal in the header.
5371 The slot function can be any function or functor that can be connected
5372 to the signal.
5373 A slot function can be connected to a given signal if the signal has at
5374 least as many arguments as the slot function. There must exist implicit
5375 conversion between the types of the corresponding arguments in the
5376 signal and the slot.
5377
5378 Example:
5379
5380 \snippet code/src_corelib_kernel_qobject.cpp 45
5381
5382 Lambda expressions can also be used:
5383
5384 \snippet code/src_corelib_kernel_qobject.cpp 46
5385
5386 The connection will automatically disconnect if the sender is destroyed.
5387 However, you should take care that any objects used within the functor
5388 are still alive when the signal is emitted.
5389
5390 For this reason, it is recommended to use the overload of connect()
5391 that also takes a QObject as a receiver/context. It is possible
5392 to disable the usage of the context-less overload by defining the
5393 \c{QT_NO_CONTEXTLESS_CONNECT} macro.
5394
5395 Overloaded functions can be resolved with help of \l qOverload.
5396
5397 */
5398
5399/*!
5400 \fn template<typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type)
5401
5402 \threadsafe
5403 \overload connect()
5404
5405 \since 5.2
5406
5407 Creates a connection of a given \a type from \a signal in
5408 \a sender object to \a functor to be placed in a specific event
5409 loop of \a context, and returns a handle to the connection.
5410
5411 \note Qt::UniqueConnections do not work for lambdas, non-member functions
5412 and functors; they only apply to connecting to member functions.
5413
5414 The signal must be a function declared as a signal in the header.
5415 The slot function can be any function or functor that can be connected
5416 to the signal.
5417 A slot function can be connected to a given signal if the signal has at
5418 least as many arguments as the slot function. There must exist implicit
5419 conversion between the types of the corresponding arguments in the
5420 signal and the slot.
5421
5422 Example:
5423
5424 \snippet code/src_corelib_kernel_qobject.cpp 50_someFunction
5425 \snippet code/src_corelib_kernel_qobject.cpp 50
5426
5427 Lambda expressions can also be used:
5428
5429 \snippet code/src_corelib_kernel_qobject.cpp 51
5430
5431 The connection will automatically disconnect if the sender or the context
5432 is destroyed.
5433 However, you should take care that any objects used within the functor
5434 are still alive when the signal is emitted.
5435
5436 Overloaded functions can be resolved with help of \l qOverload.
5437 */
5438
5439/*!
5440 \internal
5441
5442 Implementation of the template version of connect
5443
5444 \a sender is the sender object
5445 \a signal is a pointer to a pointer to a member signal of the sender
5446 \a receiver is the receiver object, may not be \nullptr, will be equal to sender when
5447 connecting to a static function or a functor
5448 \a slot a pointer only used when using Qt::UniqueConnection
5449 \a type the Qt::ConnectionType passed as argument to connect
5450 \a types an array of integer with the metatype id of the parameter of the signal
5451 to be used with queued connection
5452 must stay valid at least for the whole time of the connection, this function
5453 do not take ownership. typically static data.
5454 If \nullptr, then the types will be computed when the signal is emit in a queued
5455 connection from the types from the signature.
5456 \a senderMetaObject is the metaobject used to lookup the signal, the signal must be in
5457 this metaobject
5458 */
5459QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,
5460 const QObject *receiver, void **slot,
5461 QtPrivate::QSlotObjectBase *slotObjRaw, Qt::ConnectionType type,
5462 const int *types, const QMetaObject *senderMetaObject)
5463{
5464 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5465 if (!signal) {
5466 connectWarning(sender, senderMetaObject, receiver, "invalid nullptr parameter");
5467 return QMetaObject::Connection();
5468 }
5469
5470 int signal_index = -1;
5471 void *args[] = { &signal_index, signal };
5472 for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
5473 senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
5474 if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
5475 break;
5476 }
5477 if (!senderMetaObject) {
5478 connectWarning(sender, senderMetaObject, receiver, "signal not found");
5479 return QMetaObject::Connection(nullptr);
5480 }
5481 signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
5482 return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj.release(), type, types, senderMetaObject);
5483}
5484
5485/*!
5486 \internal
5487
5488 Internal version of connect used by the template version of QObject::connect (called via connectImpl) and
5489 also used by the QObjectPrivate::connect version used by QML. The signal_index is expected to be relative
5490 to the number of signals.
5491 */
5492QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index,
5493 const QObject *receiver, void **slot,
5494 QtPrivate::QSlotObjectBase *slotObjRaw, int type,
5495 const int *types, const QMetaObject *senderMetaObject)
5496{
5497 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5498
5499 if (!sender || !receiver || !slotObj || !senderMetaObject) {
5500 connectWarning(sender, senderMetaObject, receiver, "invalid nullptr parameter");
5501 return QMetaObject::Connection();
5502 }
5503
5504 if (type & Qt::UniqueConnection && !slot) {
5505 connectWarning(sender, senderMetaObject, receiver, "unique connections require a pointer to member function of a QObject subclass");
5506 return QMetaObject::Connection();
5507 }
5508
5509 QObject *s = const_cast<QObject *>(sender);
5510 QObject *r = const_cast<QObject *>(receiver);
5511
5512 QOrderedMutexLocker locker(signalSlotLock(sender),
5513 signalSlotLock(receiver));
5514
5515 if (type & Qt::UniqueConnection) {
5516 QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
5517 if (connections && connections->signalVectorCount() > signal_index) {
5518 const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
5519
5520 while (c2) {
5521 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot))
5522 return QMetaObject::Connection();
5523 c2 = c2->nextConnectionList.loadRelaxed();
5524 }
5525 }
5526 }
5527 type &= ~Qt::UniqueConnection;
5528
5529 const bool isSingleShot = type & Qt::SingleShotConnection;
5530 type &= ~Qt::SingleShotConnection;
5531
5532 Q_ASSERT(type >= 0);
5533 Q_ASSERT(type <= 3);
5534
5535 std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
5536 c->sender = s;
5537 c->signal_index = signal_index;
5538 QThreadData *td = r->d_func()->threadData.loadAcquire();
5539 td->ref();
5540 c->receiverThreadData.storeRelaxed(td);
5541 c->receiver.storeRelaxed(r);
5542 c->connectionType = type;
5543 c->isSlotObject = true;
5544 c->slotObj = slotObj.release();
5545 if (types) {
5546 c->argumentTypes.storeRelaxed(types);
5547 c->ownArgumentTypes = false;
5548 }
5549 c->isSingleShot = isSingleShot;
5550
5551 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
5552 QMetaObject::Connection ret(c.release());
5553 locker.unlock();
5554
5555 QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
5556 Q_ASSERT(method.isValid());
5557 s->connectNotify(method);
5558
5559 return ret;
5560}
5561
5562/*!
5563 Disconnect a connection.
5564
5565 If the \a connection is invalid or has already been disconnected, do nothing
5566 and return false.
5567
5568 \sa connect()
5569 */
5570bool QObject::disconnect(const QMetaObject::Connection &connection)
5571{
5572 QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(connection.d_ptr);
5573 if (!c)
5574 return false;
5575 const bool disconnected = QObjectPrivate::removeConnection(c);
5576 const_cast<QMetaObject::Connection &>(connection).d_ptr = nullptr;
5577 c->deref(); // has been removed from the QMetaObject::Connection object
5578 return disconnected;
5579}
5580
5581/*! \fn template<typename PointerToMemberFunction> bool QObject::disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method)
5582 \overload disconnect()
5583 \threadsafe
5584
5585 Disconnects \a signal in object \a sender from \a method in object
5586 \a receiver. Returns \c true if the connection is successfully broken;
5587 otherwise returns \c false.
5588
5589 A signal-slot connection is removed when either of the objects
5590 involved are destroyed.
5591
5592 disconnect() is typically used in three ways, as the following
5593 examples demonstrate.
5594 \list 1
5595 \li Disconnect everything connected to an object's signals:
5596
5597 \snippet code/src_corelib_kernel_qobject.cpp 26
5598
5599 \li Disconnect everything connected to a specific signal:
5600
5601 \snippet code/src_corelib_kernel_qobject.cpp 47
5602
5603 \li Disconnect a specific receiver:
5604
5605 \snippet code/src_corelib_kernel_qobject.cpp 30
5606
5607 \li Disconnect a connection from one specific signal to a specific slot:
5608
5609 \snippet code/src_corelib_kernel_qobject.cpp 48
5610
5611
5612 \endlist
5613
5614 \nullptr may be used as a wildcard, meaning "any signal", "any receiving
5615 object", or "any slot in the receiving object", respectively.
5616
5617 The \a sender may never be \nullptr. (You cannot disconnect signals
5618 from more than one object in a single call.)
5619
5620 If \a signal is \nullptr, it disconnects \a receiver and \a method from
5621 any signal. If not, only the specified signal is disconnected.
5622
5623 If \a receiver is \nullptr, it disconnects anything connected to \a
5624 signal. If not, only slots in the specified receiver are disconnected.
5625 disconnect() with a non-null \a receiver also disconnects slot functions
5626 that were connected with \a receiver as their context object.
5627
5628 If \a method is \nullptr, it disconnects anything that is connected to \a
5629 receiver. If not, only slots named \a method will be disconnected,
5630 and all other slots are left alone. The \a method must be \nullptr
5631 if \a receiver is left out, so you cannot disconnect a
5632 specifically-named slot on all objects.
5633
5634 \note It is not possible to use this overload to disconnect signals
5635 connected to functors or lambda expressions. That is because it is not
5636 possible to compare them. Instead, use the overload that takes a
5637 QMetaObject::Connection.
5638
5639 \note Unless \a method is \nullptr, this function will also not break
5640 connections that were made using the string-based version of connect(). To
5641 break such connections, use the corresponding string-based overload of
5642 disconnect().
5643
5644 \sa connect()
5645*/
5646
5647bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot, const QMetaObject *senderMetaObject)
5648{
5649 if (sender == nullptr || (receiver == nullptr && slot != nullptr)) {
5650 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
5651 return false;
5652 }
5653
5654 int signal_index = -1;
5655 if (signal) {
5656 void *args[] = { &signal_index, signal };
5657 for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
5658 senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
5659 if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
5660 break;
5661 }
5662 if (!senderMetaObject) {
5663 qCWarning(lcConnect, "QObject::disconnect: signal not found in %s", sender->metaObject()->className());
5664 return false;
5665 }
5666 signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
5667 }
5668
5669 return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1, slot);
5670}
5671
5672/*!
5673 \internal
5674 Used by QML to connect a signal by index to a slot implemented in JavaScript
5675 (wrapped in a custom QSlotObjectBase subclass).
5676
5677 This version of connect assumes that sender and receiver are the same object.
5678
5679 The signal_index is an index relative to the number of methods.
5680 */
5681QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type)
5682{
5683 return QObjectPrivate::connect(sender, signal_index, sender, slotObj, type);
5684}
5685
5686/*!
5687 \internal
5688 Used by QML to connect a signal by index to a slot implemented in JavaScript
5689 (wrapped in a custom QSlotObjectBase subclass).
5690
5691 This is an overload that should be used when \a sender and \a receiver are
5692 different objects.
5693
5694 The signal_index is an index relative to the number of methods.
5695 */
5696QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index,
5697 const QObject *receiver,
5698 QtPrivate::QSlotObjectBase *slotObjRaw,
5699 Qt::ConnectionType type)
5700{
5701 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5702 if (!sender) {
5703 connectWarning(sender, nullptr, receiver, "invalid nullptr parameter");
5704 return QMetaObject::Connection();
5705 }
5706 const QMetaObject *senderMetaObject = sender->metaObject();
5707 signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
5708
5709 return connectImpl(sender, signal_index, receiver, /*slot*/ nullptr, slotObj.release(),
5710 type, /*types*/ nullptr, senderMetaObject);
5711}
5712
5713/*!
5714 \internal
5715 Used by QML to disconnect a signal by index that's connected to a slot implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass)
5716 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
5717 required for the disconnect.
5718
5719 This version of disconnect assumes that sender and receiver are the same object.
5720 */
5721bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, void **slot)
5722{
5723 return QObjectPrivate::disconnect(sender, signal_index, sender, slot);
5724}
5725
5726/*!
5727 \internal
5728
5729 Used by QML to disconnect a signal by index that's connected to a slot
5730 implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass) In the
5731 QML case the slot is not a pointer to a pointer to the function to disconnect,
5732 but instead it is a pointer to an array of internal values required for the
5733 disconnect.
5734
5735 This is an overload that should be used when \a sender and \a receiver are
5736 different objects.
5737 */
5738bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, const QObject *receiver,
5739 void **slot)
5740{
5741 const QMetaObject *senderMetaObject = sender->metaObject();
5742 signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
5743
5744 return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1,
5745 slot);
5746}
5747
5748/*!
5749 \internal
5750 \threadsafe
5751*/
5752inline bool QObjectPrivate::removeConnection(QObjectPrivate::Connection *c)
5753{
5754 if (!c)
5755 return false;
5756 QObject *receiver = c->receiver.loadRelaxed();
5757 if (!receiver)
5758 return false;
5759
5760 QBasicMutex *senderMutex = signalSlotLock(c->sender);
5761 QBasicMutex *receiverMutex = signalSlotLock(receiver);
5762
5763 QObjectPrivate::ConnectionData *connections;
5764 {
5765 QOrderedMutexLocker locker(senderMutex, receiverMutex);
5766
5767 // load receiver once again and recheck to ensure nobody else has removed the connection in the meantime
5768 receiver = c->receiver.loadRelaxed();
5769 if (!receiver)
5770 return false;
5771
5772 connections = QObjectPrivate::get(c->sender)->connections.loadRelaxed();
5773 Q_ASSERT(connections);
5774 connections->removeConnection(c);
5775
5776 c->sender->disconnectNotify(QMetaObjectPrivate::signal(c->sender->metaObject(), c->signal_index));
5777 // We must not hold the receiver mutex, else we risk dead-locking; we also only need the sender mutex
5778 // It is however vital to hold the senderMutex before calling cleanOrphanedConnections, as otherwise
5779 // another thread might modify/delete the connection
5780 if (receiverMutex != senderMutex) {
5781 receiverMutex->unlock();
5782 }
5783 connections->cleanOrphanedConnections(c->sender, ConnectionData::AlreadyLockedAndTemporarilyReleasingLock);
5784 senderMutex->unlock(); // now both sender and receiver mutex have been manually unlocked
5785 locker.dismiss(); // so we dismiss the QOrderedMutexLocker
5786 }
5787
5788 return true;
5789}
5790
5791/*!
5792 \internal
5793
5794 Used by QPropertyAdaptorSlotObject to get an existing instance for a property, if available
5795 */
5796QtPrivate::QPropertyAdaptorSlotObject *
5797QObjectPrivate::getPropertyAdaptorSlotObject(const QMetaProperty &property)
5798{
5799 if (auto conns = connections.loadAcquire()) {
5800 Q_Q(QObject);
5801 const QMetaObject *metaObject = q->metaObject();
5802 int signal_index = methodIndexToSignalIndex(&metaObject, property.notifySignalIndex());
5803 if (signal_index >= conns->signalVectorCount())
5804 return nullptr;
5805 const auto &connectionList = conns->connectionsForSignal(signal_index);
5806 for (auto c = connectionList.first.loadRelaxed(); c;
5807 c = c->nextConnectionList.loadRelaxed()) {
5808 if (c->isSlotObject) {
5809 if (auto p = QtPrivate::QPropertyAdaptorSlotObject::cast(c->slotObj,
5810 property.propertyIndex()))
5811 return p;
5812 }
5813 }
5814 }
5815 return nullptr;
5816}
5817
5818/*! \class QMetaObject::Connection
5819 \inmodule QtCore
5820 Represents a handle to a signal-slot (or signal-functor) connection.
5821
5822 It can be used to check if the connection is valid and to disconnect it using
5823 QObject::disconnect(). For a signal-functor connection without a context object,
5824 it is the only way to selectively disconnect that connection.
5825
5826 As Connection is just a handle, the underlying signal-slot connection is unaffected
5827 when Connection is destroyed or reassigned.
5828 */
5829
5830/*!
5831 Create a copy of the handle to the \a other connection
5832 */
5833QMetaObject::Connection::Connection(const QMetaObject::Connection &other) : d_ptr(other.d_ptr)
5834{
5835 if (d_ptr)
5836 static_cast<QObjectPrivate::Connection *>(d_ptr)->ref();
5837}
5838
5839/*!
5840 Assigns \a other to this connection and returns a reference to this connection.
5841*/
5842QMetaObject::Connection &QMetaObject::Connection::operator=(const QMetaObject::Connection &other)
5843{
5844 if (other.d_ptr != d_ptr) {
5845 if (d_ptr)
5846 static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
5847 d_ptr = other.d_ptr;
5848 if (other.d_ptr)
5849 static_cast<QObjectPrivate::Connection *>(other.d_ptr)->ref();
5850 }
5851 return *this;
5852}
5853
5854/*!
5855 Creates a Connection instance.
5856*/
5857
5858QMetaObject::Connection::Connection() : d_ptr(nullptr) {}
5859
5860/*!
5861 Destructor for QMetaObject::Connection.
5862*/
5863QMetaObject::Connection::~Connection()
5864{
5865 if (d_ptr)
5866 static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
5867}
5868
5869/*! \internal Returns true if the object is still connected */
5870bool QMetaObject::Connection::isConnected_helper() const
5871{
5872 Q_ASSERT(d_ptr); // we're only called from operator RestrictedBool() const
5873 QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(d_ptr);
5874
5875 return c->receiver.loadRelaxed();
5876}
5877
5878
5879/*!
5880 \fn QMetaObject::Connection::operator bool() const
5881
5882 Returns \c true if the connection is valid.
5883
5884 The connection is valid if the call to QObject::connect succeeded.
5885 The connection is invalid if QObject::connect was not able to find
5886 the signal or the slot, or if the arguments do not match.
5887 */
5888
5889QT_END_NAMESPACE
5890
5891#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:2994
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:3690
QObject * qt_qFindChild_helper(const QObject *parent, QAnyStringView name, const QMetaObject &mo, Qt::FindChildOptions options)
Definition qobject.cpp:2241
static const char * extract_location(const char *member)
Definition qobject.cpp:2635
ConnectionEnd
Definition qobject.cpp:2709
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:2691
static Q_DECL_COLD_FUNCTION void connectWarning(const QObject *sender, const QMetaObject *senderMetaObject, const QObject *receiver, const char *message)
Definition qobject.cpp:2735
static bool check_method_code(int code, const QObject *object, const char *method, const char *func)
Definition qobject.cpp:2662
static Q_DECL_COLD_FUNCTION void err_info_about_object(const char *func, const QObject *o, ConnectionEnd end)
Definition qobject.cpp:2711
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:2194
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:2629
static bool check_signal_macro(const QObject *sender, const char *signal, const char *func, const char *op)
Definition qobject.cpp:2646
static Q_DECL_COLD_FUNCTION void err_info_about_objects(const char *func, const QObject *sender, const QObject *receiver)
Definition qobject.cpp:2728
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, QAnyStringView name, const QMetaObject &mo, QList< void * > *list, Qt::FindChildOptions options)
Definition qobject.cpp:2204
Q_CORE_EXPORT const char * qFlagLocation(const char *method)
Definition qobject.cpp:2623
SlotObjectGuard()=default