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.storeRelaxed(newValue: 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.loadRelaxed())
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 QObject::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 delete this;
1404 break;
1405
1406 case QEvent::MetaCall:
1407 {
1408 QAbstractMetaCallEvent *mce = static_cast<QAbstractMetaCallEvent*>(e);
1409
1410 QObjectPrivate::ConnectionData *connections = d_func()->connections.loadAcquire();
1411 if (!connections) {
1412 QMutexLocker locker(signalSlotLock(o: this));
1413 d_func()->ensureConnectionData();
1414 connections = d_func()->connections.loadRelaxed();
1415 }
1416 QObjectPrivate::Sender sender(this, const_cast<QObject*>(mce->sender()), mce->signalId(), connections);
1417
1418 mce->placeMetaCall(object: this);
1419 break;
1420 }
1421
1422 case QEvent::ThreadChange: {
1423 Q_D(QObject);
1424 QThreadData *threadData = d->threadData.loadRelaxed();
1425 QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
1426 if (eventDispatcher) {
1427 QList<QAbstractEventDispatcher::TimerInfoV2> timers = eventDispatcher->timersForObject(object: this);
1428 if (!timers.isEmpty()) {
1429 const bool res = eventDispatcher->unregisterTimers(object: this);
1430 // do not to release our timer ids back to the pool (since the timer ids are moving to a new thread).
1431 Q_ASSERT_X(res, Q_FUNC_INFO,
1432 "QAbstractEventDispatcher::unregisterTimers() returned false,"
1433 " but there are timers associated with this object.");
1434 auto reRegisterTimers = [this, timers = std::move(timers)]() {
1435 QAbstractEventDispatcher *eventDispatcher =
1436 d_func()->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
1437 for (const auto &ti : timers)
1438 eventDispatcher->registerTimer(timerId: ti.timerId, interval: ti.interval, timerType: ti.timerType, object: this);
1439 };
1440 QMetaObject::invokeMethod(object: this, function: std::move(reRegisterTimers), type: Qt::QueuedConnection);
1441 }
1442 }
1443 break;
1444 }
1445
1446 default:
1447 if (e->type() >= QEvent::User) {
1448 customEvent(event: e);
1449 break;
1450 }
1451 return false;
1452 }
1453 return true;
1454}
1455
1456/*!
1457 \fn void QObject::timerEvent(QTimerEvent *event)
1458
1459 This event handler can be reimplemented in a subclass to receive
1460 timer events for the object.
1461
1462 QChronoTimer provides higher-level interfaces to the timer functionality,
1463 and also more general information about timers. The timer event is passed
1464 in the \a event parameter.
1465
1466 \sa startTimer(), killTimer(), event()
1467*/
1468
1469void QObject::timerEvent(QTimerEvent *)
1470{
1471}
1472
1473
1474/*!
1475 This event handler can be reimplemented in a subclass to receive
1476 child events. The event is passed in the \a event parameter.
1477
1478 QEvent::ChildAdded and QEvent::ChildRemoved events are sent to
1479 objects when children are added or removed. In both cases you can
1480 only rely on the child being a QObject, or if isWidgetType()
1481 returns \c true, a QWidget. (This is because, in the
1482 \l{QEvent::ChildAdded}{ChildAdded} case, the child is not yet
1483 fully constructed, and in the \l{QEvent::ChildRemoved}{ChildRemoved}
1484 case it might have been destructed already).
1485
1486 QEvent::ChildPolished events are sent to widgets when children
1487 are polished, or when polished children are added. If you receive
1488 a child polished event, the child's construction is usually
1489 completed. However, this is not guaranteed, and multiple polish
1490 events may be delivered during the execution of a widget's
1491 constructor.
1492
1493 For every child widget, you receive one
1494 \l{QEvent::ChildAdded}{ChildAdded} event, zero or more
1495 \l{QEvent::ChildPolished}{ChildPolished} events, and one
1496 \l{QEvent::ChildRemoved}{ChildRemoved} event.
1497
1498 The \l{QEvent::ChildPolished}{ChildPolished} event is omitted if
1499 a child is removed immediately after it is added. If a child is
1500 polished several times during construction and destruction, you
1501 may receive several child polished events for the same child,
1502 each time with a different virtual table.
1503
1504 \sa event()
1505*/
1506
1507void QObject::childEvent(QChildEvent * /* event */)
1508{
1509}
1510
1511
1512/*!
1513 This event handler can be reimplemented in a subclass to receive
1514 custom events. Custom events are user-defined events with a type
1515 value at least as large as the QEvent::User item of the
1516 QEvent::Type enum, and is typically a QEvent subclass. The event
1517 is passed in the \a event parameter.
1518
1519 \sa event(), QEvent
1520*/
1521void QObject::customEvent(QEvent * /* event */)
1522{
1523}
1524
1525
1526
1527/*!
1528 Filters events if this object has been installed as an event
1529 filter for the \a watched object.
1530
1531 In your reimplementation of this function, if you want to filter
1532 the \a event out, i.e. stop it being handled further, return
1533 true; otherwise return false.
1534
1535 Example:
1536 \snippet code/src_corelib_kernel_qobject.cpp 6
1537
1538 Notice in the example above that unhandled events are passed to
1539 the base class's eventFilter() function, since the base class
1540 might have reimplemented eventFilter() for its own internal
1541 purposes.
1542
1543 Some events, such as \l QEvent::ShortcutOverride must be explicitly
1544 accepted (by calling \l {QEvent::}{accept()} on them) in order to prevent
1545 propagation.
1546
1547 \warning If you delete the receiver object in this function, be
1548 sure to return true. Otherwise, Qt will forward the event to the
1549 deleted object and the program might crash.
1550
1551 \sa installEventFilter()
1552*/
1553
1554bool QObject::eventFilter(QObject * /* watched */, QEvent * /* event */)
1555{
1556 return false;
1557}
1558
1559/*!
1560 \fn bool QObject::signalsBlocked() const
1561
1562 Returns \c true if signals are blocked; otherwise returns \c false.
1563
1564 Signals are not blocked by default.
1565
1566 \sa blockSignals(), QSignalBlocker
1567*/
1568
1569/*!
1570 If \a block is true, signals emitted by this object are blocked
1571 (i.e., emitting a signal will not invoke anything connected to it).
1572 If \a block is false, no such blocking will occur.
1573
1574 The return value is the previous value of signalsBlocked().
1575
1576 Note that the destroyed() signal will be emitted even if the signals
1577 for this object have been blocked.
1578
1579 Signals emitted while being blocked are not buffered.
1580
1581 \sa signalsBlocked(), QSignalBlocker
1582*/
1583
1584bool QObject::blockSignals(bool block) noexcept
1585{
1586 Q_D(QObject);
1587 bool previous = d->blockSig;
1588 d->blockSig = block;
1589 return previous;
1590}
1591
1592/*!
1593 Returns the thread in which the object lives.
1594
1595 \sa moveToThread()
1596*/
1597QThread *QObject::thread() const
1598{
1599 return d_func()->threadData.loadRelaxed()->thread.loadAcquire();
1600}
1601
1602/*!
1603 Changes the thread affinity for this object and its children and
1604 returns \c true on success. The object cannot be moved if it has a
1605 parent. Event processing will continue in the \a targetThread.
1606
1607 To move an object to the main thread, use QApplication::instance()
1608 to retrieve a pointer to the current application, and then use
1609 QApplication::thread() to retrieve the thread in which the
1610 application lives. For example:
1611
1612 \snippet code/src_corelib_kernel_qobject.cpp 7
1613
1614 If \a targetThread is \nullptr, all event processing for this object
1615 and its children stops, as they are no longer associated with any
1616 thread.
1617
1618 Note that all active timers for the object will be reset. The
1619 timers are first stopped in the current thread and restarted (with
1620 the same interval) in the \a targetThread. As a result, constantly
1621 moving an object between threads can postpone timer events
1622 indefinitely.
1623
1624 A QEvent::ThreadChange event is sent to this object just before
1625 the thread affinity is changed. You can handle this event to
1626 perform any special processing. Note that any new events that are
1627 posted to this object will be handled in the \a targetThread,
1628 provided it is not \nullptr: when it is \nullptr, no event processing
1629 for this object or its children can happen, as they are no longer
1630 associated with any thread.
1631
1632 \warning This function is \e not thread-safe; the current thread
1633 must be same as the current thread affinity. In other words, this
1634 function can only "push" an object from the current thread to
1635 another thread, it cannot "pull" an object from any arbitrary
1636 thread to the current thread. There is one exception to this rule
1637 however: objects with no thread affinity can be "pulled" to the
1638 current thread.
1639
1640 \sa thread()
1641 */
1642bool QObject::moveToThread(QThread *targetThread QT6_IMPL_NEW_OVERLOAD_TAIL)
1643{
1644 Q_D(QObject);
1645
1646 if (d->threadData.loadRelaxed()->thread.loadAcquire() == targetThread) {
1647 // object is already in this thread
1648 return true;
1649 }
1650
1651 if (d->parent != nullptr) {
1652 qWarning(msg: "QObject::moveToThread: Cannot move objects with a parent");
1653 return false;
1654 }
1655 if (d->isWidget) {
1656 qWarning(msg: "QObject::moveToThread: Widgets cannot be moved to a new thread");
1657 return false;
1658 }
1659 if (!d->bindingStorage.isEmpty()) {
1660 qWarning(msg: "QObject::moveToThread: Can not move objects that contain bindings or are used in bindings to a new thread.");
1661 return false;
1662 }
1663
1664 QThreadData *currentData = QThreadData::current();
1665 QThreadData *targetData = targetThread ? QThreadData::get2(thread: targetThread) : nullptr;
1666 QThreadData *thisThreadData = d->threadData.loadAcquire();
1667 if (!thisThreadData->thread.loadRelaxed() && currentData == targetData) {
1668 // one exception to the rule: we allow moving objects with no thread affinity to the current thread
1669 currentData = thisThreadData;
1670 } else if (thisThreadData != currentData) {
1671 qWarning(msg: "QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
1672 "Cannot move to target thread (%p)\n",
1673 currentData->thread.loadRelaxed(), thisThreadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() : nullptr);
1674
1675#ifdef Q_OS_DARWIN
1676 qWarning("You might be loading two sets of Qt binaries into the same process. "
1677 "Check that all plugins are compiled against the right Qt binaries. Export "
1678 "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.");
1679#endif
1680
1681 return false;
1682 }
1683
1684 // prepare to move
1685 d->moveToThread_helper();
1686
1687 if (!targetData)
1688 targetData = new QThreadData(0);
1689
1690 // make sure nobody adds/removes connections to this object while we're moving it
1691 QMutexLocker l(signalSlotLock(o: this));
1692
1693 QOrderedMutexLocker locker(&currentData->postEventList.mutex,
1694 &targetData->postEventList.mutex);
1695
1696 // keep currentData alive (since we've got it locked)
1697 currentData->ref();
1698
1699 // move the object
1700 auto threadPrivate = targetThread
1701 ? static_cast<QThreadPrivate *>(QThreadPrivate::get(o: targetThread))
1702 : nullptr;
1703 QBindingStatus *bindingStatus = threadPrivate
1704 ? threadPrivate->bindingStatus()
1705 : nullptr;
1706 if (threadPrivate && !bindingStatus) {
1707 bindingStatus = threadPrivate->addObjectWithPendingBindingStatusChange(obj: this);
1708 }
1709 d_func()->setThreadData_helper(currentData, targetData, status: bindingStatus);
1710
1711 locker.unlock();
1712
1713 // now currentData can commit suicide if it wants to
1714 currentData->deref();
1715 return true;
1716}
1717
1718void QObjectPrivate::moveToThread_helper()
1719{
1720 Q_Q(QObject);
1721 QEvent e(QEvent::ThreadChange);
1722 QCoreApplication::sendEvent(receiver: q, event: &e);
1723 bindingStorage.clear();
1724 for (int i = 0; i < children.size(); ++i) {
1725 QObject *child = children.at(i);
1726 child->d_func()->moveToThread_helper();
1727 }
1728}
1729
1730void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status)
1731{
1732 Q_Q(QObject);
1733
1734 if (status) {
1735 // the new thread is already running
1736 this->bindingStorage.bindingStatus = status;
1737 }
1738
1739 // move posted events
1740 qsizetype eventsMoved = 0;
1741 for (qsizetype i = 0; i < currentData->postEventList.size(); ++i) {
1742 const QPostEvent &pe = currentData->postEventList.at(i);
1743 if (!pe.event)
1744 continue;
1745 if (pe.receiver == q) {
1746 // move this post event to the targetList
1747 targetData->postEventList.addEvent(ev: pe);
1748 const_cast<QPostEvent &>(pe).event = nullptr;
1749 ++eventsMoved;
1750 }
1751 }
1752 if (eventsMoved > 0 && targetData->hasEventDispatcher()) {
1753 targetData->canWait = false;
1754 targetData->eventDispatcher.loadRelaxed()->wakeUp();
1755 }
1756
1757 // the current emitting thread shouldn't restore currentSender after calling moveToThread()
1758 ConnectionData *cd = connections.loadAcquire();
1759 if (cd) {
1760 if (cd->currentSender) {
1761 cd->currentSender->receiverDeleted();
1762 cd->currentSender = nullptr;
1763 }
1764
1765 // adjust the receiverThreadId values in the Connections
1766 if (cd) {
1767 auto *c = cd->senders;
1768 while (c) {
1769 QObject *r = c->receiver.loadRelaxed();
1770 if (r) {
1771 Q_ASSERT(r == q);
1772 targetData->ref();
1773 QThreadData *old = c->receiverThreadData.loadRelaxed();
1774 if (old)
1775 old->deref();
1776 c->receiverThreadData.storeRelaxed(newValue: targetData);
1777 }
1778 c = c->next;
1779 }
1780 }
1781
1782 }
1783
1784 // set new thread data
1785 targetData->ref();
1786 threadData.loadRelaxed()->deref();
1787
1788 // synchronizes with loadAcquire e.g. in QCoreApplication::postEvent
1789 threadData.storeRelease(newValue: targetData);
1790
1791 for (int i = 0; i < children.size(); ++i) {
1792 QObject *child = children.at(i);
1793 child->d_func()->setThreadData_helper(currentData, targetData, status);
1794 }
1795}
1796
1797//
1798// The timer flag hasTimer is set when startTimer is called.
1799// It is not reset when killing the timer because more than
1800// one timer might be active.
1801//
1802
1803/*!
1804 \fn int QObject::startTimer(int interval, Qt::TimerType timerType)
1805
1806 This is an overloaded function that will start a timer of type
1807 \a timerType and a timeout of \a interval milliseconds. This is
1808 equivalent to calling:
1809 \code
1810 startTimer(std::chrono::milliseconds{interval}, timerType);
1811 \endcode
1812
1813 \sa timerEvent(), killTimer(), QChronoTimer, QBasicTimer
1814*/
1815
1816int QObject::startTimer(int interval, Qt::TimerType timerType)
1817{
1818 // no overflow can happen here:
1819 // 2^31 ms * 1,000,000 always fits a 64-bit signed integer type
1820 return startTimer(time: std::chrono::milliseconds{interval}, timerType);
1821}
1822
1823/*!
1824 \since 5.9
1825 \overload
1826
1827 Starts a timer and returns a timer identifier, or returns zero if
1828 it could not start a timer.
1829
1830 A timer event will occur every \a interval until killTimer()
1831 is called. If \a interval is equal to \c{std::chrono::duration::zero()},
1832 then the timer event occurs once every time there are no more window
1833 system events to process.
1834
1835 The virtual timerEvent() function is called with the QTimerEvent
1836 event parameter class when a timer event occurs. Reimplement this
1837 function to get timer events.
1838
1839 If multiple timers are running, the QTimerEvent::id() method can be
1840 used to find out which timer was activated.
1841
1842 Example:
1843
1844 \snippet code/src_corelib_kernel_qobject.cpp 8
1845
1846 Note that the accuracy of the timer depends on the underlying operating
1847 system and hardware.
1848
1849 The \a timerType argument allows you to customize the accuracy of
1850 the timer. See Qt::TimerType for information on the different timer types.
1851 Most platforms support an accuracy of 20 milliseconds; some provide more.
1852 If Qt is unable to deliver the requested number of timer events, it will
1853 silently discard some.
1854
1855 The QTimer and QChronoTimer classes provide a high-level programming
1856 interface with single-shot timers and timer signals instead of
1857 events. There is also a QBasicTimer class that is more lightweight than
1858 QChronoTimer but less clumsy than using timer IDs directly.
1859
1860 \note Starting from Qt 6.8 the type of \a interval
1861 is \c std::chrono::nanoseconds, prior to that it was \c
1862 std::chrono::milliseconds. This change is backwards compatible with
1863 older releases of Qt.
1864
1865 \note In Qt 6.8, QObject was changed to use Qt::TimerId to represent timer
1866 IDs. This method converts the TimerId to int for backwards compatibility
1867 reasons, however you can use Qt::TimerId to check the value returned by
1868 this method, for example:
1869 \snippet code/src_corelib_kernel_qobject.cpp invalid-timer-id
1870
1871 \sa timerEvent(), killTimer(), QChronoTimer, QBasicTimer
1872*/
1873int QObject::startTimer(std::chrono::nanoseconds interval, Qt::TimerType timerType)
1874{
1875 Q_D(QObject);
1876
1877 using namespace std::chrono_literals;
1878
1879 if (Q_UNLIKELY(interval < 0ns)) {
1880 qWarning(msg: "QObject::startTimer: Timers cannot have negative intervals");
1881 return 0;
1882 }
1883
1884 auto thisThreadData = d->threadData.loadRelaxed();
1885 if (Q_UNLIKELY(!thisThreadData->hasEventDispatcher())) {
1886 qWarning(msg: "QObject::startTimer: Timers can only be used with threads started with QThread");
1887 return 0;
1888 }
1889 if (Q_UNLIKELY(thread() != QThread::currentThread())) {
1890 qWarning(msg: "QObject::startTimer: Timers cannot be started from another thread");
1891 return 0;
1892 }
1893
1894 auto dispatcher = thisThreadData->eventDispatcher.loadRelaxed();
1895 Qt::TimerId timerId = dispatcher->registerTimer(interval, timerType, object: this);
1896 d->ensureExtraData();
1897 d->extraData->runningTimers.append(t: timerId);
1898 return int(timerId);
1899}
1900
1901/*!
1902 Kills the timer with timer identifier, \a id.
1903
1904 The timer identifier is returned by startTimer() when a timer
1905 event is started.
1906
1907 \sa timerEvent(), startTimer()
1908*/
1909
1910void QObject::killTimer(int id)
1911{
1912 killTimer(id: Qt::TimerId{id});
1913}
1914
1915/*!
1916 \since 6.8
1917 \overload
1918*/
1919void QObject::killTimer(Qt::TimerId id)
1920{
1921 Q_D(QObject);
1922 if (Q_UNLIKELY(thread() != QThread::currentThread())) {
1923 qWarning(msg: "QObject::killTimer: Timers cannot be stopped from another thread");
1924 return;
1925 }
1926 if (id > Qt::TimerId::Invalid) {
1927 int at = d->extraData ? d->extraData->runningTimers.indexOf(t: id) : -1;
1928 if (at == -1) {
1929 // timer isn't owned by this object
1930 qWarning(msg: "QObject::killTimer(): Error: timer id %d is not valid for object %p (%s, %ls), timer has not been killed",
1931 qToUnderlying(e: id),
1932 this,
1933 metaObject()->className(),
1934 qUtf16Printable(objectName()));
1935 return;
1936 }
1937
1938 auto thisThreadData = d->threadData.loadRelaxed();
1939 if (thisThreadData->hasEventDispatcher())
1940 thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimer(timerId: id);
1941
1942 d->extraData->runningTimers.remove(i: at);
1943 QAbstractEventDispatcherPrivate::releaseTimerId(id);
1944 }
1945}
1946
1947/*!
1948 \fn QObject *QObject::parent() const
1949
1950 Returns a pointer to the parent object.
1951
1952 \sa children()
1953*/
1954
1955/*!
1956 \fn const QObjectList &QObject::children() const
1957
1958 Returns a list of child objects.
1959 The QObjectList class is defined in the \c{<QObject>} header
1960 file as the following:
1961
1962 \quotefromfile kernel/qobject.h
1963 \skipto /typedef .*QObjectList/
1964 \printuntil QObjectList
1965
1966 The first child added is the \l{QList::first()}{first} object in
1967 the list and the last child added is the \l{QList::last()}{last}
1968 object in the list, i.e. new children are appended at the end.
1969
1970 Note that the list order changes when QWidget children are
1971 \l{QWidget::raise()}{raised} or \l{QWidget::lower()}{lowered}. A
1972 widget that is raised becomes the last object in the list, and a
1973 widget that is lowered becomes the first object in the list.
1974
1975 \sa findChild(), findChildren(), parent(), setParent()
1976*/
1977
1978
1979/*!
1980 \fn template<typename T> T *QObject::findChild(QAnyStringView name, Qt::FindChildOptions options) const
1981
1982 Returns the child of this object that can be cast into type T and
1983 that is called \a name, or \nullptr if there is no such object.
1984 A null \a name argument causes all objects to be matched. An empty,
1985 non-null \a name matches only objects whose \l objectName is empty.
1986 The search is performed recursively, unless \a options specifies the
1987 option FindDirectChildrenOnly.
1988
1989 If there is more than one child matching the search, the most-direct
1990 ancestor is returned. If there are several most-direct ancestors, the
1991 first child in children() will be returned. In that case, it's better
1992 to use findChildren() to get the complete list of all children.
1993
1994 This example returns a child \c{QPushButton} of \c{parentWidget}
1995 named \c{"button1"}, even if the button isn't a direct child of
1996 the parent:
1997
1998 \snippet code/src_corelib_kernel_qobject.cpp 10
1999
2000 This example returns a \c{QListWidget} child of \c{parentWidget}:
2001
2002 \snippet code/src_corelib_kernel_qobject.cpp 11
2003
2004 This example returns a child \c{QPushButton} of \c{parentWidget}
2005 (its direct parent) named \c{"button1"}:
2006
2007 \snippet code/src_corelib_kernel_qobject.cpp 41
2008
2009 This example returns a \c{QListWidget} child of \c{parentWidget},
2010 its direct parent:
2011
2012 \snippet code/src_corelib_kernel_qobject.cpp 42
2013
2014 \note In Qt versions prior to 6.7, this function took \a name as
2015 \c{QString}, not \c{QAnyStringView}.
2016
2017 \sa findChildren()
2018*/
2019
2020/*!
2021 \fn template<typename T> T *QObject::findChild(Qt::FindChildOptions options) const
2022 \overload
2023 \since 6.7
2024
2025 Returns the child of this object that can be cast into type T, or
2026 \nullptr if there is no such object.
2027 The search is performed recursively, unless \a options specifies the
2028 option FindDirectChildrenOnly.
2029
2030 If there is more than one child matching the search, the most-direct ancestor
2031 is returned. If there are several most-direct ancestors, the first child in
2032 children() will be returned. In that case, it's better to use findChildren()
2033 to get the complete list of all children.
2034
2035 \sa findChildren()
2036*/
2037
2038/*!
2039 \fn template<typename T> QList<T> QObject::findChildren(QAnyStringView name, Qt::FindChildOptions options) const
2040
2041 Returns all children of this object with the given \a name that can be
2042 cast to type T, or an empty list if there are no such objects.
2043 A null \a name argument causes all objects to be matched, an empty one
2044 only those whose objectName is empty.
2045 The search is performed recursively, unless \a options specifies the
2046 option FindDirectChildrenOnly.
2047
2048 The following example shows how to find a list of child \c{QWidget}s of
2049 the specified \c{parentWidget} named \c{widgetname}:
2050
2051 \snippet code/src_corelib_kernel_qobject.cpp 12
2052
2053 This example returns all \c{QPushButton}s that are children of \c{parentWidget}:
2054
2055 \snippet code/src_corelib_kernel_qobject.cpp 13
2056
2057 This example returns all \c{QPushButton}s that are immediate children of \c{parentWidget}:
2058
2059 \snippet code/src_corelib_kernel_qobject.cpp 43
2060
2061 \note In Qt versions prior to 6.7, this function took \a name as
2062 \c{QString}, not \c{QAnyStringView}.
2063
2064 \sa findChild()
2065*/
2066
2067/*!
2068 \fn template<typename T> QList<T> QObject::findChildren(Qt::FindChildOptions options) const
2069 \overload
2070 \since 6.3
2071
2072 Returns all children of this object that can be cast to type T, or
2073 an empty list if there are no such objects.
2074 The search is performed recursively, unless \a options specifies the
2075 option FindDirectChildrenOnly.
2076
2077 \sa findChild()
2078*/
2079
2080/*!
2081 \fn template<typename T> QList<T> QObject::findChildren(const QRegularExpression &re, Qt::FindChildOptions options) const
2082 \overload findChildren()
2083
2084 \since 5.0
2085
2086 Returns the children of this object that can be cast to type T
2087 and that have names matching the regular expression \a re,
2088 or an empty list if there are no such objects.
2089 The search is performed recursively, unless \a options specifies the
2090 option FindDirectChildrenOnly.
2091*/
2092
2093/*!
2094 \fn template<typename T> T qFindChild(const QObject *obj, const QString &name)
2095 \relates QObject
2096 \overload qFindChildren()
2097 \deprecated
2098
2099 This function is equivalent to
2100 \a{obj}->\l{QObject::findChild()}{findChild}<T>(\a name).
2101
2102 \note This function was provided as a workaround for MSVC 6
2103 which did not support member template functions. It is advised
2104 to use the other form in new code.
2105
2106 \sa QObject::findChild()
2107*/
2108
2109/*!
2110 \fn template<typename T> QList<T> qFindChildren(const QObject *obj, const QString &name)
2111 \relates QObject
2112 \overload qFindChildren()
2113 \deprecated
2114
2115 This function is equivalent to
2116 \a{obj}->\l{QObject::findChildren()}{findChildren}<T>(\a name).
2117
2118 \note This function was provided as a workaround for MSVC 6
2119 which did not support member template functions. It is advised
2120 to use the other form in new code.
2121
2122 \sa QObject::findChildren()
2123*/
2124
2125static bool matches_objectName_non_null(QObject *obj, QAnyStringView name)
2126{
2127 if (auto ext = QObjectPrivate::get(o: obj)->extraData)
2128 return ext ->objectName.valueBypassingBindings() == name;
2129 return name.isEmpty();
2130}
2131
2132/*!
2133 \internal
2134*/
2135void qt_qFindChildren_helper(const QObject *parent, QAnyStringView name,
2136 const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
2137{
2138 Q_ASSERT(parent);
2139 Q_ASSERT(list);
2140 for (QObject *obj : parent->children()) {
2141 if (mo.cast(obj) && (name.isNull() || matches_objectName_non_null(obj, name)))
2142 list->append(t: obj);
2143 if (options & Qt::FindChildrenRecursively)
2144 qt_qFindChildren_helper(parent: obj, name, mo, list, options);
2145 }
2146}
2147
2148#if QT_CONFIG(regularexpression)
2149/*!
2150 \internal
2151*/
2152void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re,
2153 const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
2154{
2155 Q_ASSERT(parent);
2156 Q_ASSERT(list);
2157 for (QObject *obj : parent->children()) {
2158 if (mo.cast(obj)) {
2159 QRegularExpressionMatch m = re.match(subject: obj->objectName());
2160 if (m.hasMatch())
2161 list->append(t: obj);
2162 }
2163 if (options & Qt::FindChildrenRecursively)
2164 qt_qFindChildren_helper(parent: obj, re, mo, list, options);
2165 }
2166}
2167#endif // QT_CONFIG(regularexpression)
2168
2169/*!
2170 \internal
2171*/
2172QObject *qt_qFindChild_helper(const QObject *parent, QAnyStringView name, const QMetaObject &mo, Qt::FindChildOptions options)
2173{
2174 Q_ASSERT(parent);
2175 for (QObject *obj : parent->children()) {
2176 if (mo.cast(obj) && (name.isNull() || matches_objectName_non_null(obj, name)))
2177 return obj;
2178 }
2179 if (options & Qt::FindChildrenRecursively) {
2180 for (QObject *child : parent->children()) {
2181 if (QObject *obj = qt_qFindChild_helper(parent: child, name, mo, options))
2182 return obj;
2183 }
2184 }
2185 return nullptr;
2186}
2187
2188/*!
2189 Makes the object a child of \a parent.
2190
2191 \sa parent(), children()
2192*/
2193void QObject::setParent(QObject *parent)
2194{
2195 Q_D(QObject);
2196 Q_ASSERT(!d->isWidget);
2197 d->setParent_helper(parent);
2198}
2199
2200void QObjectPrivate::deleteChildren()
2201{
2202 Q_ASSERT_X(!isDeletingChildren, "QObjectPrivate::deleteChildren()", "isDeletingChildren already set, did this function recurse?");
2203 isDeletingChildren = true;
2204 // delete children objects
2205 // don't use qDeleteAll as the destructor of the child might
2206 // delete siblings
2207 for (int i = 0; i < children.size(); ++i) {
2208 currentChildBeingDeleted = children.at(i);
2209 children[i] = nullptr;
2210 delete currentChildBeingDeleted;
2211 }
2212 children.clear();
2213 currentChildBeingDeleted = nullptr;
2214 isDeletingChildren = false;
2215}
2216
2217void QObjectPrivate::setParent_helper(QObject *o)
2218{
2219 Q_Q(QObject);
2220 Q_ASSERT_X(q != o, Q_FUNC_INFO, "Cannot parent a QObject to itself");
2221#ifdef QT_DEBUG
2222 const auto checkForParentChildLoops = qScopeGuard(f: [&](){
2223 int depth = 0;
2224 auto p = parent;
2225 while (p) {
2226 if (++depth == CheckForParentChildLoopsWarnDepth) {
2227 qWarning(msg: "QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
2228 "this is undefined behavior",
2229 q, q->metaObject()->className(), qPrintable(q->objectName()));
2230 }
2231 p = p->parent();
2232 }
2233 });
2234#endif
2235
2236 if (o == parent)
2237 return;
2238
2239 if (parent) {
2240 QObjectPrivate *parentD = parent->d_func();
2241 if (parentD->isDeletingChildren && wasDeleted
2242 && parentD->currentChildBeingDeleted == q) {
2243 // don't do anything since QObjectPrivate::deleteChildren() already
2244 // cleared our entry in parentD->children.
2245 } else {
2246 const int index = parentD->children.indexOf(t: q);
2247 if (index < 0) {
2248 // we're probably recursing into setParent() from a ChildRemoved event, don't do anything
2249 } else if (parentD->isDeletingChildren) {
2250 parentD->children[index] = nullptr;
2251 } else {
2252 parentD->children.removeAt(i: index);
2253 if (sendChildEvents && parentD->receiveChildEvents) {
2254 QChildEvent e(QEvent::ChildRemoved, q);
2255 QCoreApplication::sendEvent(receiver: parent, event: &e);
2256 }
2257 }
2258 }
2259 }
2260
2261 if (receiveParentEvents) {
2262 Q_ASSERT(!isWidget); // Handled in QWidget
2263 QEvent e(QEvent::ParentAboutToChange);
2264 QCoreApplication::sendEvent(receiver: q, event: &e);
2265 }
2266
2267 parent = o;
2268
2269 if (parent) {
2270 // object hierarchies are constrained to a single thread
2271 if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) {
2272 qWarning(msg: "QObject::setParent: Cannot set parent, new parent is in a different thread");
2273 parent = nullptr;
2274 return;
2275 }
2276 parent->d_func()->children.append(t: q);
2277 if (sendChildEvents && parent->d_func()->receiveChildEvents) {
2278 if (!isWidget) {
2279 QChildEvent e(QEvent::ChildAdded, q);
2280 QCoreApplication::sendEvent(receiver: parent, event: &e);
2281 }
2282 }
2283 }
2284
2285 if (receiveParentEvents) {
2286 Q_ASSERT(!isWidget); // Handled in QWidget
2287 QEvent e(QEvent::ParentChange);
2288 QCoreApplication::sendEvent(receiver: q, event: &e);
2289 }
2290}
2291
2292/*!
2293 \fn void QObject::installEventFilter(QObject *filterObj)
2294
2295 Installs an event filter \a filterObj on this object. For example:
2296 \snippet code/src_corelib_kernel_qobject.cpp 14
2297
2298 An event filter is an object that receives all events that are
2299 sent to this object. The filter can either stop the event or
2300 forward it to this object. The event filter \a filterObj receives
2301 events via its eventFilter() function. The eventFilter() function
2302 must return true if the event should be filtered, (i.e. stopped);
2303 otherwise it must return false.
2304
2305 If multiple event filters are installed on a single object, the
2306 filter that was installed last is activated first.
2307
2308 If \a filterObj has already been installed for this object,
2309 this function moves it so it acts as if it was installed last.
2310
2311 Here's a \c KeyPressEater class that eats the key presses of its
2312 monitored objects:
2313
2314 \snippet code/src_corelib_kernel_qobject.cpp 15
2315
2316 And here's how to install it on two widgets:
2317
2318 \snippet code/src_corelib_kernel_qobject.cpp 16
2319
2320 The QShortcut class, for example, uses this technique to intercept
2321 shortcut key presses.
2322
2323 \warning If you delete the receiver object in your eventFilter()
2324 function, be sure to return true. If you return false, Qt sends
2325 the event to the deleted object and the program will crash.
2326
2327 Note that the filtering object must be in the same thread as this
2328 object. If \a filterObj is in a different thread, this function does
2329 nothing. If either \a filterObj or this object are moved to a different
2330 thread after calling this function, the event filter will not be
2331 called until both objects have the same thread affinity again (it
2332 is \e not removed).
2333
2334 \sa removeEventFilter(), eventFilter(), event()
2335*/
2336
2337void QObject::installEventFilter(QObject *obj)
2338{
2339 Q_D(QObject);
2340 if (!obj)
2341 return;
2342 if (d->threadData.loadRelaxed() != obj->d_func()->threadData.loadRelaxed()) {
2343 qWarning(msg: "QObject::installEventFilter(): Cannot filter events for objects in a different thread.");
2344 return;
2345 }
2346
2347 d->ensureExtraData();
2348
2349 // clean up unused items in the list along the way:
2350 auto isNullOrEquals = [](auto obj) { return [obj](const auto &p) { return !p || p == obj; }; };
2351 d->extraData->eventFilters.removeIf(pred: isNullOrEquals(obj));
2352 d->extraData->eventFilters.prepend(t: obj);
2353}
2354
2355/*!
2356 Removes an event filter object \a obj from this object. The
2357 request is ignored if such an event filter has not been installed.
2358
2359 All event filters for this object are automatically removed when
2360 this object is destroyed.
2361
2362 It is always safe to remove an event filter, even during event
2363 filter activation (i.e. from the eventFilter() function).
2364
2365 \sa installEventFilter(), eventFilter(), event()
2366*/
2367
2368void QObject::removeEventFilter(QObject *obj)
2369{
2370 Q_D(QObject);
2371 if (d->extraData) {
2372 for (auto &filter : d->extraData->eventFilters) {
2373 if (filter == obj) {
2374 filter = nullptr;
2375 break;
2376 }
2377 }
2378 }
2379}
2380
2381/*!
2382 \fn void QObject::destroyed(QObject *obj)
2383
2384 This signal is emitted immediately before the object \a obj is
2385 destroyed, after any instances of QPointer have been notified,
2386 and cannot be blocked.
2387
2388 All the objects's children are destroyed immediately after this
2389 signal is emitted.
2390
2391 \sa deleteLater(), QPointer
2392*/
2393
2394/*!
2395 \threadsafe
2396
2397 Schedules this object for deletion.
2398
2399 The object will be deleted when control returns to the event
2400 loop. If the event loop is not running when this function is
2401 called (e.g. deleteLater() is called on an object before
2402 QCoreApplication::exec()), the object will be deleted once the
2403 event loop is started. If deleteLater() is called after the main event loop
2404 has stopped, the object will not be deleted.
2405 If deleteLater() is called on an object that lives in a
2406 thread with no running event loop, the object will be destroyed when the
2407 thread finishes.
2408
2409 Note that entering and leaving a new event loop (e.g., by opening a modal
2410 dialog) will \e not perform the deferred deletion; for the object to be
2411 deleted, the control must return to the event loop from which deleteLater()
2412 was called. This does not apply to objects deleted while a previous, nested
2413 event loop was still running: the Qt event loop will delete those objects
2414 as soon as the new nested event loop starts.
2415
2416 In situations where Qt is not driving the event dispatcher via e.g.
2417 QCoreApplication::exec() or QEventLoop::exec(), deferred deletes
2418 will not be processed automatically. To ensure deferred deletion in
2419 this scenario, the following workaround can be used:
2420
2421 \code
2422 const auto *eventDispatcher = QThread::currentThread()->eventDispatcher();
2423 QObject::connect(eventDispatcher, &QAbstractEventDispatcher::aboutToBlock,
2424 QThread::currentThread(), []{
2425 if (QThread::currentThread()->loopLevel() == 0)
2426 QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
2427 }
2428 );
2429 \endcode
2430
2431 \sa destroyed(), QPointer
2432*/
2433void QObject::deleteLater()
2434{
2435#ifdef QT_DEBUG
2436 if (qApp == this)
2437 qWarning(msg: "You are deferring the delete of QCoreApplication, this may not work as expected.");
2438#endif
2439
2440
2441 // De-bounce QDeferredDeleteEvents. Use the post event list mutex
2442 // to guard access to deleteLaterCalled, so we don't need a separate
2443 // mutex in QObjectData.
2444 auto eventListLocker = QCoreApplicationPrivate::lockThreadPostEventList(object: this);
2445 if (!eventListLocker.threadData)
2446 return;
2447
2448 // FIXME: The deleteLaterCalled flag is part of a bit field,
2449 // so we likely have data races here, even with the mutex above,
2450 // as long as we're not guarding every access to the bit field.
2451
2452 Q_D(QObject);
2453 if (d->deleteLaterCalled)
2454 return;
2455
2456 d->deleteLaterCalled = true;
2457
2458 int loopLevel = 0;
2459 int scopeLevel = 0;
2460
2461 auto *objectThreadData = eventListLocker.threadData;
2462 if (objectThreadData == QThreadData::current()) {
2463 // Remember the current running eventloop for deleteLater
2464 // calls in the object's own thread.
2465
2466 // Events sent by non-Qt event handlers (such as glib) may not
2467 // have the scopeLevel set correctly. The scope level makes sure that
2468 // code like this:
2469 // foo->deleteLater();
2470 // qApp->processEvents(); // without passing QEvent::DeferredDelete
2471 // will not cause "foo" to be deleted before returning to the event loop.
2472
2473 loopLevel = objectThreadData->loopLevel;
2474 scopeLevel = objectThreadData->scopeLevel;
2475
2476 // If the scope level is 0 while loopLevel != 0, we are called from a
2477 // non-conformant code path, and our best guess is that the scope level
2478 // should be 1. (Loop level 0 is special: it means that no event loops
2479 // are running.)
2480 if (scopeLevel == 0 && loopLevel != 0)
2481 scopeLevel = 1;
2482 }
2483
2484 eventListLocker.unlock();
2485 QCoreApplication::postEvent(receiver: this,
2486 event: new QDeferredDeleteEvent(loopLevel, scopeLevel));
2487}
2488
2489/*!
2490 \fn QString QObject::tr(const char *sourceText, const char *disambiguation, int n)
2491 \reentrant
2492
2493 Returns a translated version of \a sourceText, optionally based on a
2494 \a disambiguation string and value of \a n for strings containing plurals;
2495 otherwise returns QString::fromUtf8(\a sourceText) if no appropriate
2496 translated string is available.
2497
2498 Example:
2499 \snippet ../widgets/itemviews/spreadsheet/spreadsheet.cpp implicit tr context
2500 \dots
2501
2502 If the same \a sourceText is used in different roles within the
2503 same context, an additional identifying string may be passed in
2504 \a disambiguation (\nullptr by default).
2505
2506 Example:
2507
2508 \snippet code/src_corelib_kernel_qobject.cpp 17
2509 \dots
2510
2511 See \l{Writing Source Code for Translation} for a detailed description of
2512 Qt's translation mechanisms in general, and the
2513 \l{Writing Source Code for Translation#Disambiguate Identical Text}
2514 {Disambiguate Identical Text} section for information on disambiguation.
2515
2516 \warning This method is reentrant only if all translators are
2517 installed \e before calling this method. Installing or removing
2518 translators while performing translations is not supported. Doing
2519 so will probably result in crashes or other undesirable behavior.
2520
2521 \sa QCoreApplication::translate(), {Internationalization with Qt}
2522*/
2523
2524/*****************************************************************************
2525 Signals and slots
2526 *****************************************************************************/
2527
2528namespace {
2529// This class provides (per-thread) storage for qFlagLocation()
2530class FlaggedDebugSignatures
2531{
2532 uint idx = 0;
2533 std::array<const char *, 2> locations = {}; // one for the SIGNAL, one for the SLOT
2534
2535public:
2536 void store(const char* method) noexcept
2537 { locations[idx++ % locations.size()] = method; }
2538
2539 bool contains(const char *method) const noexcept
2540 { return std::find(first: locations.begin(), last: locations.end(), val: method) != locations.end(); }
2541};
2542
2543Q_CONSTINIT static thread_local FlaggedDebugSignatures flaggedSignatures = {};
2544} // unnamed namespace
2545
2546const char *qFlagLocation(const char *method)
2547{
2548 flaggedSignatures.store(method);
2549 return method;
2550}
2551
2552static int extract_code(const char *member)
2553{
2554 // extract code, ensure QMETHOD_CODE <= code <= QSIGNAL_CODE
2555 return (((int)(*member) - '0') & 0x3);
2556}
2557
2558static const char *extract_location(const char *member)
2559{
2560 if (flaggedSignatures.contains(method: member)) {
2561 // signature includes location information after the first null-terminator
2562 const char *location = member + qstrlen(str: member) + 1;
2563 if (*location != '\0')
2564 return location;
2565 }
2566 return nullptr;
2567}
2568
2569static bool check_signal_macro(const QObject *sender, const char *signal,
2570 const char *func, const char *op)
2571{
2572 int sigcode = extract_code(member: signal);
2573 if (sigcode != QSIGNAL_CODE) {
2574 if (sigcode == QSLOT_CODE)
2575 qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s", func, op,
2576 sender->metaObject()->className(), signal + 1);
2577 else
2578 qCWarning(lcConnect, "QObject::%s: Use the SIGNAL macro to %s %s::%s", func, op,
2579 sender->metaObject()->className(), signal);
2580 return false;
2581 }
2582 return true;
2583}
2584
2585static bool check_method_code(int code, const QObject *object, const char *method, const char *func)
2586{
2587 if (code != QSLOT_CODE && code != QSIGNAL_CODE) {
2588 qCWarning(lcConnect,
2589 "QObject::%s: Use the SLOT or SIGNAL macro to "
2590 "%s %s::%s",
2591 func, func, object->metaObject()->className(), method);
2592 return false;
2593 }
2594 return true;
2595}
2596
2597Q_DECL_COLD_FUNCTION
2598static void err_method_notfound(const QObject *object,
2599 const char *method, const char *func)
2600{
2601 const char *type = "method";
2602 switch (extract_code(member: method)) {
2603 case QSLOT_CODE: type = "slot"; break;
2604 case QSIGNAL_CODE: type = "signal"; break;
2605 }
2606 const char *loc = extract_location(member: method);
2607 if (strchr(s: method, c: ')') == nullptr) // common typing mistake
2608 qCWarning(lcConnect, "QObject::%s: Parentheses expected, %s %s::%s%s%s", func, type,
2609 object->metaObject()->className(), method + 1, loc ? " in " : "", loc ? loc : "");
2610 else
2611 qCWarning(lcConnect, "QObject::%s: No such %s %s::%s%s%s", func, type,
2612 object->metaObject()->className(), method + 1, loc ? " in " : "", loc ? loc : "");
2613}
2614
2615Q_DECL_COLD_FUNCTION
2616static void err_info_about_objects(const char *func, const QObject *sender, const QObject *receiver)
2617{
2618 QString a = sender ? sender->objectName() : QString();
2619 QString b = receiver ? receiver->objectName() : QString();
2620 if (!a.isEmpty())
2621 qCWarning(lcConnect, "QObject::%s: (sender name: '%s')", func, a.toLocal8Bit().data());
2622 if (!b.isEmpty())
2623 qCWarning(lcConnect, "QObject::%s: (receiver name: '%s')", func, b.toLocal8Bit().data());
2624}
2625
2626/*!
2627 Returns a pointer to the object that sent the signal, if called in
2628 a slot activated by a signal; otherwise it returns \nullptr. The pointer
2629 is valid only during the execution of the slot that calls this
2630 function from this object's thread context.
2631
2632 The pointer returned by this function becomes invalid if the
2633 sender is destroyed, or if the slot is disconnected from the
2634 sender's signal.
2635
2636 \warning This function violates the object-oriented principle of
2637 modularity. However, getting access to the sender might be useful
2638 when many signals are connected to a single slot.
2639
2640 \warning As mentioned above, the return value of this function is
2641 not valid when the slot is called via a Qt::DirectConnection from
2642 a thread different from this object's thread. Do not use this
2643 function in this type of scenario.
2644
2645 \sa senderSignalIndex()
2646*/
2647
2648QObject *QObject::sender() const
2649{
2650 Q_D(const QObject);
2651
2652 QMutexLocker locker(signalSlotLock(o: this));
2653 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2654 if (!cd || !cd->currentSender)
2655 return nullptr;
2656
2657 for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2658 if (c->sender == cd->currentSender->sender)
2659 return cd->currentSender->sender;
2660 }
2661
2662 return nullptr;
2663}
2664
2665/*!
2666 \since 4.8
2667
2668 Returns the meta-method index of the signal that called the currently
2669 executing slot, which is a member of the class returned by sender().
2670 If called outside of a slot activated by a signal, -1 is returned.
2671
2672 For signals with default parameters, this function will always return
2673 the index with all parameters, regardless of which was used with
2674 connect(). For example, the signal \c {destroyed(QObject *obj = \nullptr)}
2675 will have two different indexes (with and without the parameter), but
2676 this function will always return the index with a parameter. This does
2677 not apply when overloading signals with different parameters.
2678
2679 \warning This function violates the object-oriented principle of
2680 modularity. However, getting access to the signal index might be useful
2681 when many signals are connected to a single slot.
2682
2683 \warning The return value of this function is not valid when the slot
2684 is called via a Qt::DirectConnection from a thread different from this
2685 object's thread. Do not use this function in this type of scenario.
2686
2687 \sa sender(), QMetaObject::indexOfSignal(), QMetaObject::method()
2688*/
2689
2690int QObject::senderSignalIndex() const
2691{
2692 Q_D(const QObject);
2693
2694 QMutexLocker locker(signalSlotLock(o: this));
2695 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2696 if (!cd || !cd->currentSender)
2697 return -1;
2698
2699 for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2700 if (c->sender == cd->currentSender->sender) {
2701 // Convert from signal range to method range
2702 return QMetaObjectPrivate::signal(m: c->sender->metaObject(), signal_index: cd->currentSender->signal).methodIndex();
2703 }
2704 }
2705
2706 return -1;
2707}
2708
2709/*!
2710 Returns the number of receivers connected to the \a signal.
2711
2712 Since both slots and signals can be used as receivers for signals,
2713 and the same connections can be made many times, the number of
2714 receivers is the same as the number of connections made from this
2715 signal.
2716
2717 When calling this function, you can use the \c SIGNAL() macro to
2718 pass a specific signal:
2719
2720 \snippet code/src_corelib_kernel_qobject.cpp 21
2721
2722 As the code snippet above illustrates, you can use this function to avoid
2723 expensive operations or emitting a signal that nobody listens to.
2724
2725 \warning In a multithreaded application, consecutive calls to this
2726 function are not guaranteed to yield the same results.
2727
2728 \warning This function violates the object-oriented principle of
2729 modularity. In particular, this function must not be called from an
2730 override of connectNotify() or disconnectNotify(), as those might get
2731 called from any thread.
2732
2733 \sa isSignalConnected()
2734*/
2735
2736int QObject::receivers(const char *signal) const
2737{
2738 Q_D(const QObject);
2739 int receivers = 0;
2740 if (signal) {
2741 QByteArray signal_name = QMetaObject::normalizedSignature(method: signal);
2742 signal = signal_name;
2743#ifndef QT_NO_DEBUG
2744 if (!check_signal_macro(sender: this, signal, func: "receivers", op: "bind"))
2745 return 0;
2746#endif
2747 signal++; // skip code
2748 int signal_index = d->signalIndex(signalName: signal);
2749 if (signal_index < 0) {
2750#ifndef QT_NO_DEBUG
2751 err_method_notfound(object: this, method: signal - 1, func: "receivers");
2752#endif
2753 return 0;
2754 }
2755
2756 if (!d->isSignalConnected(signalIndex: signal_index))
2757 return receivers;
2758
2759 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::receivers) {
2760 receivers += QAbstractDeclarativeData::receivers(d->declarativeData, this,
2761 signal_index);
2762 }
2763
2764 QMutexLocker locker(signalSlotLock(o: this));
2765 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2766 if (cd && signal_index < cd->signalVectorCount()) {
2767 const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(i: signal_index).first.loadRelaxed();
2768 while (c) {
2769 receivers += c->receiver.loadRelaxed() ? 1 : 0;
2770 c = c->nextConnectionList.loadRelaxed();
2771 }
2772 }
2773 }
2774 return receivers;
2775}
2776
2777/*!
2778 \since 5.0
2779 Returns \c true if the \a signal is connected to at least one receiver,
2780 otherwise returns \c false.
2781
2782 \a signal must be a signal member of this object, otherwise the behaviour
2783 is undefined.
2784
2785 \snippet code/src_corelib_kernel_qobject.cpp 49
2786
2787 As the code snippet above illustrates, you can use this function to avoid
2788 expensive operations or emitting a signal that nobody listens to.
2789
2790 \warning In a multithreaded application, consecutive calls to this
2791 function are not guaranteed to yield the same results.
2792
2793 \warning This function violates the object-oriented principle of
2794 modularity. In particular, this function must not be called from an
2795 override of connectNotify() or disconnectNotify(), as those might get
2796 called from any thread.
2797
2798 \sa receivers()
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 an expensive operation only if something is connected to a signal.
3481
3482 \warning This function is called from the thread which performs the
3483 connection, which may be a different thread from the thread in which
3484 this object lives. This function may also be called with a QObject internal
3485 mutex locked. It is therefore not allowed to re-enter any QObject
3486 functions, including isSignalConnected(), from your reimplementation. If
3487 you lock a mutex in your reimplementation, make sure that you don't call
3488 QObject functions with that mutex held in other places or it will result in
3489 a deadlock.
3490
3491 \sa connect(), disconnectNotify()
3492*/
3493
3494void QObject::connectNotify(const QMetaMethod &signal)
3495{
3496 Q_UNUSED(signal);
3497}
3498
3499/*!
3500 \since 5.0
3501
3502 This virtual function is called when something has been
3503 disconnected from \a signal in this object.
3504
3505 See connectNotify() for an example of how to compare
3506 \a signal with a specific signal.
3507
3508 If all signals were disconnected from this object (e.g., the
3509 signal argument to disconnect() was \nullptr), disconnectNotify()
3510 is only called once, and the \a signal will be an invalid
3511 QMetaMethod (QMetaMethod::isValid() returns \c false).
3512
3513 \warning This function violates the object-oriented principle of
3514 modularity. However, it might be useful for optimizing access to
3515 expensive resources.
3516
3517 \warning This function is called from the thread which performs the
3518 disconnection, which may be a different thread from the thread in which
3519 this object lives. This function may also be called with a QObject internal
3520 mutex locked. It is therefore not allowed to re-enter any QObject
3521 functions, including isSignalConnected(), from your reimplementation. If
3522 you lock a mutex in your reimplementation, make sure that you don't call
3523 QObject functions with that mutex held in other places or it will result in
3524 a deadlock.
3525
3526 \sa disconnect(), connectNotify()
3527*/
3528
3529void QObject::disconnectNotify(const QMetaMethod &signal)
3530{
3531 Q_UNUSED(signal);
3532}
3533
3534/*
3535 \internal
3536 convert a signal index from the method range to the signal range
3537 */
3538static int methodIndexToSignalIndex(const QMetaObject **base, int signal_index)
3539{
3540 if (signal_index < 0)
3541 return signal_index;
3542 const QMetaObject *metaObject = *base;
3543 while (metaObject && metaObject->methodOffset() > signal_index)
3544 metaObject = metaObject->superClass();
3545
3546 if (metaObject) {
3547 int signalOffset, methodOffset;
3548 computeOffsets(metaobject: metaObject, signalOffset: &signalOffset, methodOffset: &methodOffset);
3549 if (signal_index < metaObject->methodCount())
3550 signal_index = QMetaObjectPrivate::originalClone(obj: metaObject, local_method_index: signal_index - methodOffset) + signalOffset;
3551 else
3552 signal_index = signal_index - methodOffset + signalOffset;
3553 *base = metaObject;
3554 }
3555 return signal_index;
3556}
3557
3558/*!
3559 \internal
3560 \a types is a 0-terminated vector of meta types for queued
3561 connections.
3562
3563 if \a signal_index is -1, then we effectively connect *all* signals
3564 from the sender to the receiver's slot
3565 */
3566QMetaObject::Connection QMetaObject::connect(const QObject *sender, int signal_index,
3567 const QObject *receiver, int method_index, int type,
3568 int *types)
3569{
3570 const QMetaObject *smeta = sender->metaObject();
3571 signal_index = methodIndexToSignalIndex(base: &smeta, signal_index);
3572 return Connection(QMetaObjectPrivate::connect(sender, signal_index, smeta,
3573 receiver, method_index_relative: method_index,
3574 rmeta: nullptr, //FIXME, we could speed this connection up by computing the relative index
3575 type, types));
3576}
3577
3578/*!
3579 \internal
3580 Same as the QMetaObject::connect, but \a signal_index must be the result of QObjectPrivate::signalIndex
3581
3582 method_index is relative to the rmeta metaobject, if rmeta is \nullptr, then it is absolute index
3583
3584 the QObjectPrivate::Connection* has a refcount of 2, so it must be passed to a QMetaObject::Connection
3585 */
3586QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender,
3587 int signal_index, const QMetaObject *smeta,
3588 const QObject *receiver, int method_index,
3589 const QMetaObject *rmeta, int type, int *types)
3590{
3591 QObject *s = const_cast<QObject *>(sender);
3592 QObject *r = const_cast<QObject *>(receiver);
3593
3594 int method_offset = rmeta ? rmeta->methodOffset() : 0;
3595 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 6);
3596 QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall : nullptr;
3597
3598 QOrderedMutexLocker locker(signalSlotLock(o: sender),
3599 signalSlotLock(o: receiver));
3600
3601 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(o: s)->connections.loadRelaxed();
3602 if (type & Qt::UniqueConnection && scd) {
3603 if (scd->signalVectorCount() > signal_index) {
3604 const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(i: signal_index).first.loadRelaxed();
3605
3606 int method_index_absolute = method_index + method_offset;
3607
3608 while (c2) {
3609 if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute)
3610 return nullptr;
3611 c2 = c2->nextConnectionList.loadRelaxed();
3612 }
3613 }
3614 }
3615 type &= ~Qt::UniqueConnection;
3616
3617 const bool isSingleShot = type & Qt::SingleShotConnection;
3618 type &= ~Qt::SingleShotConnection;
3619
3620 Q_ASSERT(type >= 0);
3621 Q_ASSERT(type <= 3);
3622
3623 std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
3624 c->sender = s;
3625 c->signal_index = signal_index;
3626 c->receiver.storeRelaxed(newValue: r);
3627 QThreadData *td = r->d_func()->threadData.loadAcquire();
3628 td->ref();
3629 c->receiverThreadData.storeRelaxed(newValue: td);
3630 c->method_relative = method_index;
3631 c->method_offset = method_offset;
3632 c->connectionType = type;
3633 c->isSlotObject = false;
3634 c->argumentTypes.storeRelaxed(newValue: types);
3635 c->callFunction = callFunction;
3636 c->isSingleShot = isSingleShot;
3637
3638 QObjectPrivate::get(o: s)->addConnection(signal: signal_index, c: c.get());
3639
3640 locker.unlock();
3641 QMetaMethod smethod = QMetaObjectPrivate::signal(m: smeta, signal_index);
3642 if (smethod.isValid())
3643 s->connectNotify(signal: smethod);
3644
3645 return c.release();
3646}
3647
3648/*!
3649 \internal
3650 */
3651bool QMetaObject::disconnect(const QObject *sender, int signal_index,
3652 const QObject *receiver, int method_index)
3653{
3654 const QMetaObject *smeta = sender->metaObject();
3655 signal_index = methodIndexToSignalIndex(base: &smeta, signal_index);
3656 return QMetaObjectPrivate::disconnect(sender, signal_index, smeta,
3657 receiver, method_index, slot: nullptr);
3658}
3659
3660/*!
3661 \internal
3662
3663Disconnect a single signal connection. If QMetaObject::connect() has been called
3664multiple times for the same sender, signal_index, receiver and method_index only
3665one of these connections will be removed.
3666 */
3667bool QMetaObject::disconnectOne(const QObject *sender, int signal_index,
3668 const QObject *receiver, int method_index)
3669{
3670 const QMetaObject *smeta = sender->metaObject();
3671 signal_index = methodIndexToSignalIndex(base: &smeta, signal_index);
3672 return QMetaObjectPrivate::disconnect(sender, signal_index, smeta,
3673 receiver, method_index, slot: nullptr,
3674 QMetaObjectPrivate::DisconnectOne);
3675}
3676
3677/*!
3678 \internal
3679 Helper function to remove the connection from the senders list and set the receivers to \nullptr
3680 */
3681bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::ConnectionData *connections, int signalIndex,
3682 const QObject *receiver, int method_index, void **slot,
3683 QBasicMutex *senderMutex, DisconnectType disconnectType)
3684{
3685 bool success = false;
3686
3687 auto &connectionList = connections->connectionsForSignal(signal: signalIndex);
3688 auto *c = connectionList.first.loadRelaxed();
3689 while (c) {
3690 QObject *r = c->receiver.loadRelaxed();
3691 if (r && (receiver == nullptr || (r == receiver
3692 && (method_index < 0 || (!c->isSlotObject && c->method() == method_index))
3693 && (slot == nullptr || (c->isSlotObject && c->slotObj->compare(a: slot)))))) {
3694 bool needToUnlock = false;
3695 QBasicMutex *receiverMutex = nullptr;
3696 if (r) {
3697 receiverMutex = signalSlotLock(o: r);
3698 // need to relock this receiver and sender in the correct order
3699 needToUnlock = QOrderedMutexLocker::relock(mtx1: senderMutex, mtx2: receiverMutex);
3700 }
3701 if (c->receiver.loadRelaxed())
3702 connections->removeConnection(c);
3703
3704 if (needToUnlock)
3705 receiverMutex->unlock();
3706
3707 success = true;
3708
3709 if (disconnectType == DisconnectOne)
3710 return success;
3711 }
3712 c = c->nextConnectionList.loadRelaxed();
3713 }
3714 return success;
3715}
3716
3717/*!
3718 \internal
3719 Same as the QMetaObject::disconnect, but \a signal_index must be the result of QObjectPrivate::signalIndex
3720 */
3721bool QMetaObjectPrivate::disconnect(const QObject *sender,
3722 int signal_index, const QMetaObject *smeta,
3723 const QObject *receiver, int method_index, void **slot,
3724 DisconnectType disconnectType)
3725{
3726 if (!sender)
3727 return false;
3728
3729 QObject *s = const_cast<QObject *>(sender);
3730
3731 QBasicMutex *senderMutex = signalSlotLock(o: sender);
3732 QMutexLocker locker(senderMutex);
3733
3734 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(o: s)->connections.loadRelaxed();
3735 if (!scd)
3736 return false;
3737
3738 bool success = false;
3739 {
3740 // prevent incoming connections changing the connections->receivers while unlocked
3741 QObjectPrivate::ConnectionDataPointer connections(scd);
3742
3743 if (signal_index < 0) {
3744 // remove from all connection lists
3745 for (int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
3746 if (disconnectHelper(connections: connections.data(), signalIndex: sig_index, receiver, method_index, slot, senderMutex, disconnectType))
3747 success = true;
3748 }
3749 } else if (signal_index < scd->signalVectorCount()) {
3750 if (disconnectHelper(connections: connections.data(), signalIndex: signal_index, receiver, method_index, slot, senderMutex, disconnectType))
3751 success = true;
3752 }
3753 }
3754
3755 locker.unlock();
3756 if (success) {
3757 scd->cleanOrphanedConnections(sender: s);
3758
3759 QMetaMethod smethod = QMetaObjectPrivate::signal(m: smeta, signal_index);
3760 if (smethod.isValid())
3761 s->disconnectNotify(signal: smethod);
3762 }
3763
3764 return success;
3765}
3766
3767// Helpers for formatting the connect statements of connectSlotsByName()'s debug mode
3768static QByteArray formatConnectionSignature(const char *className, const QMetaMethod &method)
3769{
3770 const auto signature = method.methodSignature();
3771 Q_ASSERT(signature.endsWith(')'));
3772 const int openParen = signature.indexOf(c: '(');
3773 const bool hasParameters = openParen >= 0 && openParen < signature.size() - 2;
3774 QByteArray result;
3775 if (hasParameters) {
3776 result += "qOverload<"
3777 + signature.mid(index: openParen + 1, len: signature.size() - openParen - 2) + ">(";
3778 }
3779 result += '&';
3780 result += className + QByteArrayLiteral("::") + method.name();
3781 if (hasParameters)
3782 result += ')';
3783 return result;
3784}
3785
3786static QByteArray msgConnect(const QMetaObject *senderMo, const QByteArray &senderName,
3787 const QMetaMethod &signal, const QObject *receiver, int receiverIndex)
3788{
3789 const auto receiverMo = receiver->metaObject();
3790 const auto slot = receiverMo->method(index: receiverIndex);
3791 QByteArray message = QByteArrayLiteral("QObject::connect(")
3792 + senderName + ", " + formatConnectionSignature(className: senderMo->className(), method: signal)
3793 + ", " + receiver->objectName().toLatin1() + ", "
3794 + formatConnectionSignature(className: receiverMo->className(), method: slot) + ");";
3795 return message;
3796}
3797
3798/*!
3799 \fn void QMetaObject::connectSlotsByName(QObject *object)
3800
3801 Searches recursively for all child objects of the given \a object, and connects
3802 matching signals from them to slots of \a object that follow the following form:
3803
3804 \snippet code/src_corelib_kernel_qobject.cpp 33
3805
3806 Let's assume our object has a child object of type \c{QPushButton} with
3807 the \l{QObject::objectName}{object name} \c{button1}. The slot to catch the
3808 button's \c{clicked()} signal would be:
3809
3810 \snippet code/src_corelib_kernel_qobject.cpp 34
3811
3812 If \a object itself has a properly set object name, its own signals are also
3813 connected to its respective slots.
3814
3815 \sa QObject::setObjectName()
3816 */
3817void QMetaObject::connectSlotsByName(QObject *o)
3818{
3819 if (!o)
3820 return;
3821 const QMetaObject *mo = o->metaObject();
3822 Q_ASSERT(mo);
3823 const QObjectList list = // list of all objects to look for matching signals including...
3824 o->findChildren<QObject *>() // all children of 'o'...
3825 << o; // and the object 'o' itself
3826
3827 // for each method/slot of o ...
3828 for (int i = 0; i < mo->methodCount(); ++i) {
3829 const QByteArray slotSignature = mo->method(index: i).methodSignature();
3830 const char *slot = slotSignature.constData();
3831 Q_ASSERT(slot);
3832
3833 // ...that starts with "on_", ...
3834 if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
3835 continue;
3836
3837 // ...we check each object in our list, ...
3838 bool foundIt = false;
3839 for (int j = 0; j < list.size(); ++j) {
3840 const QObject *co = list.at(i: j);
3841 const QByteArray coName = co->objectName().toLatin1();
3842
3843 // ...discarding those whose objectName is not fitting the pattern "on_<objectName>_...", ...
3844 if (coName.isEmpty() || qstrncmp(str1: slot + 3, str2: coName.constData(), len: coName.size()) || slot[coName.size()+3] != '_')
3845 continue;
3846
3847 const char *signal = slot + coName.size() + 4; // the 'signal' part of the slot name
3848
3849 // ...for the presence of a matching signal "on_<objectName>_<signal>".
3850 const QMetaObject *smeta;
3851 int sigIndex = co->d_func()->signalIndex(signalName: signal, meta: &smeta);
3852 if (sigIndex < 0) {
3853 // if no exactly fitting signal (name + complete parameter type list) could be found
3854 // look for just any signal with the correct name and at least the slot's parameter list.
3855 // Note: if more than one of those signals exist, the one that gets connected is
3856 // chosen 'at random' (order of declaration in source file)
3857 QList<QByteArray> compatibleSignals;
3858 const QMetaObject *smo = co->metaObject();
3859 int sigLen = int(qstrlen(str: signal)) - 1; // ignore the trailing ')'
3860 for (int k = QMetaObjectPrivate::absoluteSignalCount(m: smo)-1; k >= 0; --k) {
3861 const QMetaMethod method = QMetaObjectPrivate::signal(m: smo, signal_index: k);
3862 if (!qstrncmp(str1: method.methodSignature().constData(), str2: signal, len: sigLen)) {
3863 smeta = method.enclosingMetaObject();
3864 sigIndex = k;
3865 compatibleSignals.prepend(t: method.methodSignature());
3866 }
3867 }
3868 if (compatibleSignals.size() > 1)
3869 qCWarning(lcConnectSlotsByName) << "QMetaObject::connectSlotsByName: Connecting slot" << slot
3870 << "with the first of the following compatible signals:" << compatibleSignals;
3871 }
3872
3873 if (sigIndex < 0)
3874 continue;
3875
3876 // we connect it...
3877 if (Connection(QMetaObjectPrivate::connect(sender: co, signal_index: sigIndex, smeta, receiver: o, method_index: i))) {
3878 foundIt = true;
3879 qCDebug(lcConnectSlotsByName, "%s",
3880 msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData());
3881 // ...and stop looking for further objects with the same name.
3882 // Note: the Designer will make sure each object name is unique in the above
3883 // 'list' but other code may create two child objects with the same name. In
3884 // this case one is chosen 'at random'.
3885 break;
3886 }
3887 }
3888 if (foundIt) {
3889 // we found our slot, now skip all overloads
3890 while (mo->method(index: i + 1).attributes() & QMetaMethod::Cloned)
3891 ++i;
3892 } else if (!(mo->method(index: i).attributes() & QMetaMethod::Cloned)) {
3893 // check if the slot has the following signature: "on_..._...(..."
3894 int iParen = slotSignature.indexOf(c: '(');
3895 int iLastUnderscore = slotSignature.lastIndexOf(c: '_', from: iParen - 1);
3896 if (iLastUnderscore > 3)
3897 qCWarning(lcConnectSlotsByName,
3898 "QMetaObject::connectSlotsByName: No matching signal for %s", slot);
3899 }
3900 }
3901}
3902
3903/*!
3904 \internal
3905 A small RAII helper for QSlotObjectBase.
3906 Calls ref on construction and destroyLastRef in its dtor.
3907 Allows construction from a nullptr in which case it does nothing.
3908 */
3909struct SlotObjectGuard {
3910 SlotObjectGuard() = default;
3911 // move would be fine, but we do not need it currently
3912 Q_DISABLE_COPY_MOVE(SlotObjectGuard)
3913 Q_NODISCARD_CTOR explicit SlotObjectGuard(QtPrivate::QSlotObjectBase *slotObject)
3914 : m_slotObject(slotObject)
3915 {
3916 if (m_slotObject)
3917 m_slotObject->ref();
3918 }
3919
3920 QtPrivate::QSlotObjectBase const *operator->() const
3921 { return m_slotObject.get(); }
3922
3923 QtPrivate::QSlotObjectBase *operator->()
3924 { return m_slotObject.get(); }
3925
3926 ~SlotObjectGuard() = default;
3927private:
3928 QtPrivate::SlotObjUniquePtr m_slotObject;
3929};
3930
3931/*!
3932 \internal
3933
3934 \a signal must be in the signal index range (see QObjectPrivate::signalIndex()).
3935*/
3936static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv)
3937{
3938 const int *argumentTypes = c->argumentTypes.loadRelaxed();
3939 if (!argumentTypes) {
3940 QMetaMethod m = QMetaObjectPrivate::signal(m: sender->metaObject(), signal_index: signal);
3941 argumentTypes = queuedConnectionTypes(method: m);
3942 if (!argumentTypes) // cannot queue arguments
3943 argumentTypes = &DIRECT_CONNECTION_ONLY;
3944 if (!c->argumentTypes.testAndSetOrdered(expectedValue: nullptr, newValue: argumentTypes)) {
3945 if (argumentTypes != &DIRECT_CONNECTION_ONLY)
3946 delete[] argumentTypes;
3947 argumentTypes = c->argumentTypes.loadRelaxed();
3948 }
3949 }
3950 if (argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate
3951 return;
3952 int nargs = 1; // include return type
3953 while (argumentTypes[nargs - 1])
3954 ++nargs;
3955
3956 QMutexLocker locker(signalSlotLock(o: c->receiver.loadRelaxed()));
3957 QObject *receiver = c->receiver.loadRelaxed();
3958 if (!receiver) {
3959 // the connection has been disconnected before we got the lock
3960 return;
3961 }
3962
3963 SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj : nullptr };
3964 locker.unlock();
3965
3966 QMetaCallEvent *ev = c->isSlotObject ?
3967 new QMetaCallEvent(c->slotObj, sender, signal, nargs) :
3968 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs);
3969
3970 void **args = ev->args();
3971 QMetaType *types = ev->types();
3972
3973 types[0] = QMetaType(); // return type
3974 args[0] = nullptr; // return value
3975
3976 if (nargs > 1) {
3977 for (int n = 1; n < nargs; ++n)
3978 types[n] = QMetaType(argumentTypes[n - 1]);
3979
3980 for (int n = 1; n < nargs; ++n)
3981 args[n] = types[n].create(copy: argv[n]);
3982 }
3983
3984 if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) {
3985 delete ev;
3986 return;
3987 }
3988
3989 locker.relock();
3990 if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
3991 // the connection has been disconnected while we were unlocked
3992 locker.unlock();
3993 delete ev;
3994 return;
3995 }
3996
3997 QCoreApplication::postEvent(receiver, event: ev);
3998}
3999
4000template <bool callbacks_enabled>
4001void doActivate(QObject *sender, int signal_index, void **argv)
4002{
4003 QObjectPrivate *sp = QObjectPrivate::get(o: sender);
4004
4005 if (sp->blockSig)
4006 return;
4007
4008 Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
4009
4010 if (sp->isDeclarativeSignalConnected(signal_index)
4011 && QAbstractDeclarativeData::signalEmitted) {
4012 Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
4013 QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
4014 signal_index, argv);
4015 }
4016
4017 const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() : nullptr;
4018
4019 void *empty_argv[] = { nullptr };
4020 if (!argv)
4021 argv = empty_argv;
4022
4023 if (!sp->maybeSignalConnected(signalIndex: signal_index)) {
4024 // The possible declarative connection is done, and nothing else is connected
4025 if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
4026 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4027 if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
4028 signal_spy_set->signal_end_callback(sender, signal_index);
4029 return;
4030 }
4031
4032 if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
4033 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4034
4035 bool senderDeleted = false;
4036 {
4037 Q_ASSERT(sp->connections.loadRelaxed());
4038 QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadAcquire());
4039 QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();
4040
4041 const QObjectPrivate::ConnectionList *list;
4042 if (signal_index < signalVector->count())
4043 list = &signalVector->at(i: signal_index);
4044 else
4045 list = &signalVector->at(i: -1);
4046
4047 Qt::HANDLE currentThreadId = QThread::currentThreadId();
4048 bool inSenderThread = currentThreadId == QObjectPrivate::get(o: sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
4049
4050 // We need to check against the highest connection id to ensure that signals added
4051 // during the signal emission are not emitted in this emission.
4052 uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
4053 do {
4054 QObjectPrivate::Connection *c = list->first.loadRelaxed();
4055 if (!c)
4056 continue;
4057
4058 do {
4059 QObject * const receiver = c->receiver.loadRelaxed();
4060 if (!receiver)
4061 continue;
4062
4063 QThreadData *td = c->receiverThreadData.loadRelaxed();
4064 if (!td)
4065 continue;
4066
4067 bool receiverInSameThread;
4068 if (inSenderThread) {
4069 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4070 } else {
4071 // need to lock before reading the threadId, because moveToThread() could interfere
4072 QMutexLocker lock(signalSlotLock(o: receiver));
4073 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4074 }
4075
4076
4077 // determine if this connection should be sent immediately or
4078 // put into the event queue
4079 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
4080 || (c->connectionType == Qt::QueuedConnection)) {
4081 queued_activate(sender, signal: signal_index, c, argv);
4082 continue;
4083#if QT_CONFIG(thread)
4084 } else if (c->connectionType == Qt::BlockingQueuedConnection) {
4085 if (receiverInSameThread) {
4086 qWarning(msg: "Qt: Dead lock detected while activating a BlockingQueuedConnection: "
4087 "Sender is %s(%p), receiver is %s(%p)",
4088 sender->metaObject()->className(), sender,
4089 receiver->metaObject()->className(), receiver);
4090 }
4091
4092 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4093 continue;
4094
4095 QSemaphore semaphore;
4096 {
4097 QMutexLocker locker(signalSlotLock(o: receiver));
4098 if (!c->isSingleShot && !c->receiver.loadAcquire())
4099 continue;
4100 QMetaCallEvent *ev = c->isSlotObject ?
4101 new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &semaphore) :
4102 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
4103 sender, signal_index, argv, &semaphore);
4104 QCoreApplication::postEvent(receiver, event: ev);
4105 }
4106 semaphore.acquire();
4107 continue;
4108#endif
4109 }
4110
4111 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4112 continue;
4113
4114 QObjectPrivate::Sender senderData(
4115 receiverInSameThread ? receiver : nullptr, sender, signal_index,
4116 receiverInSameThread ? QObjectPrivate::get(o: receiver)->connections.loadAcquire() : nullptr);
4117
4118 if (c->isSlotObject) {
4119 SlotObjectGuard obj{c->slotObj};
4120
4121 {
4122 Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
4123 obj->call(r: receiver, a: argv);
4124 }
4125 } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
4126 //we compare the vtable to make sure we are not in the destructor of the object.
4127 const int method_relative = c->method_relative;
4128 const auto callFunction = c->callFunction;
4129 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
4130 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)
4131 signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
4132
4133 {
4134 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
4135 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
4136 }
4137
4138 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
4139 signal_spy_set->slot_end_callback(receiver, methodIndex);
4140 } else {
4141 const int method = c->method_relative + c->method_offset;
4142
4143 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {
4144 signal_spy_set->slot_begin_callback(receiver, method, argv);
4145 }
4146
4147 {
4148 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
4149 QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
4150 }
4151
4152 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
4153 signal_spy_set->slot_end_callback(receiver, method);
4154 }
4155 } while ((c = c->nextConnectionList.loadRelaxed()) != nullptr && c->id <= highestConnectionId);
4156
4157 } while (list != &signalVector->at(i: -1) &&
4158 //start over for all signals;
4159 ((list = &signalVector->at(i: -1)), true));
4160
4161 if (connections->currentConnectionId.loadRelaxed() == 0)
4162 senderDeleted = true;
4163 }
4164 if (!senderDeleted) {
4165 sp->connections.loadAcquire()->cleanOrphanedConnections(sender);
4166
4167 if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
4168 signal_spy_set->signal_end_callback(sender, signal_index);
4169 }
4170}
4171
4172/*!
4173 \internal
4174 */
4175void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
4176 void **argv)
4177{
4178 int signal_index = local_signal_index + QMetaObjectPrivate::signalOffset(m);
4179
4180 if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
4181 doActivate<true>(sender, signal_index, argv);
4182 else
4183 doActivate<false>(sender, signal_index, argv);
4184}
4185
4186/*!
4187 \internal
4188 */
4189void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
4190{
4191 int signal_index = signalOffset + local_signal_index;
4192
4193 if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
4194 doActivate<true>(sender, signal_index, argv);
4195 else
4196 doActivate<false>(sender, signal_index, argv);
4197}
4198
4199/*!
4200 \internal
4201 signal_index comes from indexOfMethod()
4202*/
4203void QMetaObject::activate(QObject *sender, int signal_index, void **argv)
4204{
4205 const QMetaObject *mo = sender->metaObject();
4206 while (mo->methodOffset() > signal_index)
4207 mo = mo->superClass();
4208 activate(sender, m: mo, local_signal_index: signal_index - mo->methodOffset(), argv);
4209}
4210
4211/*!
4212 \internal
4213 Returns the signal index used in the internal connections->receivers vector.
4214
4215 It is different from QMetaObject::indexOfSignal(): indexOfSignal is the same as indexOfMethod
4216 while QObjectPrivate::signalIndex is smaller because it doesn't give index to slots.
4217
4218 If \a meta is not \nullptr, it is set to the meta-object where the signal was found.
4219*/
4220int QObjectPrivate::signalIndex(const char *signalName,
4221 const QMetaObject **meta) const
4222{
4223 Q_Q(const QObject);
4224 const QMetaObject *base = q->metaObject();
4225 Q_ASSERT(QMetaObjectPrivate::get(base)->revision >= 7);
4226 QArgumentTypeArray types;
4227 QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signature: signalName, types);
4228 int relative_index = QMetaObjectPrivate::indexOfSignalRelative(
4229 baseObject: &base, name, argc: types.size(), types: types.constData());
4230 if (relative_index < 0)
4231 return relative_index;
4232 relative_index = QMetaObjectPrivate::originalClone(obj: base, local_method_index: relative_index);
4233 if (meta)
4234 *meta = base;
4235 return relative_index + QMetaObjectPrivate::signalOffset(m: base);
4236}
4237
4238/*****************************************************************************
4239 Properties
4240 *****************************************************************************/
4241
4242/*!
4243 \fn bool QObject::setProperty(const char *name, const QVariant &value)
4244
4245 Sets the value of the object's \a name property to \a value.
4246
4247 If the property is defined in the class using Q_PROPERTY then
4248 true is returned on success and false otherwise. If the property
4249 is not defined using Q_PROPERTY, and therefore not listed in the
4250 meta-object, it is added as a dynamic property and false is returned.
4251
4252 Information about all available properties is provided through the
4253 metaObject() and dynamicPropertyNames().
4254
4255 Dynamic properties can be queried again using property() and can be
4256 removed by setting the property value to an invalid QVariant.
4257 Changing the value of a dynamic property causes a QDynamicPropertyChangeEvent
4258 to be sent to the object.
4259
4260 \b{Note:} Dynamic properties starting with "_q_" are reserved for internal
4261 purposes.
4262
4263 \sa property(), metaObject(), dynamicPropertyNames(), QMetaProperty::write()
4264*/
4265
4266/*!
4267 \fn bool QObject::setProperty(const char *name, QVariant &&value)
4268 \since 6.6
4269 \overload setProperty
4270*/
4271
4272bool QObject::doSetProperty(const char *name, const QVariant *lvalue, QVariant *rvalue)
4273{
4274 Q_D(QObject);
4275 const auto &value =*lvalue;
4276 const QMetaObject *meta = metaObject();
4277 if (!name || !meta)
4278 return false;
4279
4280 int id = meta->indexOfProperty(name);
4281 if (id < 0) {
4282 d->ensureExtraData();
4283
4284 const int idx = d->extraData->propertyNames.indexOf(t: name);
4285
4286 if (!value.isValid()) {
4287 if (idx == -1)
4288 return false;
4289 d->extraData->propertyNames.removeAt(i: idx);
4290 d->extraData->propertyValues.removeAt(i: idx);
4291 } else {
4292 if (idx == -1) {
4293 d->extraData->propertyNames.append(t: name);
4294 if (rvalue)
4295 d->extraData->propertyValues.append(t: std::move(*rvalue));
4296 else
4297 d->extraData->propertyValues.append(t: *lvalue);
4298 } else {
4299 if (value.userType() == d->extraData->propertyValues.at(i: idx).userType()
4300 && value == d->extraData->propertyValues.at(i: idx))
4301 return false;
4302 if (rvalue)
4303 d->extraData->propertyValues[idx] = std::move(*rvalue);
4304 else
4305 d->extraData->propertyValues[idx] = *lvalue;
4306 }
4307 }
4308
4309 QDynamicPropertyChangeEvent ev(name);
4310 QCoreApplication::sendEvent(receiver: this, event: &ev);
4311
4312 return false;
4313 }
4314 QMetaProperty p = meta->property(index: id);
4315#ifndef QT_NO_DEBUG
4316 if (!p.isWritable())
4317 qWarning(msg: "%s::setProperty: Property \"%s\" invalid,"
4318 " read-only or does not exist", metaObject()->className(), name);
4319#endif
4320 return rvalue ? p.write(obj: this, value: std::move(*rvalue)) : p.write(obj: this, value: *lvalue);
4321}
4322
4323/*!
4324 Returns the value of the object's \a name property.
4325
4326 If no such property exists, the returned variant is invalid.
4327
4328 Information about all available properties is provided through the
4329 metaObject() and dynamicPropertyNames().
4330
4331 \sa setProperty(), QVariant::isValid(), metaObject(), dynamicPropertyNames()
4332*/
4333QVariant QObject::property(const char *name) const
4334{
4335 Q_D(const QObject);
4336 const QMetaObject *meta = metaObject();
4337 if (!name || !meta)
4338 return QVariant();
4339
4340 int id = meta->indexOfProperty(name);
4341 if (id < 0) {
4342 if (!d->extraData)
4343 return QVariant();
4344 const int i = d->extraData->propertyNames.indexOf(t: name);
4345 return d->extraData->propertyValues.value(i);
4346 }
4347 QMetaProperty p = meta->property(index: id);
4348#ifndef QT_NO_DEBUG
4349 if (!p.isReadable())
4350 qWarning(msg: "%s::property: Property \"%s\" invalid or does not exist",
4351 metaObject()->className(), name);
4352#endif
4353 return p.read(obj: this);
4354}
4355
4356/*!
4357 \since 4.2
4358
4359 Returns the names of all properties that were dynamically added to
4360 the object using setProperty().
4361*/
4362QList<QByteArray> QObject::dynamicPropertyNames() const
4363{
4364 Q_D(const QObject);
4365 if (d->extraData)
4366 return d->extraData->propertyNames;
4367 return QList<QByteArray>();
4368}
4369
4370/*****************************************************************************
4371 QObject debugging output routines.
4372 *****************************************************************************/
4373
4374std::string QObjectPrivate::flagsForDumping() const
4375{
4376 return {};
4377}
4378
4379static void dumpRecursive(int level, const QObject *object)
4380{
4381 if (object) {
4382 const int indent = level * 4;
4383 qDebug(msg: "%*s%s::%ls %s", indent, "", object->metaObject()->className(),
4384 qUtf16Printable(object->objectName()),
4385 QObjectPrivate::get(o: object)->flagsForDumping().c_str());
4386 for (auto child : object->children())
4387 dumpRecursive(level: level + 1, object: child);
4388 }
4389}
4390
4391
4392/*!
4393 Dumps a tree of children to the debug output.
4394
4395 \note Before Qt 5.9, this function was not const.
4396
4397 \sa dumpObjectInfo()
4398*/
4399
4400void QObject::dumpObjectTree() const
4401{
4402 dumpRecursive(level: 0, object: this);
4403}
4404
4405/*!
4406 Dumps information about signal connections, etc. for this object
4407 to the debug output.
4408
4409 \note Before Qt 5.9, this function was not const.
4410
4411 \sa dumpObjectTree()
4412*/
4413
4414void QObject::dumpObjectInfo() const
4415{
4416 qDebug(msg: "OBJECT %s::%s", metaObject()->className(),
4417 objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
4418
4419 Q_D(const QObject);
4420 QMutexLocker locker(signalSlotLock(o: this));
4421
4422 // first, look for connections where this object is the sender
4423 qDebug(msg: " SIGNALS OUT");
4424
4425 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
4426 if (cd && cd->signalVectorCount() > 0) {
4427 QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
4428 for (int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
4429 const QObjectPrivate::Connection *c = signalVector->at(i: signal_index).first.loadRelaxed();
4430 if (!c)
4431 continue;
4432 const QMetaMethod signal = QMetaObjectPrivate::signal(m: metaObject(), signal_index);
4433 qDebug(msg: " signal: %s", signal.methodSignature().constData());
4434
4435 // receivers
4436 while (c) {
4437 if (!c->receiver.loadRelaxed()) {
4438 qDebug(msg: " <Disconnected receiver>");
4439 c = c->nextConnectionList.loadRelaxed();
4440 continue;
4441 }
4442 if (c->isSlotObject) {
4443 qDebug(msg: " <functor or function pointer>");
4444 c = c->nextConnectionList.loadRelaxed();
4445 continue;
4446 }
4447 const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
4448 const QMetaMethod method = receiverMetaObject->method(index: c->method());
4449 qDebug(msg: " --> %s::%s %s",
4450 receiverMetaObject->className(),
4451 c->receiver.loadRelaxed()->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
4452 method.methodSignature().constData());
4453 c = c->nextConnectionList.loadRelaxed();
4454 }
4455 }
4456 } else {
4457 qDebug( msg: " <None>" );
4458 }
4459
4460 // now look for connections where this object is the receiver
4461 qDebug(msg: " SIGNALS IN");
4462
4463 if (cd && cd->senders) {
4464 for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
4465 QByteArray slotName = QByteArrayLiteral("<unknown>");
4466 if (!s->isSlotObject) {
4467 const QMetaMethod slot = metaObject()->method(index: s->method());
4468 slotName = slot.methodSignature();
4469 }
4470 qDebug(msg: " <-- %s::%s %s",
4471 s->sender->metaObject()->className(),
4472 s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()),
4473 slotName.constData());
4474 }
4475 } else {
4476 qDebug(msg: " <None>");
4477 }
4478}
4479
4480
4481#ifndef QT_NO_DEBUG_STREAM
4482void QObjectPrivate::writeToDebugStream(QDebug &dbg) const
4483{
4484 Q_Q(const QObject);
4485 dbg.nospace() << q->metaObject()->className() << '(' << (const void *)q;
4486 if (!q->objectName().isEmpty())
4487 dbg << ", name = " << q->objectName();
4488 dbg << ')';
4489}
4490
4491QDebug operator<<(QDebug dbg, const QObject *o)
4492{
4493 QDebugStateSaver saver(dbg);
4494 if (!o)
4495 return dbg << "QObject(0x0)";
4496
4497 const QObjectPrivate *d = QObjectPrivate::get(o);
4498 d->writeToDebugStream(dbg);
4499 return dbg;
4500}
4501#endif
4502
4503/*!
4504 \macro Q_CLASSINFO(Name, Value)
4505 \relates QObject
4506
4507 This macro associates extra information to the class, which is available
4508 using QObject::metaObject(). The extra information takes the form of a
4509 \a Name string and a \a Value literal string.
4510
4511 Example:
4512
4513 \snippet code/src_corelib_kernel_qobject.cpp 35
4514
4515 Qt makes use of the macro in \l{Qt D-Bus} and \l{Qt Qml} modules.
4516 For instance, when defining \l{QML Object Types} in C++, you can
4517 designate a property as the \e default one:
4518
4519 \snippet code/doc_src_properties.cpp 7
4520
4521 \sa QMetaObject::classInfo()
4522 \sa {Using Qt D-Bus Adaptors}
4523 \sa {Defining QML Types from C++}
4524*/
4525
4526/*!
4527 \macro Q_INTERFACES(...)
4528 \relates QObject
4529
4530 This macro tells Qt which interfaces the class implements. This
4531 is used when implementing plugins.
4532
4533 \sa Q_DECLARE_INTERFACE(), Q_PLUGIN_METADATA(), {How to Create Qt Plugins}
4534*/
4535
4536/*!
4537 \macro Q_PROPERTY(...)
4538 \relates QObject
4539
4540 This macro is used for declaring properties in classes that
4541 inherit QObject. Properties behave like class data members, but
4542 they have additional features accessible through the \l
4543 {Meta-Object System}.
4544
4545 \snippet code/doc_src_properties.cpp 0
4546
4547 The property name and type and the \c READ function are required.
4548 The type can be any type supported by QVariant, or it can be a
4549 user-defined type. The other items are optional, but a \c WRITE
4550 function is common. The attributes default to true except \c USER,
4551 which defaults to false.
4552
4553 For example:
4554
4555 \snippet code/src_corelib_kernel_qobject.cpp 37
4556
4557 For more details about how to use this macro, and a more detailed
4558 example of its use, see the discussion on \l {Qt's Property System}.
4559
4560 \sa {Qt's Property System}
4561*/
4562
4563/*!
4564 \macro Q_ENUMS(...)
4565 \relates QObject
4566 \deprecated
4567
4568 In new code, you should prefer the use of the Q_ENUM() macro, which makes the
4569 type available also to the meta type system.
4570 For instance, QMetaEnum::fromType() will not work with types declared with Q_ENUMS().
4571
4572 This macro registers one or several enum types to the meta-object
4573 system.
4574
4575 If you want to register an enum that is declared in another class,
4576 the enum must be fully qualified with the name of the class
4577 defining it. In addition, the class \e defining the enum has to
4578 inherit QObject as well as declare the enum using Q_ENUMS().
4579
4580 \sa {Qt's Property System}
4581*/
4582
4583/*!
4584 \macro Q_FLAGS(...)
4585 \relates QObject
4586 \deprecated
4587
4588 This macro registers one or several \l{QFlags}{flags types} with the
4589 meta-object system. It is typically used in a class definition to declare
4590 that values of a given enum can be used as flags and combined using the
4591 bitwise OR operator.
4592
4593 \note This macro takes care of registering individual flag values
4594 with the meta-object system, so it is unnecessary to use Q_ENUMS()
4595 in addition to this macro.
4596
4597 In new code, you should prefer the use of the Q_FLAG() macro, which makes the
4598 type available also to the meta type system.
4599
4600 \sa {Qt's Property System}
4601*/
4602
4603/*!
4604 \macro Q_ENUM(...)
4605 \relates QObject
4606 \since 5.5
4607
4608 This macro registers an enum type with the meta-object system.
4609 It must be placed after the enum declaration in a class that has the Q_OBJECT,
4610 Q_GADGET or Q_GADGET_EXPORT macro. For namespaces use \l Q_ENUM_NS() instead.
4611
4612 For example:
4613
4614 \snippet code/src_corelib_kernel_qobject.cpp 38
4615
4616 Enumerations that are declared with Q_ENUM have their QMetaEnum registered in the
4617 enclosing QMetaObject. You can also use QMetaEnum::fromType() to get the QMetaEnum.
4618
4619 Registered enumerations are automatically registered also to the Qt meta
4620 type system, making them known to QMetaType without the need to use
4621 Q_DECLARE_METATYPE(). This will enable useful features; for example, if used
4622 in a QVariant, you can convert them to strings. Likewise, passing them to
4623 QDebug will print out their names.
4624
4625 Mind that the enum values are stored as signed \c int in the meta object system.
4626 Registering enumerations with values outside the range of values valid for \c int
4627 will lead to overflows and potentially undefined behavior when accessing them through
4628 the meta object system. QML, for example, does access registered enumerations through
4629 the meta object system.
4630
4631 \sa {Qt's Property System}
4632*/
4633
4634
4635/*!
4636 \macro Q_FLAG(...)
4637 \relates QObject
4638 \since 5.5
4639
4640 This macro registers a single \l{QFlags}{flags type} with the
4641 meta-object system. It is typically used in a class definition to declare
4642 that values of a given enum can be used as flags and combined using the
4643 bitwise OR operator. For namespaces use \l Q_FLAG_NS() instead.
4644
4645 The macro must be placed after the enum declaration. The declaration of
4646 the flags type is done using the \l Q_DECLARE_FLAGS() macro.
4647
4648 For example, in QItemSelectionModel, the
4649 \l{QItemSelectionModel::SelectionFlags}{SelectionFlags} flag is
4650 declared in the following way:
4651
4652 \snippet code/src_corelib_kernel_qobject.cpp 39
4653
4654 \note The Q_FLAG macro takes care of registering individual flag values
4655 with the meta-object system, so it is unnecessary to use Q_ENUM()
4656 in addition to this macro.
4657
4658 \sa {Qt's Property System}
4659*/
4660
4661/*!
4662 \macro Q_ENUM_NS(...)
4663 \relates QObject
4664 \since 5.8
4665
4666 This macro registers an enum type with the meta-object system.
4667 It must be placed after the enum declaration in a namespace that
4668 has the Q_NAMESPACE macro. It is the same as \l Q_ENUM but in a
4669 namespace.
4670
4671 Enumerations that are declared with Q_ENUM_NS have their QMetaEnum
4672 registered in the enclosing QMetaObject. You can also use
4673 QMetaEnum::fromType() to get the QMetaEnum.
4674
4675 Registered enumerations are automatically registered also to the Qt meta
4676 type system, making them known to QMetaType without the need to use
4677 Q_DECLARE_METATYPE(). This will enable useful features; for example, if
4678 used in a QVariant, you can convert them to strings. Likewise, passing them
4679 to QDebug will print out their names.
4680
4681 Mind that the enum values are stored as signed \c int in the meta object system.
4682 Registering enumerations with values outside the range of values valid for \c int
4683 will lead to overflows and potentially undefined behavior when accessing them through
4684 the meta object system. QML, for example, does access registered enumerations through
4685 the meta object system.
4686
4687 \sa {Qt's Property System}
4688*/
4689
4690
4691/*!
4692 \macro Q_FLAG_NS(...)
4693 \relates QObject
4694 \since 5.8
4695
4696 This macro registers a single \l{QFlags}{flags type} with the
4697 meta-object system. It is used in a namespace that has the
4698 Q_NAMESPACE macro, to declare that values of a given enum can be
4699 used as flags and combined using the bitwise OR operator.
4700 It is the same as \l Q_FLAG but in a namespace.
4701
4702 The macro must be placed after the enum declaration.
4703
4704 \note The Q_FLAG_NS macro takes care of registering individual flag
4705 values with the meta-object system, so it is unnecessary to use
4706 Q_ENUM_NS() in addition to this macro.
4707
4708 \sa {Qt's Property System}
4709*/
4710
4711/*!
4712 \macro Q_OBJECT
4713 \relates QObject
4714
4715 The Q_OBJECT macro is used to enable meta-object features, such as dynamic
4716 properties, signals, and slots.
4717
4718 You can add the Q_OBJECT macro to any section of a class definition that
4719 declares its own signals and slots or that uses other services provided by
4720 Qt's meta-object system.
4721
4722//! [qobject-macros-private-access-specifier]
4723 \note This macro expansion ends with a \c private: access specifier. If you
4724 declare members immediately after this macro, those members will also be
4725 private. To add public (or protected) members right after the macro, use a
4726 \c {public:} (or \c {protected:}) access specifier.
4727//! [qobject-macros-private-access-specifier]
4728
4729 Example:
4730
4731 \snippet signalsandslots/signalsandslots.h 1
4732 \codeline
4733 \snippet signalsandslots/signalsandslots.h 2
4734 \snippet signalsandslots/signalsandslots.h 3
4735
4736 \note This macro requires the class to be a subclass of QObject. Use
4737 Q_GADGET or Q_GADGET_EXPORT instead of Q_OBJECT to enable the meta object
4738 system's support for enums in a class that is not a QObject subclass.
4739
4740 \sa {Meta-Object System}, {Signals and Slots}, {Qt's Property System}
4741*/
4742
4743/*!
4744 \macro Q_GADGET
4745 \relates QObject
4746
4747 The Q_GADGET macro is a lighter version of the Q_OBJECT macro for classes
4748 that do not inherit from QObject but still want to use some of the
4749 reflection capabilities offered by QMetaObject.
4750
4751 \include qobject.cpp qobject-macros-private-access-specifier
4752
4753 Q_GADGETs can have Q_ENUM, Q_PROPERTY and Q_INVOKABLE, but they cannot have
4754 signals or slots.
4755
4756 Q_GADGET makes a class member, \c{staticMetaObject}, available.
4757 \c{staticMetaObject} is of type QMetaObject and provides access to the
4758 enums declared with Q_ENUM.
4759
4760 \sa Q_GADGET_EXPORT
4761*/
4762
4763/*!
4764 \macro Q_GADGET_EXPORT(EXPORT_MACRO)
4765 \relates QObject
4766 \since 6.3
4767
4768 The Q_GADGET_EXPORT macro works exactly like the Q_GADGET macro.
4769 However, the \c{staticMetaObject} variable that is made available (see
4770 Q_GADGET) is declared with the supplied \a EXPORT_MACRO qualifier. This is
4771 useful if the object needs to be exported from a dynamic library, but the
4772 enclosing class as a whole should not be (e.g. because it consists of mostly
4773 inline functions).
4774
4775 \include qobject.cpp qobject-macros-private-access-specifier
4776
4777 For example:
4778
4779 \code
4780 class Point {
4781 Q_GADGET_EXPORT(EXPORT_MACRO)
4782 Q_PROPERTY(int x MEMBER x)
4783 Q_PROPERTY(int y MEMBER y)
4784 ~~~
4785 \endcode
4786
4787 \sa Q_GADGET, {Creating Shared Libraries}
4788*/
4789
4790/*!
4791 \macro Q_NAMESPACE
4792 \relates QObject
4793 \since 5.8
4794
4795 The Q_NAMESPACE macro can be used to add QMetaObject capabilities
4796 to a namespace.
4797
4798 Q_NAMESPACEs can have Q_CLASSINFO, Q_ENUM_NS, Q_FLAG_NS, but they
4799 cannot have Q_ENUM, Q_FLAG, Q_PROPERTY, Q_INVOKABLE, signals nor slots.
4800
4801 Q_NAMESPACE makes an external variable, \c{staticMetaObject}, available.
4802 \c{staticMetaObject} is of type QMetaObject and provides access to the
4803 enums declared with Q_ENUM_NS/Q_FLAG_NS.
4804
4805 For example:
4806
4807 \code
4808 namespace test {
4809 Q_NAMESPACE
4810 ...
4811 \endcode
4812
4813 \sa Q_NAMESPACE_EXPORT
4814*/
4815
4816/*!
4817 \macro Q_NAMESPACE_EXPORT(EXPORT_MACRO)
4818 \relates QObject
4819 \since 5.14
4820
4821 The Q_NAMESPACE_EXPORT macro can be used to add QMetaObject capabilities
4822 to a namespace.
4823
4824 It works exactly like the Q_NAMESPACE macro. However, the external
4825 \c{staticMetaObject} variable that gets defined in the namespace
4826 is declared with the supplied \a EXPORT_MACRO qualifier. This is
4827 useful if the object needs to be exported from a dynamic library.
4828
4829 For example:
4830
4831 \code
4832 namespace test {
4833 Q_NAMESPACE_EXPORT(EXPORT_MACRO)
4834 ...
4835 \endcode
4836
4837 \sa Q_NAMESPACE, {Creating Shared Libraries}
4838*/
4839
4840/*!
4841 \macro Q_MOC_INCLUDE
4842 \relates QObject
4843 \since 6.0
4844
4845 The Q_MOC_INCLUDE macro can be used within or outside a class, and tell the
4846 \l{moc}{Meta Object Compiler} to add an include.
4847
4848 \code
4849 // Put this in your code and the generated code will include this header.
4850 Q_MOC_INCLUDE("myheader.h")
4851 \endcode
4852
4853 This is useful if the types you use as properties or signal/slots arguments
4854 are forward declared.
4855*/
4856
4857/*!
4858 \macro Q_SIGNALS
4859 \relates QObject
4860
4861 Use this macro to replace the \c signals keyword in class
4862 declarations, when you want to use Qt Signals and Slots with a
4863 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
4864
4865 The macro is normally used when \c no_keywords is specified with
4866 the \c CONFIG variable in the \c .pro file, but it can be used
4867 even when \c no_keywords is \e not specified.
4868*/
4869
4870/*!
4871 \macro Q_SIGNAL
4872 \relates QObject
4873
4874 This is an additional macro that allows you to mark a single
4875 function as a signal. It can be quite useful, especially when you
4876 use a 3rd-party source code parser which doesn't understand a \c
4877 signals or \c Q_SIGNALS groups.
4878
4879 Use this macro to replace the \c signals keyword in class
4880 declarations, when you want to use Qt Signals and Slots with a
4881 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
4882
4883 The macro is normally used when \c no_keywords is specified with
4884 the \c CONFIG variable in the \c .pro file, but it can be used
4885 even when \c no_keywords is \e not specified.
4886*/
4887
4888/*!
4889 \macro Q_SLOTS
4890 \relates QObject
4891
4892 Use this macro to replace the \c slots keyword in class
4893 declarations, when you want to use Qt Signals and Slots with a
4894 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
4895
4896 The macro is normally used when \c no_keywords is specified with
4897 the \c CONFIG variable in the \c .pro file, but it can be used
4898 even when \c no_keywords is \e not specified.
4899*/
4900
4901/*!
4902 \macro Q_SLOT
4903 \relates QObject
4904
4905 This is an additional macro that allows you to mark a single
4906 function as a slot. It can be quite useful, especially when you
4907 use a 3rd-party source code parser which doesn't understand a \c
4908 slots or \c Q_SLOTS groups.
4909
4910 Use this macro to replace the \c slots keyword in class
4911 declarations, when you want to use Qt Signals and Slots with a
4912 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
4913
4914 The macro is normally used when \c no_keywords is specified with
4915 the \c CONFIG variable in the \c .pro file, but it can be used
4916 even when \c no_keywords is \e not specified.
4917*/
4918
4919/*!
4920 \macro Q_EMIT
4921 \relates QObject
4922
4923 Use this macro to replace the \c emit keyword for emitting
4924 signals, when you want to use Qt Signals and Slots with a
4925 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
4926
4927 The macro is normally used when \c no_keywords is specified with
4928 the \c CONFIG variable in the \c .pro file, but it can be used
4929 even when \c no_keywords is \e not specified.
4930*/
4931
4932/*!
4933 \macro Q_INVOKABLE
4934 \relates QObject
4935
4936 Apply this macro to declarations of member functions to allow them to
4937 be invoked via the meta-object system. The macro is written before
4938 the return type, as shown in the following example:
4939
4940 \snippet qmetaobject-invokable/window.h Window class with invokable method
4941
4942 The \c invokableMethod() function is marked up using Q_INVOKABLE, causing
4943 it to be registered with the meta-object system and enabling it to be
4944 invoked using QMetaObject::invokeMethod().
4945 Since \c normalMethod() function is not registered in this way, it cannot
4946 be invoked using QMetaObject::invokeMethod().
4947
4948 If an invokable member function returns a pointer to a QObject or a
4949 subclass of QObject and it is invoked from QML, special ownership rules
4950 apply. See \l{qtqml-cppintegration-data.html}{Data Type Conversion Between QML and C++}
4951 for more information.
4952*/
4953
4954/*!
4955 \macro Q_REVISION
4956 \relates QObject
4957
4958 Apply this macro to declarations of member functions to tag them with a
4959 revision number in the meta-object system. The macro is written before
4960 the return type, as shown in the following example:
4961
4962 \snippet qmetaobject-revision/window.h Window class with revision
4963
4964 This is useful when using the meta-object system to dynamically expose
4965 objects to another API, as you can match the version expected by multiple
4966 versions of the other API. Consider the following simplified example:
4967
4968 \snippet qmetaobject-revision/main.cpp Window class using revision
4969
4970 Using the same Window class as the previous example, the newProperty and
4971 newMethod would only be exposed in this code when the expected version is
4972 \c{2.1} or greater.
4973
4974 Since all methods are considered to be in revision \c{0} if untagged, a tag
4975 of \c{Q_REVISION(0)} or \c{Q_REVISION(0, 0)} is invalid and ignored.
4976
4977 You can pass one or two integer parameters to \c{Q_REVISION}. If you pass
4978 one parameter, it denotes the minor version only. This means that the major
4979 version is unspecified. If you pass two, the first parameter is the major
4980 version and the second parameter is the minor version.
4981
4982 This tag is not used by the meta-object system itself. Currently this is only
4983 used by the QtQml module.
4984
4985 For a more generic string tag, see \l QMetaMethod::tag()
4986
4987 \sa QMetaMethod::revision()
4988*/
4989
4990/*!
4991 \macro Q_SET_OBJECT_NAME(Object)
4992 \relates QObject
4993 \since 5.0
4994
4995 This macro assigns \a Object the objectName "Object".
4996
4997 It doesn't matter whether \a Object is a pointer or not, the
4998 macro figures that out by itself.
4999
5000 \sa QObject::objectName()
5001*/
5002
5003/*!
5004 \macro QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
5005 \relates QObject
5006 \since 5.8
5007
5008 Defining this macro will disable narrowing and floating-point-to-integral
5009 conversions between the arguments carried by a signal and the arguments
5010 accepted by a slot, when the signal and the slot are connected using the
5011 PMF-based syntax.
5012
5013 \sa QObject::connect
5014*/
5015
5016/*!
5017 \macro QT_NO_CONTEXTLESS_CONNECT
5018 \relates QObject
5019 \since 6.7
5020
5021 Defining this macro will disable the overload of QObject::connect() that
5022 connects a signal to a functor, without also specifying a QObject
5023 as a receiver/context object (that is, the 3-arguments overload
5024 of QObject::connect()).
5025
5026 Using the context-less overload is error prone, because it is easy
5027 to connect to functors that depend on some local state of the
5028 receiving end. If such local state gets destroyed, the connection
5029 does not get automatically disconnected.
5030
5031 Moreover, such connections are always direct connections, which may
5032 cause issues in multithreaded scenarios (for instance, if the
5033 signal is emitted from another thread).
5034
5035 \sa QObject::connect, Qt::ConnectionType
5036*/
5037
5038/*!
5039 \typedef QObjectList
5040 \relates QObject
5041
5042 Synonym for QList<QObject *>.
5043*/
5044
5045/*!
5046 \fn template<typename PointerToMemberFunction> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type)
5047 \overload connect()
5048 \threadsafe
5049
5050 Creates a connection of the given \a type from the \a signal in
5051 the \a sender object to the \a method in the \a receiver object.
5052 Returns a handle to the connection that can be used to disconnect
5053 it later.
5054
5055 The signal must be a function declared as a signal in the header.
5056 The slot function can be any member function that can be connected
5057 to the signal.
5058 A slot can be connected to a given signal if the signal has at
5059 least as many arguments as the slot, and there is an implicit
5060 conversion between the types of the corresponding arguments in the
5061 signal and the slot.
5062
5063 Example:
5064
5065 \snippet code/src_corelib_kernel_qobject.cpp 44
5066
5067 This example ensures that the label always displays the current
5068 line edit text.
5069
5070 A signal can be connected to many slots and signals. Many signals
5071 can be connected to one slot.
5072
5073 If a signal is connected to several slots, the slots are activated
5074 in the same order as the order the connection was made, when the
5075 signal is emitted
5076
5077 The function returns an handle to a connection if it successfully
5078 connects the signal to the slot. The Connection handle will be invalid
5079 if it cannot create the connection, for example, if QObject is unable
5080 to verify the existence of \a signal (if it was not declared as a signal)
5081 You can check if the QMetaObject::Connection is valid by casting it to a bool.
5082
5083 By default, a signal is emitted for every connection you make;
5084 two signals are emitted for duplicate connections. You can break
5085 all of these connections with a single disconnect() call.
5086 If you pass the Qt::UniqueConnection \a type, the connection will only
5087 be made if it is not a duplicate. If there is already a duplicate
5088 (exact same signal to the exact same slot on the same objects),
5089 the connection will fail and connect will return an invalid QMetaObject::Connection.
5090
5091 The optional \a type parameter describes the type of connection
5092 to establish. In particular, it determines whether a particular
5093 signal is delivered to a slot immediately or queued for delivery
5094 at a later time. If the signal is queued, the parameters must be
5095 of types that are known to Qt's meta-object system, because Qt
5096 needs to copy the arguments to store them in an event behind the
5097 scenes. If you try to use a queued connection and get the error
5098 message
5099
5100 \snippet code/src_corelib_kernel_qobject.cpp 25
5101
5102 make sure to declare the argument type with Q_DECLARE_METATYPE
5103
5104 Overloaded functions can be resolved with help of \l qOverload.
5105
5106 \sa {Differences between String-Based and Functor-Based Connections}
5107 */
5108
5109/*!
5110 \fn template<typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
5111
5112 \threadsafe
5113 \overload connect()
5114
5115 Creates a connection from \a signal in
5116 \a sender object to \a functor, and returns a handle to the connection
5117
5118 The signal must be a function declared as a signal in the header.
5119 The slot function can be any function or functor that can be connected
5120 to the signal.
5121 A slot function can be connected to a given signal if the signal has at
5122 least as many arguments as the slot function. There must exist implicit
5123 conversion between the types of the corresponding arguments in the
5124 signal and the slot.
5125
5126 Example:
5127
5128 \snippet code/src_corelib_kernel_qobject.cpp 45
5129
5130 Lambda expressions can also be used:
5131
5132 \snippet code/src_corelib_kernel_qobject.cpp 46
5133
5134 The connection will automatically disconnect if the sender is destroyed.
5135 However, you should take care that any objects used within the functor
5136 are still alive when the signal is emitted.
5137
5138 For this reason, it is recommended to use the overload of connect()
5139 that also takes a QObject as a receiver/context. It is possible
5140 to disable the usage of the context-less overload by defining the
5141 \c{QT_NO_CONTEXTLESS_CONNECT} macro.
5142
5143 Overloaded functions can be resolved with help of \l qOverload.
5144
5145 */
5146
5147/*!
5148 \fn template<typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type)
5149
5150 \threadsafe
5151 \overload connect()
5152
5153 \since 5.2
5154
5155 Creates a connection of a given \a type from \a signal in
5156 \a sender object to \a functor to be placed in a specific event
5157 loop of \a context, and returns a handle to the connection.
5158
5159 \note Qt::UniqueConnections do not work for lambdas, non-member functions
5160 and functors; they only apply to connecting to member functions.
5161
5162 The signal must be a function declared as a signal in the header.
5163 The slot function can be any function or functor that can be connected
5164 to the signal.
5165 A slot function can be connected to a given signal if the signal has at
5166 least as many arguments as the slot function. There must exist implicit
5167 conversion between the types of the corresponding arguments in the
5168 signal and the slot.
5169
5170 Example:
5171
5172 \snippet code/src_corelib_kernel_qobject.cpp 50
5173
5174 Lambda expressions can also be used:
5175
5176 \snippet code/src_corelib_kernel_qobject.cpp 51
5177
5178 The connection will automatically disconnect if the sender or the context
5179 is destroyed.
5180 However, you should take care that any objects used within the functor
5181 are still alive when the signal is emitted.
5182
5183 Overloaded functions can be resolved with help of \l qOverload.
5184 */
5185
5186/*!
5187 \internal
5188
5189 Implementation of the template version of connect
5190
5191 \a sender is the sender object
5192 \a signal is a pointer to a pointer to a member signal of the sender
5193 \a receiver is the receiver object, may not be \nullptr, will be equal to sender when
5194 connecting to a static function or a functor
5195 \a slot a pointer only used when using Qt::UniqueConnection
5196 \a type the Qt::ConnectionType passed as argument to connect
5197 \a types an array of integer with the metatype id of the parameter of the signal
5198 to be used with queued connection
5199 must stay valid at least for the whole time of the connection, this function
5200 do not take ownership. typically static data.
5201 If \nullptr, then the types will be computed when the signal is emit in a queued
5202 connection from the types from the signature.
5203 \a senderMetaObject is the metaobject used to lookup the signal, the signal must be in
5204 this metaobject
5205 */
5206QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,
5207 const QObject *receiver, void **slot,
5208 QtPrivate::QSlotObjectBase *slotObjRaw, Qt::ConnectionType type,
5209 const int *types, const QMetaObject *senderMetaObject)
5210{
5211 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5212 if (!signal) {
5213 qCWarning(lcConnect, "QObject::connect: invalid nullptr parameter");
5214 return QMetaObject::Connection();
5215 }
5216
5217 int signal_index = -1;
5218 void *args[] = { &signal_index, signal };
5219 for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
5220 senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
5221 if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(metaobject: senderMetaObject)->signalCount)
5222 break;
5223 }
5224 if (!senderMetaObject) {
5225 qCWarning(lcConnect, "QObject::connect: signal not found in %s", sender->metaObject()->className());
5226 return QMetaObject::Connection(nullptr);
5227 }
5228 signal_index += QMetaObjectPrivate::signalOffset(m: senderMetaObject);
5229 return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj: slotObj.release(), type, types, senderMetaObject);
5230}
5231
5232static void connectWarning(const QObject *sender,
5233 const QMetaObject *senderMetaObject,
5234 const QObject *receiver,
5235 const char *message)
5236{
5237 const char *senderString = sender ? sender->metaObject()->className()
5238 : senderMetaObject ? senderMetaObject->className()
5239 : "Unknown";
5240 const char *receiverString = receiver ? receiver->metaObject()->className()
5241 : "Unknown";
5242 qCWarning(lcConnect, "QObject::connect(%s, %s): %s", senderString, receiverString, message);
5243}
5244
5245/*!
5246 \internal
5247
5248 Internal version of connect used by the template version of QObject::connect (called via connectImpl) and
5249 also used by the QObjectPrivate::connect version used by QML. The signal_index is expected to be relative
5250 to the number of signals.
5251 */
5252QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index,
5253 const QObject *receiver, void **slot,
5254 QtPrivate::QSlotObjectBase *slotObjRaw, int type,
5255 const int *types, const QMetaObject *senderMetaObject)
5256{
5257 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5258
5259 if (!sender || !receiver || !slotObj || !senderMetaObject) {
5260 connectWarning(sender, senderMetaObject, receiver, message: "invalid nullptr parameter");
5261 return QMetaObject::Connection();
5262 }
5263
5264 if (type & Qt::UniqueConnection && !slot) {
5265 connectWarning(sender, senderMetaObject, receiver, message: "unique connections require a pointer to member function of a QObject subclass");
5266 return QMetaObject::Connection();
5267 }
5268
5269 QObject *s = const_cast<QObject *>(sender);
5270 QObject *r = const_cast<QObject *>(receiver);
5271
5272 QOrderedMutexLocker locker(signalSlotLock(o: sender),
5273 signalSlotLock(o: receiver));
5274
5275 if (type & Qt::UniqueConnection && slot) {
5276 QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(o: s)->connections.loadRelaxed();
5277 if (connections && connections->signalVectorCount() > signal_index) {
5278 const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(i: signal_index).first.loadRelaxed();
5279
5280 while (c2) {
5281 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(a: slot))
5282 return QMetaObject::Connection();
5283 c2 = c2->nextConnectionList.loadRelaxed();
5284 }
5285 }
5286 }
5287 type &= ~Qt::UniqueConnection;
5288
5289 const bool isSingleShot = type & Qt::SingleShotConnection;
5290 type &= ~Qt::SingleShotConnection;
5291
5292 Q_ASSERT(type >= 0);
5293 Q_ASSERT(type <= 3);
5294
5295 std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
5296 c->sender = s;
5297 c->signal_index = signal_index;
5298 QThreadData *td = r->d_func()->threadData.loadAcquire();
5299 td->ref();
5300 c->receiverThreadData.storeRelaxed(newValue: td);
5301 c->receiver.storeRelaxed(newValue: r);
5302 c->connectionType = type;
5303 c->isSlotObject = true;
5304 c->slotObj = slotObj.release();
5305 if (types) {
5306 c->argumentTypes.storeRelaxed(newValue: types);
5307 c->ownArgumentTypes = false;
5308 }
5309 c->isSingleShot = isSingleShot;
5310
5311 QObjectPrivate::get(o: s)->addConnection(signal: signal_index, c: c.get());
5312 QMetaObject::Connection ret(c.release());
5313 locker.unlock();
5314
5315 QMetaMethod method = QMetaObjectPrivate::signal(m: senderMetaObject, signal_index);
5316 Q_ASSERT(method.isValid());
5317 s->connectNotify(signal: method);
5318
5319 return ret;
5320}
5321
5322/*!
5323 Disconnect a connection.
5324
5325 If the \a connection is invalid or has already been disconnected, do nothing
5326 and return false.
5327
5328 \sa connect()
5329 */
5330bool QObject::disconnect(const QMetaObject::Connection &connection)
5331{
5332 QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(connection.d_ptr);
5333 if (!c)
5334 return false;
5335 const bool disconnected = QObjectPrivate::removeConnection(c);
5336 const_cast<QMetaObject::Connection &>(connection).d_ptr = nullptr;
5337 c->deref(); // has been removed from the QMetaObject::Connection object
5338 return disconnected;
5339}
5340
5341/*! \fn template<typename PointerToMemberFunction> bool QObject::disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method)
5342 \overload disconnect()
5343 \threadsafe
5344
5345 Disconnects \a signal in object \a sender from \a method in object
5346 \a receiver. Returns \c true if the connection is successfully broken;
5347 otherwise returns \c false.
5348
5349 A signal-slot connection is removed when either of the objects
5350 involved are destroyed.
5351
5352 disconnect() is typically used in three ways, as the following
5353 examples demonstrate.
5354 \list 1
5355 \li Disconnect everything connected to an object's signals:
5356
5357 \snippet code/src_corelib_kernel_qobject.cpp 26
5358
5359 \li Disconnect everything connected to a specific signal:
5360
5361 \snippet code/src_corelib_kernel_qobject.cpp 47
5362
5363 \li Disconnect a specific receiver:
5364
5365 \snippet code/src_corelib_kernel_qobject.cpp 30
5366
5367 \li Disconnect a connection from one specific signal to a specific slot:
5368
5369 \snippet code/src_corelib_kernel_qobject.cpp 48
5370
5371
5372 \endlist
5373
5374 \nullptr may be used as a wildcard, meaning "any signal", "any receiving
5375 object", or "any slot in the receiving object", respectively.
5376
5377 The \a sender may never be \nullptr. (You cannot disconnect signals
5378 from more than one object in a single call.)
5379
5380 If \a signal is \nullptr, it disconnects \a receiver and \a method from
5381 any signal. If not, only the specified signal is disconnected.
5382
5383 If \a receiver is \nullptr, it disconnects anything connected to \a
5384 signal. If not, only slots in the specified receiver are disconnected.
5385 disconnect() with a non-null \a receiver also disconnects slot functions
5386 that were connected with \a receiver as their context object.
5387
5388 If \a method is \nullptr, it disconnects anything that is connected to \a
5389 receiver. If not, only slots named \a method will be disconnected,
5390 and all other slots are left alone. The \a method must be \nullptr
5391 if \a receiver is left out, so you cannot disconnect a
5392 specifically-named slot on all objects.
5393
5394 \note It is not possible to use this overload to disconnect signals
5395 connected to functors or lambda expressions. That is because it is not
5396 possible to compare them. Instead, use the overload that takes a
5397 QMetaObject::Connection.
5398
5399 \note Unless \a method is \nullptr, this function will also not break
5400 connections that were made using the string-based version of connect(). To
5401 break such connections, use the corresponding string-based overload of
5402 disconnect().
5403
5404 \sa connect()
5405*/
5406
5407bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot, const QMetaObject *senderMetaObject)
5408{
5409 if (sender == nullptr || (receiver == nullptr && slot != nullptr)) {
5410 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
5411 return false;
5412 }
5413
5414 int signal_index = -1;
5415 if (signal) {
5416 void *args[] = { &signal_index, signal };
5417 for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
5418 senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
5419 if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(metaobject: senderMetaObject)->signalCount)
5420 break;
5421 }
5422 if (!senderMetaObject) {
5423 qCWarning(lcConnect, "QObject::disconnect: signal not found in %s", sender->metaObject()->className());
5424 return false;
5425 }
5426 signal_index += QMetaObjectPrivate::signalOffset(m: senderMetaObject);
5427 }
5428
5429 return QMetaObjectPrivate::disconnect(sender, signal_index, smeta: senderMetaObject, receiver, method_index: -1, slot);
5430}
5431
5432/*!
5433 \internal
5434 Used by QML to connect a signal by index to a slot implemented in JavaScript
5435 (wrapped in a custom QSlotObjectBase subclass).
5436
5437 This version of connect assumes that sender and receiver are the same object.
5438
5439 The signal_index is an index relative to the number of methods.
5440 */
5441QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type)
5442{
5443 return QObjectPrivate::connect(sender, signal_index, receiver: sender, slotObj, type);
5444}
5445
5446/*!
5447 \internal
5448 Used by QML to connect a signal by index to a slot implemented in JavaScript
5449 (wrapped in a custom QSlotObjectBase subclass).
5450
5451 This is an overload that should be used when \a sender and \a receiver are
5452 different objects.
5453
5454 The signal_index is an index relative to the number of methods.
5455 */
5456QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index,
5457 const QObject *receiver,
5458 QtPrivate::QSlotObjectBase *slotObjRaw,
5459 Qt::ConnectionType type)
5460{
5461 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5462 if (!sender) {
5463 qCWarning(lcConnect, "QObject::connect: invalid nullptr parameter");
5464 return QMetaObject::Connection();
5465 }
5466 const QMetaObject *senderMetaObject = sender->metaObject();
5467 signal_index = methodIndexToSignalIndex(base: &senderMetaObject, signal_index);
5468
5469 return connectImpl(sender, signal_index, receiver, /*slot*/ nullptr, slotObjRaw: slotObj.release(),
5470 type, /*types*/ nullptr, senderMetaObject);
5471}
5472
5473/*!
5474 \internal
5475 Used by QML to disconnect a signal by index that's connected to a slot implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass)
5476 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
5477 required for the disconnect.
5478
5479 This version of disconnect assumes that sender and receiver are the same object.
5480 */
5481bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, void **slot)
5482{
5483 return QObjectPrivate::disconnect(sender, signal_index, receiver: sender, slot);
5484}
5485
5486/*!
5487 \internal
5488
5489 Used by QML to disconnect a signal by index that's connected to a slot
5490 implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass) In the
5491 QML case the slot is not a pointer to a pointer to the function to disconnect,
5492 but instead it is a pointer to an array of internal values required for the
5493 disconnect.
5494
5495 This is an overload that should be used when \a sender and \a receiver are
5496 different objects.
5497 */
5498bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, const QObject *receiver,
5499 void **slot)
5500{
5501 const QMetaObject *senderMetaObject = sender->metaObject();
5502 signal_index = methodIndexToSignalIndex(base: &senderMetaObject, signal_index);
5503
5504 return QMetaObjectPrivate::disconnect(sender, signal_index, smeta: senderMetaObject, receiver, method_index: -1,
5505 slot);
5506}
5507
5508/*!
5509 \internal
5510 \threadsafe
5511*/
5512inline bool QObjectPrivate::removeConnection(QObjectPrivate::Connection *c)
5513{
5514 if (!c)
5515 return false;
5516 QObject *receiver = c->receiver.loadRelaxed();
5517 if (!receiver)
5518 return false;
5519
5520 QBasicMutex *senderMutex = signalSlotLock(o: c->sender);
5521 QBasicMutex *receiverMutex = signalSlotLock(o: receiver);
5522
5523 QObjectPrivate::ConnectionData *connections;
5524 {
5525 QOrderedMutexLocker locker(senderMutex, receiverMutex);
5526
5527 // load receiver once again and recheck to ensure nobody else has removed the connection in the meantime
5528 receiver = c->receiver.loadRelaxed();
5529 if (!receiver)
5530 return false;
5531
5532 connections = QObjectPrivate::get(o: c->sender)->connections.loadRelaxed();
5533 Q_ASSERT(connections);
5534 connections->removeConnection(c);
5535
5536 c->sender->disconnectNotify(signal: QMetaObjectPrivate::signal(m: c->sender->metaObject(), signal_index: c->signal_index));
5537 // We must not hold the receiver mutex, else we risk dead-locking; we also only need the sender mutex
5538 // It is however vital to hold the senderMutex before calling cleanOrphanedConnections, as otherwise
5539 // another thread might modify/delete the connection
5540 if (receiverMutex != senderMutex) {
5541 receiverMutex->unlock();
5542 }
5543 connections->cleanOrphanedConnections(sender: c->sender, lockPolicy: ConnectionData::AlreadyLockedAndTemporarilyReleasingLock);
5544 senderMutex->unlock(); // now both sender and receiver mutex have been manually unlocked
5545 locker.dismiss(); // so we dismiss the QOrderedMutexLocker
5546 }
5547
5548 return true;
5549}
5550
5551/*!
5552 \internal
5553
5554 Used by QPropertyAdaptorSlotObject to get an existing instance for a property, if available
5555 */
5556QtPrivate::QPropertyAdaptorSlotObject *
5557QObjectPrivate::getPropertyAdaptorSlotObject(const QMetaProperty &property)
5558{
5559 if (auto conns = connections.loadAcquire()) {
5560 Q_Q(QObject);
5561 const QMetaObject *metaObject = q->metaObject();
5562 int signal_index = methodIndexToSignalIndex(base: &metaObject, signal_index: property.notifySignalIndex());
5563 if (signal_index >= conns->signalVectorCount())
5564 return nullptr;
5565 const auto &connectionList = conns->connectionsForSignal(signal: signal_index);
5566 for (auto c = connectionList.first.loadRelaxed(); c;
5567 c = c->nextConnectionList.loadRelaxed()) {
5568 if (c->isSlotObject) {
5569 if (auto p = QtPrivate::QPropertyAdaptorSlotObject::cast(ptr: c->slotObj,
5570 propertyIndex: property.propertyIndex()))
5571 return p;
5572 }
5573 }
5574 }
5575 return nullptr;
5576}
5577
5578/*! \class QMetaObject::Connection
5579 \inmodule QtCore
5580 Represents a handle to a signal-slot (or signal-functor) connection.
5581
5582 It can be used to check if the connection is valid and to disconnect it using
5583 QObject::disconnect(). For a signal-functor connection without a context object,
5584 it is the only way to selectively disconnect that connection.
5585
5586 As Connection is just a handle, the underlying signal-slot connection is unaffected
5587 when Connection is destroyed or reassigned.
5588 */
5589
5590/*!
5591 Create a copy of the handle to the \a other connection
5592 */
5593QMetaObject::Connection::Connection(const QMetaObject::Connection &other) : d_ptr(other.d_ptr)
5594{
5595 if (d_ptr)
5596 static_cast<QObjectPrivate::Connection *>(d_ptr)->ref();
5597}
5598
5599/*!
5600 Assigns \a other to this connection and returns a reference to this connection.
5601*/
5602QMetaObject::Connection &QMetaObject::Connection::operator=(const QMetaObject::Connection &other)
5603{
5604 if (other.d_ptr != d_ptr) {
5605 if (d_ptr)
5606 static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
5607 d_ptr = other.d_ptr;
5608 if (other.d_ptr)
5609 static_cast<QObjectPrivate::Connection *>(other.d_ptr)->ref();
5610 }
5611 return *this;
5612}
5613
5614/*!
5615 Creates a Connection instance.
5616*/
5617
5618QMetaObject::Connection::Connection() : d_ptr(nullptr) {}
5619
5620/*!
5621 Destructor for QMetaObject::Connection.
5622*/
5623QMetaObject::Connection::~Connection()
5624{
5625 if (d_ptr)
5626 static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
5627}
5628
5629/*! \internal Returns true if the object is still connected */
5630bool QMetaObject::Connection::isConnected_helper() const
5631{
5632 Q_ASSERT(d_ptr); // we're only called from operator RestrictedBool() const
5633 QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(d_ptr);
5634
5635 return c->receiver.loadRelaxed();
5636}
5637
5638
5639/*!
5640 \fn QMetaObject::Connection::operator bool() const
5641
5642 Returns \c true if the connection is valid.
5643
5644 The connection is valid if the call to QObject::connect succeeded.
5645 The connection is invalid if QObject::connect was not able to find
5646 the signal or the slot, or if the arguments do not match.
5647 */
5648
5649QT_END_NAMESPACE
5650
5651#include "moc_qobject.cpp"
5652

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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