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