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