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

source code of qtbase/src/corelib/kernel/qobject.cpp