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

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