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