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 (Q_LIKELY(thisThreadData->thread.loadAcquire() == QThread::currentThread())) {
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, that is, there are no more native window system events to process.
1947
1948 \include timers-common.qdocinc negative-intervals-not-allowed
1949
1950 The virtual timerEvent() function is called with the QTimerEvent
1951 event parameter class when a timer event occurs. Reimplement this
1952 function to get timer events.
1953
1954 If multiple timers are running, the QTimerEvent::id() method can be
1955 used to find out which timer was activated.
1956
1957 Example:
1958
1959 \snippet code/src_corelib_kernel_qobject.cpp 8
1960
1961 Note that the accuracy of the timer depends on the underlying operating
1962 system and hardware.
1963
1964 The \a timerType argument allows you to customize the accuracy of
1965 the timer. See Qt::TimerType for information on the different timer types.
1966 Most platforms support an accuracy of 20 milliseconds; some provide more.
1967 If Qt is unable to deliver the requested number of timer events, it will
1968 silently discard some.
1969
1970 The QTimer and QChronoTimer classes provide a high-level programming
1971 interface with single-shot timers and timer signals instead of
1972 events. There is also a QBasicTimer class that is more lightweight than
1973 QChronoTimer but less clumsy than using timer IDs directly.
1974
1975 \note Starting from Qt 6.8 the type of \a interval
1976 is \c std::chrono::nanoseconds, prior to that it was \c
1977 std::chrono::milliseconds. This change is backwards compatible with
1978 older releases of Qt.
1979
1980 \note In Qt 6.8, QObject was changed to use Qt::TimerId to represent timer
1981 IDs. This method converts the TimerId to int for backwards compatibility
1982 reasons, however you can use Qt::TimerId to check the value returned by
1983 this method, for example:
1984 \snippet code/src_corelib_kernel_qobject.cpp invalid-timer-id
1985
1986 \sa timerEvent(), killTimer(), QChronoTimer, QBasicTimer
1987*/
1988int QObject::startTimer(std::chrono::nanoseconds interval, Qt::TimerType timerType)
1989{
1990 Q_D(QObject);
1991
1992 using namespace std::chrono_literals;
1993
1994 if (interval < 0ns) {
1995 qWarning("QObject::startTimer: negative intervals aren't allowed; the "
1996 "interval will be set to 1ms.");
1997 interval = 1ms;
1998 }
1999
2000 auto thisThreadData = d->threadData.loadRelaxed();
2001 if (Q_UNLIKELY(thisThreadData != QThreadData::current())) {
2002 qWarning("QObject::startTimer: Timers cannot be started from another thread");
2003 return 0;
2004 }
2005
2006 auto dispatcher = thisThreadData->eventDispatcher.loadRelaxed();
2007 if (Q_UNLIKELY(!dispatcher)) {
2008 qWarning("QObject::startTimer: current thread's event dispatcher has already been destroyed");
2009 return 0;
2010 }
2011
2012 Qt::TimerId timerId = dispatcher->registerTimer(interval, timerType, this);
2013 d->ensureExtraData();
2014 d->extraData->runningTimers.append(timerId);
2015 return int(timerId);
2016}
2017
2018/*!
2019 Kills the timer with timer identifier, \a id.
2020
2021 The timer identifier is returned by startTimer() when a timer
2022 event is started.
2023
2024 \sa timerEvent(), startTimer()
2025*/
2026
2027void QObject::killTimer(int id)
2028{
2029 killTimer(Qt::TimerId{id});
2030}
2031
2032/*!
2033 \since 6.8
2034 \overload
2035*/
2036void QObject::killTimer(Qt::TimerId id)
2037{
2038 Q_D(QObject);
2039 if (Q_UNLIKELY(thread() != QThread::currentThread())) {
2040 qWarning("QObject::killTimer: Timers cannot be stopped from another thread");
2041 return;
2042 }
2043 if (id > Qt::TimerId::Invalid) {
2044 qsizetype at = d->extraData ? d->extraData->runningTimers.indexOf(id) : -1;
2045 if (at == -1) {
2046 // timer isn't owned by this object
2047 qWarning("QObject::killTimer(): Error: timer id %d is not valid for object %p (%s, %ls), timer has not been killed",
2048 qToUnderlying(id),
2049 this,
2050 metaObject()->className(),
2051 qUtf16Printable(objectName()));
2052 return;
2053 }
2054
2055 auto thisThreadData = d->threadData.loadRelaxed();
2056 if (thisThreadData->hasEventDispatcher())
2057 thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimer(id);
2058
2059 d->extraData->runningTimers.remove(at);
2060 QAbstractEventDispatcherPrivate::releaseTimerId(id);
2061 }
2062}
2063
2064/*!
2065 \fn QObject *QObject::parent() const
2066
2067 Returns a pointer to the parent object.
2068
2069 \sa children()
2070*/
2071
2072/*!
2073 \fn const QObjectList &QObject::children() const
2074
2075 Returns a list of child objects.
2076 The QObjectList class is defined in the \c{<QObject>} header
2077 file as the following:
2078
2079 \quotefromfile kernel/qobject.h
2080 \skipto /typedef .*QObjectList/
2081 \printuntil QObjectList
2082
2083 The first child added is the \l{QList::first()}{first} object in
2084 the list and the last child added is the \l{QList::last()}{last}
2085 object in the list, i.e. new children are appended at the end.
2086
2087 Note that the list order changes when QWidget children are
2088 \l{QWidget::raise()}{raised} or \l{QWidget::lower()}{lowered}. A
2089 widget that is raised becomes the last object in the list, and a
2090 widget that is lowered becomes the first object in the list.
2091
2092 \sa findChild(), findChildren(), parent(), setParent()
2093*/
2094
2095
2096/*!
2097 \fn template<typename T> T *QObject::findChild(QAnyStringView name, Qt::FindChildOptions options) const
2098
2099 Returns the child of this object that can be cast into type T and
2100 that is called \a name, or \nullptr if there is no such object.
2101 A null \a name argument causes all objects to be matched. An empty,
2102 non-null \a name matches only objects whose \l objectName is empty.
2103 The search is performed recursively, unless \a options specifies the
2104 option FindDirectChildrenOnly.
2105
2106 If there is more than one child matching the search, the most-direct
2107 ancestor is returned. If there are several most-direct ancestors, the
2108 first child in children() will be returned. In that case, it's better
2109 to use findChildren() to get the complete list of all children.
2110
2111 This example returns a child \c{QPushButton} of \c{parentWidget}
2112 named \c{"button1"}, even if the button isn't a direct child of
2113 the parent:
2114
2115 \snippet code/src_corelib_kernel_qobject.cpp 10
2116
2117 This example returns a \c{QListWidget} child of \c{parentWidget}:
2118
2119 \snippet code/src_corelib_kernel_qobject.cpp 11
2120
2121 This example returns a child \c{QPushButton} of \c{parentWidget}
2122 (its direct parent) named \c{"button1"}:
2123
2124 \snippet code/src_corelib_kernel_qobject.cpp 41
2125
2126 This example returns a \c{QListWidget} child of \c{parentWidget},
2127 its direct parent:
2128
2129 \snippet code/src_corelib_kernel_qobject.cpp 42
2130
2131 \note In Qt versions prior to 6.7, this function took \a name as
2132 \c{QString}, not \c{QAnyStringView}.
2133
2134 \sa findChildren()
2135*/
2136
2137/*!
2138 \fn template<typename T> T *QObject::findChild(Qt::FindChildOptions options) const
2139 \overload
2140 \since 6.7
2141
2142 Returns the child of this object that can be cast into type T, or
2143 \nullptr if there is no such object.
2144 The search is performed recursively, unless \a options specifies the
2145 option FindDirectChildrenOnly.
2146
2147 If there is more than one child matching the search, the most-direct ancestor
2148 is returned. If there are several most-direct ancestors, the first child in
2149 children() will be returned. In that case, it's better to use findChildren()
2150 to get the complete list of all children.
2151
2152 \sa findChildren()
2153*/
2154
2155/*!
2156 \fn template<typename T> QList<T> QObject::findChildren(QAnyStringView name, Qt::FindChildOptions options) const
2157
2158 Returns all children of this object with the given \a name that can be
2159 cast to type T, or an empty list if there are no such objects.
2160 A null \a name argument causes all objects to be matched, an empty one
2161 only those whose objectName is empty.
2162 The search is performed recursively, unless \a options specifies the
2163 option FindDirectChildrenOnly.
2164
2165 The following example shows how to find a list of child \c{QWidget}s of
2166 the specified \c{parentWidget} named \c{widgetname}:
2167
2168 \snippet code/src_corelib_kernel_qobject.cpp 12
2169
2170 This example returns all \c{QPushButton}s that are children of \c{parentWidget}:
2171
2172 \snippet code/src_corelib_kernel_qobject.cpp 13
2173
2174 This example returns all \c{QPushButton}s that are immediate children of \c{parentWidget}:
2175
2176 \snippet code/src_corelib_kernel_qobject.cpp 43
2177
2178 \note In Qt versions prior to 6.7, this function took \a name as
2179 \c{QString}, not \c{QAnyStringView}.
2180
2181 \sa findChild()
2182*/
2183
2184/*!
2185 \fn template<typename T> QList<T> QObject::findChildren(Qt::FindChildOptions options) const
2186 \overload
2187 \since 6.3
2188
2189 Returns all children of this object that can be cast to type T, or
2190 an empty list if there are no such objects.
2191 The search is performed recursively, unless \a options specifies the
2192 option FindDirectChildrenOnly.
2193
2194 \sa findChild()
2195*/
2196
2197/*!
2198 \fn template<typename T> QList<T> QObject::findChildren(const QRegularExpression &re, Qt::FindChildOptions options) const
2199 \overload findChildren()
2200
2201 \since 5.0
2202
2203 Returns the children of this object that can be cast to type T
2204 and that have names matching the regular expression \a re,
2205 or an empty list if there are no such objects.
2206 The search is performed recursively, unless \a options specifies the
2207 option FindDirectChildrenOnly.
2208*/
2209
2210/*!
2211 \fn template<typename T> T qFindChild(const QObject *obj, const QString &name)
2212 \relates QObject
2213 \overload qFindChildren()
2214 \deprecated [4.8]
2215
2216 This function is equivalent to
2217 \a{obj}->\l{QObject::findChild()}{findChild}<T>(\a name).
2218
2219 \note This function was provided as a workaround for MSVC 6
2220 which did not support member template functions. It is advised
2221 to use the other form in new code.
2222
2223 \sa QObject::findChild()
2224*/
2225
2226/*!
2227 \fn template<typename T> QList<T> qFindChildren(const QObject *obj, const QString &name)
2228 \relates QObject
2229 \overload qFindChildren()
2230 \deprecated [4.8]
2231
2232 This function is equivalent to
2233 \a{obj}->\l{QObject::findChildren()}{findChildren}<T>(\a name).
2234
2235 \note This function was provided as a workaround for MSVC 6
2236 which did not support member template functions. It is advised
2237 to use the other form in new code.
2238
2239 \sa QObject::findChildren()
2240*/
2241
2242static bool matches_objectName_non_null(QObject *obj, QAnyStringView name)
2243{
2244 if (auto ext = QObjectPrivate::get(obj)->extraData)
2245 return ext ->objectName.valueBypassingBindings() == name;
2246 return name.isEmpty();
2247}
2248
2249/*!
2250 \internal
2251*/
2252void qt_qFindChildren_helper(const QObject *parent, QAnyStringView name,
2253 const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
2254{
2255 Q_ASSERT(parent);
2256 Q_ASSERT(list);
2257 for (QObject *obj : parent->children()) {
2258 if (mo.cast(obj) && (name.isNull() || matches_objectName_non_null(obj, name)))
2259 list->append(obj);
2260 if (options & Qt::FindChildrenRecursively)
2261 qt_qFindChildren_helper(obj, name, mo, list, options);
2262 }
2263}
2264
2265#if QT_CONFIG(regularexpression)
2266/*!
2267 \internal
2268*/
2269void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re,
2270 const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
2271{
2272 Q_ASSERT(parent);
2273 Q_ASSERT(list);
2274 for (QObject *obj : parent->children()) {
2275 if (mo.cast(obj)) {
2276 QRegularExpressionMatch m = re.match(obj->objectName());
2277 if (m.hasMatch())
2278 list->append(obj);
2279 }
2280 if (options & Qt::FindChildrenRecursively)
2281 qt_qFindChildren_helper(obj, re, mo, list, options);
2282 }
2283}
2284#endif // QT_CONFIG(regularexpression)
2285
2286/*!
2287 \internal
2288*/
2289QObject *qt_qFindChild_helper(const QObject *parent, QAnyStringView name, const QMetaObject &mo, Qt::FindChildOptions options)
2290{
2291 Q_ASSERT(parent);
2292 for (QObject *obj : parent->children()) {
2293 if (mo.cast(obj) && (name.isNull() || matches_objectName_non_null(obj, name)))
2294 return obj;
2295 }
2296 if (options & Qt::FindChildrenRecursively) {
2297 for (QObject *child : parent->children()) {
2298 if (QObject *obj = qt_qFindChild_helper(child, name, mo, options))
2299 return obj;
2300 }
2301 }
2302 return nullptr;
2303}
2304
2305/*!
2306 Makes the object a child of \a parent.
2307
2308 \sa parent(), children()
2309*/
2310void QObject::setParent(QObject *parent)
2311{
2312 Q_D(QObject);
2313 Q_ASSERT(!d->isWidget);
2314 d->setParent_helper(parent);
2315}
2316
2317void QObjectPrivate::deleteChildren()
2318{
2319 Q_ASSERT_X(!isDeletingChildren, "QObjectPrivate::deleteChildren()", "isDeletingChildren already set, did this function recurse?");
2320 isDeletingChildren = true;
2321 // delete children objects
2322 // don't use qDeleteAll as the destructor of the child might
2323 // delete siblings
2324 for (int i = 0; i < children.size(); ++i) {
2325 currentChildBeingDeleted = children.at(i);
2326 children[i] = nullptr;
2327 delete currentChildBeingDeleted;
2328 }
2329 children.clear();
2330 currentChildBeingDeleted = nullptr;
2331 isDeletingChildren = false;
2332}
2333
2334void QObjectPrivate::setParent_helper(QObject *o)
2335{
2336 Q_Q(QObject);
2337 Q_ASSERT_X(q != o, Q_FUNC_INFO, "Cannot parent a QObject to itself");
2338#ifdef QT_DEBUG
2339 const auto checkForParentChildLoops = qScopeGuard([&](){
2340 int depth = 0;
2341 auto p = parent;
2342 while (p) {
2343 if (++depth == CheckForParentChildLoopsWarnDepth) {
2344 qWarning("QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
2345 "this is undefined behavior",
2346 q, q->metaObject()->className(), qPrintable(q->objectName()));
2347 }
2348 p = p->parent();
2349 }
2350 });
2351#endif
2352
2353 if (o == parent)
2354 return;
2355
2356 if (parent) {
2357 QObjectPrivate *parentD = parent->d_func();
2358 if (parentD->isDeletingChildren && wasDeleted
2359 && parentD->currentChildBeingDeleted == q) {
2360 // don't do anything since QObjectPrivate::deleteChildren() already
2361 // cleared our entry in parentD->children.
2362 } else {
2363 const qsizetype index = parentD->children.indexOf(q);
2364 if (index < 0) {
2365 // we're probably recursing into setParent() from a ChildRemoved event, don't do anything
2366 } else if (parentD->isDeletingChildren) {
2367 parentD->children[index] = nullptr;
2368 } else {
2369 parentD->children.removeAt(index);
2370 if (sendChildEvents && parentD->receiveChildEvents) {
2371 QChildEvent e(QEvent::ChildRemoved, q);
2372 QCoreApplication::sendEvent(parent, &e);
2373 }
2374 }
2375 }
2376 }
2377
2378 if (receiveParentEvents) {
2379 Q_ASSERT(!isWidget); // Handled in QWidget
2380 QEvent e(QEvent::ParentAboutToChange);
2381 QCoreApplication::sendEvent(q, &e);
2382 }
2383
2384 parent = o;
2385
2386 if (parent) {
2387 // object hierarchies are constrained to a single thread
2388 if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) {
2389 qWarning("QObject::setParent: Cannot set parent, new parent is in a different thread");
2390 parent = nullptr;
2391 return;
2392 }
2393 parent->d_func()->children.append(q);
2394 if (sendChildEvents && parent->d_func()->receiveChildEvents) {
2395 if (!isWidget) {
2396 QChildEvent e(QEvent::ChildAdded, q);
2397 QCoreApplication::sendEvent(parent, &e);
2398 }
2399 }
2400 }
2401
2402 if (receiveParentEvents) {
2403 Q_ASSERT(!isWidget); // Handled in QWidget
2404 QEvent e(QEvent::ParentChange);
2405 QCoreApplication::sendEvent(q, &e);
2406 }
2407}
2408
2409/*!
2410 \fn void QObject::installEventFilter(QObject *filterObj)
2411
2412 Installs an event filter \a filterObj on this object. For example:
2413 \snippet code/src_corelib_kernel_qobject.cpp 14
2414
2415 An event filter is an object that receives all events that are
2416 sent to this object. The filter can either stop the event or
2417 forward it to this object. The event filter \a filterObj receives
2418 events via its eventFilter() function. The eventFilter() function
2419 must return true if the event should be filtered, (i.e. stopped);
2420 otherwise it must return false.
2421
2422 If multiple event filters are installed on a single object, the
2423 filter that was installed last is activated first.
2424
2425 If \a filterObj has already been installed for this object,
2426 this function moves it so it acts as if it was installed last.
2427
2428 Here's a \c KeyPressEater class that eats the key presses of its
2429 monitored objects:
2430
2431 \snippet code/src_corelib_kernel_qobject.cpp 15
2432
2433 And here's how to install it on two widgets:
2434
2435 \snippet code/src_corelib_kernel_qobject.cpp 16
2436
2437 The QShortcut class, for example, uses this technique to intercept
2438 shortcut key presses.
2439
2440 \warning If you delete the receiver object in your eventFilter()
2441 function, be sure to return true. If you return false, Qt sends
2442 the event to the deleted object and the program will crash.
2443
2444 Note that the filtering object must be in the same thread as this
2445 object. If \a filterObj is in a different thread, this function does
2446 nothing. If either \a filterObj or this object are moved to a different
2447 thread after calling this function, the event filter will not be
2448 called until both objects have the same thread affinity again (it
2449 is \e not removed).
2450
2451 \sa removeEventFilter(), eventFilter(), event()
2452*/
2453
2454void QObject::installEventFilter(QObject *obj)
2455{
2456 Q_D(QObject);
2457 if (!obj)
2458 return;
2459 if (d->threadData.loadRelaxed() != obj->d_func()->threadData.loadRelaxed()) {
2460 qWarning("QObject::installEventFilter(): Cannot filter events for objects in a different thread.");
2461 return;
2462 }
2463
2464 d->ensureExtraData();
2465
2466 // clean up unused items in the list along the way:
2467 auto isNullOrEquals = [](auto obj) { return [obj](const auto &p) { return !p || p == obj; }; };
2468 d->extraData->eventFilters.removeIf(isNullOrEquals(obj));
2469 d->extraData->eventFilters.prepend(obj);
2470}
2471
2472/*!
2473 Removes an event filter object \a obj from this object. The
2474 request is ignored if such an event filter has not been installed.
2475
2476 All event filters for this object are automatically removed when
2477 this object is destroyed.
2478
2479 It is always safe to remove an event filter, even during event
2480 filter activation (i.e. from the eventFilter() function).
2481
2482 \sa installEventFilter(), eventFilter(), event()
2483*/
2484
2485void QObject::removeEventFilter(QObject *obj)
2486{
2487 Q_D(QObject);
2488 if (d->extraData) {
2489 for (auto &filter : d->extraData->eventFilters) {
2490 if (filter == obj) {
2491 filter = nullptr;
2492 break;
2493 }
2494 }
2495 }
2496}
2497
2498/*!
2499 \fn void QObject::destroyed(QObject *obj)
2500
2501 This signal is emitted immediately before the object \a obj is
2502 destroyed, after any instances of QPointer have been notified,
2503 and cannot be blocked.
2504
2505 All the objects's children are destroyed immediately after this
2506 signal is emitted.
2507
2508 \sa deleteLater(), QPointer
2509*/
2510
2511/*!
2512 \threadsafe
2513
2514 Schedules this object for deletion.
2515
2516 The object will be deleted when control returns to the event
2517 loop. If the event loop is not running when this function is
2518 called (e.g. deleteLater() is called on an object before
2519 QCoreApplication::exec()), the object will be deleted once the
2520 event loop is started. If deleteLater() is called after the main event loop
2521 has stopped, the object will not be deleted.
2522 If deleteLater() is called on an object that lives in a
2523 thread with no running event loop, the object will be destroyed when the
2524 thread finishes.
2525
2526 A common pattern when using a worker \c QObject in a \c QThread
2527 is to connect the thread's \c finished() signal to the worker's
2528 \c deleteLater() slot to ensure it is safely deleted:
2529
2530 \code
2531 connect(thread, &QThread::finished, worker, &QObject::deleteLater);
2532 \endcode
2533
2534 Note that entering and leaving a new event loop (e.g., by opening a modal
2535 dialog) will \e not perform the deferred deletion; for the object to be
2536 deleted, the control must return to the event loop from which deleteLater()
2537 was called. This does not apply to objects deleted while a previous, nested
2538 event loop was still running: the Qt event loop will delete those objects
2539 as soon as the new nested event loop starts.
2540
2541 In situations where Qt is not driving the event dispatcher via e.g.
2542 QCoreApplication::exec() or QEventLoop::exec(), deferred deletes
2543 will not be processed automatically. To ensure deferred deletion in
2544 this scenario, the following workaround can be used:
2545
2546 \code
2547 const auto *eventDispatcher = QThread::currentThread()->eventDispatcher();
2548 QObject::connect(eventDispatcher, &QAbstractEventDispatcher::aboutToBlock,
2549 QThread::currentThread(), []{
2550 if (QThread::currentThread()->loopLevel() == 0)
2551 QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
2552 }
2553 );
2554 \endcode
2555
2556 \sa destroyed(), QPointer
2557*/
2558void QObject::deleteLater()
2559{
2560#ifdef QT_DEBUG
2561 if (qApp == this)
2562 qWarning("You are deferring the delete of QCoreApplication, this may not work as expected.");
2563#endif
2564
2565
2566 // De-bounce QDeferredDeleteEvents. Use the post event list mutex
2567 // to guard access to deleteLaterCalled, so we don't need a separate
2568 // mutex in QObjectData.
2569 auto eventListLocker = QCoreApplicationPrivate::lockThreadPostEventList(this);
2570 if (!eventListLocker.threadData)
2571 return;
2572
2573 // FIXME: The deleteLaterCalled flag is part of a bit field,
2574 // so we likely have data races here, even with the mutex above,
2575 // as long as we're not guarding every access to the bit field.
2576
2577 Q_D(QObject);
2578 if (d->deleteLaterCalled)
2579 return;
2580
2581 d->deleteLaterCalled = true;
2582
2583 int loopLevel = 0;
2584 int scopeLevel = 0;
2585
2586 auto *objectThreadData = eventListLocker.threadData;
2587 if (objectThreadData == QThreadData::current()) {
2588 // Remember the current running eventloop for deleteLater
2589 // calls in the object's own thread.
2590
2591 // Events sent by non-Qt event handlers (such as glib) may not
2592 // have the scopeLevel set correctly. The scope level makes sure that
2593 // code like this:
2594 // foo->deleteLater();
2595 // qApp->processEvents(); // without passing QEvent::DeferredDelete
2596 // will not cause "foo" to be deleted before returning to the event loop.
2597
2598 loopLevel = objectThreadData->loopLevel;
2599 scopeLevel = objectThreadData->scopeLevel;
2600
2601 // If the scope level is 0 while loopLevel != 0, we are called from a
2602 // non-conformant code path, and our best guess is that the scope level
2603 // should be 1. (Loop level 0 is special: it means that no event loops
2604 // are running.)
2605 if (scopeLevel == 0 && loopLevel != 0)
2606 scopeLevel = 1;
2607 }
2608
2609 eventListLocker.unlock();
2610 QCoreApplication::postEvent(this,
2611 new QDeferredDeleteEvent(loopLevel, scopeLevel));
2612}
2613
2614/*!
2615 \internal
2616
2617 Destroys \a object in the thread it belongs to, via deleteLater(), so that its
2618 vtable and members are not touched from the wrong thread. Falls back to deleting
2619 it right away when that thread cannot run the deferred delete: it is the current
2620 thread, or it has no event dispatcher (never started, or torn down at application
2621 exit). This is meant for objects deleted from a thread that is usually not their
2622 own, e.g. a worker handed to a thread pool.
2623
2624 The thread and the dispatcher are read from the object's QThreadData, which stays
2625 alive as long as the object does, rather than from QThread, which the owning thread
2626 may be destroying concurrently.
2627*/
2628void QObjectPrivate::deleteInOwnThread(QObject *object)
2629{
2630 QThreadData *objectData = QObjectPrivate::get(object)->threadData.loadRelaxed();
2631 if (objectData->hasEventDispatcher()
2632 && objectData->threadId.loadRelaxed() != QThread::currentThreadId()) {
2633 object->deleteLater();
2634 } else {
2635 delete object;
2636 }
2637}
2638
2639/*!
2640 \fn QString QObject::tr(const char *sourceText, const char *disambiguation, int n)
2641 \reentrant
2642
2643 Returns a translated version of \a sourceText, optionally based on a
2644 \a disambiguation string and value of \a n for strings containing plurals;
2645 otherwise returns QString::fromUtf8(\a sourceText) if no appropriate
2646 translated string is available.
2647
2648 Example:
2649 \snippet ../widgets/itemviews/spreadsheet/spreadsheet.cpp implicit tr context
2650 \dots
2651
2652 If the same \a sourceText is used in different roles within the
2653 same context, an additional identifying string may be passed in
2654 \a disambiguation (\nullptr by default).
2655
2656 Example:
2657
2658 \snippet code/src_corelib_kernel_qobject.cpp 17
2659 \dots
2660
2661 See \l{Writing Source Code for Translation} for a detailed description of
2662 Qt's translation mechanisms in general, and the
2663 \l{Writing Source Code for Translation#Disambiguate Identical Text}
2664 {Disambiguate Identical Text} section for information on disambiguation.
2665
2666 \warning This method is reentrant only if all translators are
2667 installed \e before calling this method. Installing or removing
2668 translators while performing translations is not supported. Doing
2669 so will probably result in crashes or other undesirable behavior.
2670
2671 \sa QCoreApplication::translate(), {Internationalization with Qt}
2672*/
2673
2674/*****************************************************************************
2675 Signals and slots
2676 *****************************************************************************/
2677
2678namespace {
2679// This class provides (per-thread) storage for qFlagLocation()
2680class FlaggedDebugSignatures
2681{
2682 uint idx = 0;
2683 std::array<const char *, 2> locations = {}; // one for the SIGNAL, one for the SLOT
2684
2685public:
2686 void store(const char* method) noexcept
2687 { locations[idx++ % locations.size()] = method; }
2688
2689 bool contains(const char *method) const noexcept
2690 { return std::find(locations.begin(), locations.end(), method) != locations.end(); }
2691};
2692
2693Q_CONSTINIT static thread_local FlaggedDebugSignatures flaggedSignatures = {};
2694} // unnamed namespace
2695
2696const char *qFlagLocation(const char *method)
2697{
2698 flaggedSignatures.store(method);
2699 return method;
2700}
2701
2702static int extract_code(const char *member)
2703{
2704 // extract code, ensure QMETHOD_CODE <= code <= QSIGNAL_CODE
2705 return (((int)(*member) - '0') & 0x3);
2706}
2707
2708static const char *extract_location(const char *member)
2709{
2710 if (flaggedSignatures.contains(member)) {
2711 // signature includes location information after the first null-terminator
2712 const char *location = member + qstrlen(member) + 1;
2713 if (*location != '\0')
2714 return location;
2715 }
2716 return nullptr;
2717}
2718
2719static bool check_signal_macro(const QObject *sender, const char *signal,
2720 const char *func, const char *op)
2721{
2722 int sigcode = extract_code(signal);
2723 if (sigcode != QSIGNAL_CODE) {
2724 if (sigcode == QSLOT_CODE)
2725 qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s", func, op,
2726 sender->metaObject()->className(), signal + 1);
2727 else
2728 qCWarning(lcConnect, "QObject::%s: Use the SIGNAL macro to %s %s::%s", func, op,
2729 sender->metaObject()->className(), signal);
2730 return false;
2731 }
2732 return true;
2733}
2734
2735static bool check_method_code(int code, const QObject *object, const char *method, const char *func)
2736{
2737 if (code != QSLOT_CODE && code != QSIGNAL_CODE) {
2738 qCWarning(lcConnect,
2739 "QObject::%s: Use the SLOT or SIGNAL macro to "
2740 "%s %s::%s",
2741 func, func, object->metaObject()->className(), method);
2742 return false;
2743 }
2744 return true;
2745}
2746
2747#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
2748static void check_and_warn_non_slot(const char *func, const char *method, int membcode,
2749 const QMetaObject *rmeta, const QMetaMethod &rmethod)
2750{
2751 if (membcode == QSLOT_CODE && rmethod.methodType() != QMetaMethod::Slot) {
2752 // In Qt7 QMetaObject::indexOfSlot{,relative} will return -1 if `method`
2753 // isn't a slot.
2754 qCWarning(lcConnect,
2755 "QObject::%s: the SLOT() macro is used with a non-slot function: %s::%s. "
2756 "This currently works due to backwards-compatibility reasons. In Qt7 the "
2757 "SLOT() macro will work only for methods marked as slots.",
2758 func, rmeta->className(), method);
2759 }
2760}
2761#endif // QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
2762
2764static void err_method_notfound(const QObject *object,
2765 const char *method, const char *func)
2766{
2767 const char *type = "method";
2768 switch (extract_code(method)) {
2769 case QSLOT_CODE: type = "slot"; break;
2770 case QSIGNAL_CODE: type = "signal"; break;
2771 }
2772 const char *loc = extract_location(method);
2773 const char *err;
2774 if (strchr(method, ')') == nullptr) // common typing mistake
2775 err = "Parentheses expected,";
2776 else
2777 err = "No such";
2778 qCWarning(lcConnect, "QObject::%s: %s %s %s::%s%s%s", func, err, type,
2779 object->metaObject()->className(), method + 1, loc ? " in " : "", loc ? loc : "");
2780}
2781
2782enum class ConnectionEnd : bool { Sender, Receiver };
2784static void err_info_about_object(const char *func, const QObject *o, ConnectionEnd end)
2785{
2786 if (!o)
2787 return;
2788 const QString name = o->objectName();
2789 if (name.isEmpty())
2790 return;
2791 const bool sender = end == ConnectionEnd::Sender;
2792 qCWarning(lcConnect, "QObject::%s: (%s name:%*s'%ls')",
2793 func,
2794 sender ? "sender" : "receiver",
2795 sender ? 3 : 1, // ← length of generated whitespace
2796 "",
2797 qUtf16Printable(name));
2798}
2799
2801static void err_info_about_objects(const char *func, const QObject *sender, const QObject *receiver)
2802{
2805}
2806
2808static void connectWarning(const QObject *sender,
2809 const QMetaObject *senderMetaObject,
2810 const QObject *receiver,
2811 const char *message)
2812{
2813 const char *senderString = sender ? sender->metaObject()->className()
2814 : senderMetaObject ? senderMetaObject->className()
2815 : "Unknown";
2816 const char *receiverString = receiver ? receiver->metaObject()->className()
2817 : "Unknown";
2818 qCWarning(lcConnect, "QObject::connect(%s, %s): %s", senderString, receiverString, message);
2819}
2820
2821/*!
2822 Returns a pointer to the object that sent the signal, if called in
2823 a slot activated by a signal; otherwise it returns \nullptr. The pointer
2824 is valid only during the execution of the slot that calls this
2825 function from this object's thread context.
2826
2827 The pointer returned by this function becomes invalid if the
2828 sender is destroyed, or if the slot is disconnected from the
2829 sender's signal.
2830
2831 \warning This function violates the object-oriented principle of
2832 modularity. However, getting access to the sender might be useful
2833 when many signals are connected to a single slot.
2834
2835 \warning As mentioned above, the return value of this function is
2836 not valid when the slot is called via a Qt::DirectConnection from
2837 a thread different from this object's thread. Do not use this
2838 function in this type of scenario.
2839
2840 \sa senderSignalIndex()
2841*/
2842
2843QObject *QObject::sender() const
2844{
2845 Q_D(const QObject);
2846
2847 QMutexLocker locker(signalSlotLock(this));
2848 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2849 if (!cd || !cd->currentSender)
2850 return nullptr;
2851
2852 for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2853 if (c->sender == cd->currentSender->sender)
2854 return cd->currentSender->sender;
2855 }
2856
2857 return nullptr;
2858}
2859
2860/*!
2861 \since 4.8
2862
2863 Returns the meta-method index of the signal that called the currently
2864 executing slot, which is a member of the class returned by sender().
2865 If called outside of a slot activated by a signal, -1 is returned.
2866
2867 For signals with default parameters, this function will always return
2868 the index with all parameters, regardless of which was used with
2869 connect(). For example, the signal \c {destroyed(QObject *obj = \nullptr)}
2870 will have two different indexes (with and without the parameter), but
2871 this function will always return the index with a parameter. This does
2872 not apply when overloading signals with different parameters.
2873
2874 \warning This function violates the object-oriented principle of
2875 modularity. However, getting access to the signal index might be useful
2876 when many signals are connected to a single slot.
2877
2878 \warning The return value of this function is not valid when the slot
2879 is called via a Qt::DirectConnection from a thread different from this
2880 object's thread. Do not use this function in this type of scenario.
2881
2882 \sa sender(), QMetaObject::indexOfSignal(), QMetaObject::method()
2883*/
2884
2885int QObject::senderSignalIndex() const
2886{
2887 Q_D(const QObject);
2888
2889 QMutexLocker locker(signalSlotLock(this));
2890 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2891 if (!cd || !cd->currentSender)
2892 return -1;
2893
2894 for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2895 if (c->sender == cd->currentSender->sender) {
2896 // Convert from signal range to method range
2897 return QMetaObjectPrivate::signal(c->sender->metaObject(), cd->currentSender->signal).methodIndex();
2898 }
2899 }
2900
2901 return -1;
2902}
2903
2904/*!
2905 Returns the number of receivers connected to the \a signal.
2906
2907 Since both slots and signals can be used as receivers for signals,
2908 and the same connections can be made many times, the number of
2909 receivers is the same as the number of connections made from this
2910 signal.
2911
2912 When calling this function, you can use the \c SIGNAL() macro to
2913 pass a specific signal:
2914
2915 \snippet code/src_corelib_kernel_qobject.cpp 21
2916
2917 As the code snippet above illustrates, you can use this function to avoid
2918 expensive operations or emitting a signal that nobody listens to.
2919
2920 \warning In a multithreaded application, consecutive calls to this
2921 function are not guaranteed to yield the same results.
2922
2923 \warning This function violates the object-oriented principle of
2924 modularity. In particular, this function must not be called from an
2925 override of connectNotify() or disconnectNotify(), as those might get
2926 called from any thread.
2927
2928 \sa isSignalConnected()
2929*/
2930
2931int QObject::receivers(const char *signal) const
2932{
2933 Q_D(const QObject);
2934 int receivers = 0;
2935 if (signal) {
2936 QByteArray signal_name = QMetaObject::normalizedSignature(signal);
2937 signal = signal_name;
2938#ifndef QT_NO_DEBUG
2939 if (!check_signal_macro(this, signal, "receivers", "bind"))
2940 return 0;
2941#endif
2942 signal++; // skip code
2943 int signal_index = d->signalIndex(signal);
2944 if (signal_index < 0) {
2945#ifndef QT_NO_DEBUG
2946 err_method_notfound(this, signal - 1, "receivers");
2947#endif
2948 return 0;
2949 }
2950
2951 if (!d->isSignalConnected(signal_index))
2952 return receivers;
2953
2954 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::receivers) {
2955 receivers += QAbstractDeclarativeData::receivers(d->declarativeData, this,
2956 signal_index);
2957 }
2958
2959 QMutexLocker locker(signalSlotLock(this));
2960 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2961 if (cd && signal_index < cd->signalVectorCount()) {
2962 const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
2963 while (c) {
2964 receivers += c->receiver.loadRelaxed() ? 1 : 0;
2965 c = c->nextConnectionList.loadRelaxed();
2966 }
2967 }
2968 }
2969 return receivers;
2970}
2971
2972/*!
2973 \since 5.0
2974 Returns \c true if the \a signal is connected to at least one receiver,
2975 otherwise returns \c false.
2976
2977 \a signal must be a signal member of this object, otherwise the behaviour
2978 is undefined.
2979
2980 \snippet code/src_corelib_kernel_qobject.cpp 49
2981
2982 As the code snippet above illustrates, you can use this function to avoid
2983 expensive operations or emitting a signal that nobody listens to.
2984
2985 \warning In a multithreaded application, consecutive calls to this
2986 function are not guaranteed to yield the same results.
2987
2988 \warning This function violates the object-oriented principle of
2989 modularity. In particular, this function must not be called from an
2990 override of connectNotify() or disconnectNotify(), as those might get
2991 called from any thread.
2992
2993 \sa receivers()
2994*/
2995bool QObject::isSignalConnected(const QMetaMethod &signal) const
2996{
2997 Q_D(const QObject);
2998 if (!signal.mobj)
2999 return false;
3000
3001 Q_ASSERT_X(signal.mobj->cast(this) && signal.methodType() == QMetaMethod::Signal,
3002 "QObject::isSignalConnected" , "the parameter must be a signal member of the object");
3003 uint signalIndex = signal.relativeMethodIndex();
3004
3005 if (signal.data.flags() & MethodCloned)
3006 signalIndex = QMetaObjectPrivate::originalClone(signal.mobj, signalIndex);
3007
3008 signalIndex += QMetaObjectPrivate::signalOffset(signal.mobj);
3009
3010 QMutexLocker locker(signalSlotLock(this));
3011 return d->isSignalConnected(signalIndex, true);
3012}
3013
3014/*!
3015 \internal
3016
3017 This helper function calculates signal and method index for the given
3018 member in the specified class.
3019
3020 \list
3021 \li If member.mobj is \nullptr then both signalIndex and methodIndex are set to -1.
3022
3023 \li If specified member is not a member of obj instance class (or one of
3024 its parent classes) then both signalIndex and methodIndex are set to -1.
3025 \endlist
3026
3027 This function is used by QObject::connect and QObject::disconnect which
3028 are working with QMetaMethod.
3029
3030 \a signalIndex is set to the signal index of member. If the member
3031 specified is not signal this variable is set to -1.
3032
3033 \a methodIndex is set to the method index of the member. If the
3034 member is not a method of the object specified by the \a obj argument this
3035 variable is set to -1.
3036*/
3037void QMetaObjectPrivate::memberIndexes(const QObject *obj,
3038 const QMetaMethod &member,
3039 int *signalIndex, int *methodIndex)
3040{
3041 *signalIndex = -1;
3042 *methodIndex = -1;
3043 if (!obj || !member.mobj)
3044 return;
3045 const QMetaObject *m = obj->metaObject();
3046 // Check that member is member of obj class
3047 while (m != nullptr && m != member.mobj)
3048 m = m->d.superdata;
3049 if (!m)
3050 return;
3051 *signalIndex = *methodIndex = member.relativeMethodIndex();
3052
3053 int signalOffset;
3054 int methodOffset;
3055 computeOffsets(m, &signalOffset, &methodOffset);
3056
3057 *methodIndex += methodOffset;
3058 if (member.methodType() == QMetaMethod::Signal) {
3059 *signalIndex = originalClone(m, *signalIndex);
3060 *signalIndex += signalOffset;
3061 } else {
3062 *signalIndex = -1;
3063 }
3064}
3065
3066#ifndef QT_NO_DEBUG
3067static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaMethod &signal,
3068 const QMetaObject *receiver, const QMetaMethod &method)
3069{
3070 if (signal.attributes() & QMetaMethod::Compatibility) {
3071 if (!(method.attributes() & QMetaMethod::Compatibility))
3072 qCWarning(lcConnect, "QObject::connect: Connecting from COMPAT signal (%s::%s)",
3073 sender->className(), signal.methodSignature().constData());
3074 } else if ((method.attributes() & QMetaMethod::Compatibility)
3075 && method.methodType() == QMetaMethod::Signal) {
3076 qCWarning(lcConnect, "QObject::connect: Connecting from %s::%s to COMPAT slot (%s::%s)",
3077 sender->className(), signal.methodSignature().constData(), receiver->className(),
3078 method.methodSignature().constData());
3079 }
3080}
3081#endif
3082
3083/*!
3084 \threadsafe
3085
3086 Creates a connection of the given \a type from the \a signal in
3087 the \a sender object to the \a method in the \a receiver object.
3088 Returns a handle to the connection that can be used to disconnect
3089 it later.
3090
3091 You must use the \c SIGNAL() and \c SLOT() macros when specifying
3092 the \a signal and the \a method, for example:
3093
3094 \snippet code/src_corelib_kernel_qobject.cpp 22
3095
3096 This example ensures that the label always displays the current
3097 scroll bar value. Note that the signal and slots parameters must not
3098 contain any variable names, only the type. E.g. the following would
3099 not work and return false:
3100
3101 \snippet code/src_corelib_kernel_qobject.cpp 23
3102
3103 A signal can also be connected to another signal:
3104
3105 \snippet code/src_corelib_kernel_qobject.cpp 24
3106
3107 In this example, the \c MyWidget constructor relays a signal from
3108 a private member variable, and makes it available under a name
3109 that relates to \c MyWidget.
3110
3111 A signal can be connected to many slots and signals. Many signals
3112 can be connected to one slot.
3113
3114 If a signal is connected to several slots, the slots are activated
3115 in the same order in which the connections were made, when the
3116 signal is emitted.
3117
3118 The function returns a QMetaObject::Connection that represents
3119 a handle to a connection if it successfully
3120 connects the signal to the slot. The connection handle will be invalid
3121 if it cannot create the connection, for example, if QObject is unable
3122 to verify the existence of either \a signal or \a method, or if their
3123 signatures aren't compatible.
3124 You can check if the handle is valid by casting it to a bool.
3125
3126 By default, a signal is emitted for every connection you make;
3127 two signals are emitted for duplicate connections. You can break
3128 all of these connections with a single disconnect() call.
3129 If you pass the Qt::UniqueConnection \a type, the connection will only
3130 be made if it is not a duplicate. If there is already a duplicate
3131 (exact same signal to the exact same slot on the same objects),
3132 the connection will fail and connect will return an invalid QMetaObject::Connection.
3133
3134 \note Qt::UniqueConnections do not work for lambdas, non-member functions
3135 and functors; they only apply to connecting to member functions.
3136
3137 The optional \a type parameter describes the type of connection
3138 to establish. In particular, it determines whether a particular
3139 signal is delivered to a slot immediately or queued for delivery
3140 at a later time. If the signal is queued, the parameters must be
3141 of types that are known to Qt's meta-object system, because Qt
3142 needs to copy the arguments to store them in an event behind the
3143 scenes. If you try to use a queued connection and get the error
3144 message
3145
3146 \snippet code/src_corelib_kernel_qobject.cpp 25
3147
3148 call qRegisterMetaType() to register the data type before you
3149 establish the connection.
3150
3151 \sa disconnect(), sender(), qRegisterMetaType(), Q_DECLARE_METATYPE(),
3152 {Differences between String-Based and Functor-Based Connections}
3153*/
3154QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal,
3155 const QObject *receiver, const char *method,
3156 Qt::ConnectionType type)
3157{
3158 if (sender == nullptr || receiver == nullptr || signal == nullptr || method == nullptr) {
3159 qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
3160 sender ? sender->metaObject()->className() : "(nullptr)",
3161 (signal && *signal) ? signal + 1 : "(nullptr)",
3162 receiver ? receiver->metaObject()->className() : "(nullptr)",
3163 (method && *method) ? method + 1 : "(nullptr)");
3164 return QMetaObject::Connection(nullptr);
3165 }
3166
3167 if (!check_signal_macro(sender, signal, "connect", "bind"))
3168 return QMetaObject::Connection(nullptr);
3169
3170 int membcode = extract_code(method);
3171 if (!check_method_code(membcode, receiver, method, "connect"))
3172 return QMetaObject::Connection(nullptr);
3173
3174 QByteArray pinnedSignal;
3175 const QMetaObject *smeta = sender->metaObject();
3176 const char *signal_arg = signal;
3177 ++signal; // skip code
3178 QByteArrayView signalView{signal}; // after skipping code
3179 QArgumentTypeArray signalTypes;
3180 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3181 QByteArrayView signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3182 int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3183 if (signal_index < 0) {
3184 // check for normalized signatures
3185 pinnedSignal = QMetaObjectPrivate::normalizedSignature(signalView);
3186 signalView = pinnedSignal;
3187
3188 signalTypes.clear();
3189 signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3190 smeta = sender->metaObject();
3191 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3192 }
3193 if (signal_index < 0) {
3194 err_method_notfound(sender, signal_arg, "connect");
3195 err_info_about_objects("connect", sender, receiver);
3196 return QMetaObject::Connection(nullptr);
3197 }
3198 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3199 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3200
3201 QByteArray pinnedMethod;
3202 const char *method_arg = method;
3203 ++method; // skip code
3204 QByteArrayView methodView{method}; // after skipping code
3205
3206 QArgumentTypeArray methodTypes;
3207 QByteArrayView methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3208 const QMetaObject *rmeta = receiver->metaObject();
3209 int method_index_relative = -1;
3210 Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
3211 switch (membcode) {
3212 case QSLOT_CODE:
3213 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3214 &rmeta, methodName, methodTypes);
3215 break;
3216 case QSIGNAL_CODE:
3217 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3218 &rmeta, methodName, methodTypes);
3219 break;
3220 }
3221
3222 if (method_index_relative < 0) {
3223 // check for normalized methods
3224 pinnedMethod = QMetaObjectPrivate::normalizedSignature(methodView);
3225 methodView = pinnedMethod;
3226
3227 methodTypes.clear();
3228 methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3229 // rmeta may have been modified above
3230 rmeta = receiver->metaObject();
3231 switch (membcode) {
3232 case QSLOT_CODE:
3233 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3234 &rmeta, methodName, methodTypes);
3235 break;
3236 case QSIGNAL_CODE:
3237 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3238 &rmeta, methodName, methodTypes);
3239 break;
3240 }
3241 }
3242
3243 if (method_index_relative < 0) {
3244 err_method_notfound(receiver, method_arg, "connect");
3245 err_info_about_objects("connect", sender, receiver);
3246 return QMetaObject::Connection(nullptr);
3247 }
3248
3249 if (!QMetaObjectPrivate::checkConnectArgs(signalTypes, methodTypes)) {
3250 qCWarning(lcConnect,
3251 "QObject::connect: Incompatible sender/receiver arguments"
3252 "\n %s::%s --> %s::%s",
3253 sender->metaObject()->className(), signalView.constData(),
3254 receiver->metaObject()->className(), methodView.constData());
3255 return QMetaObject::Connection(nullptr);
3256 }
3257
3258 // ### Future work: attempt get the metatypes from the meta object first
3259 // because it's possible they're all registered.
3260 int *types = nullptr;
3261 if (type == Qt::QueuedConnection && !(types = queuedConnectionTypes(signalTypes))) {
3262 return QMetaObject::Connection(nullptr);
3263 }
3264
3265 QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
3266#ifndef QT_NO_DEBUG
3267 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3268 check_and_warn_compat(smeta, smethod, rmeta, rmethod);
3269#endif
3270
3271#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
3272 check_and_warn_non_slot("connect", method, membcode, rmeta, rmethod);
3273#endif
3274
3275 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3276 sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
3277 return handle;
3278}
3279
3280/*!
3281 \since 4.8
3282
3283 Creates a connection of the given \a type from the \a signal in
3284 the \a sender object to the \a method in the \a receiver object.
3285 Returns a handle to the connection that can be used to disconnect
3286 it later.
3287
3288 The Connection handle will be invalid if it cannot create the
3289 connection, for example, the parameters were invalid.
3290 You can check if the QMetaObject::Connection is valid by casting it to a bool.
3291
3292 This function works in the same way as
3293 \c {connect(const QObject *sender, const char *signal,
3294 const QObject *receiver, const char *method,
3295 Qt::ConnectionType type)}
3296 but it uses QMetaMethod to specify signal and method.
3297
3298 \sa connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
3299 */
3300QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMethod &signal,
3301 const QObject *receiver, const QMetaMethod &method,
3302 Qt::ConnectionType type)
3303{
3304 if (sender == nullptr
3305 || receiver == nullptr
3306 || signal.methodType() != QMetaMethod::Signal
3307 || method.methodType() == QMetaMethod::Constructor) {
3308 qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
3309 sender ? sender->metaObject()->className() : "(nullptr)",
3310 signal.methodSignature().constData(),
3311 receiver ? receiver->metaObject()->className() : "(nullptr)",
3312 method.methodSignature().constData());
3313 return QMetaObject::Connection(nullptr);
3314 }
3315
3316 int signal_index;
3317 int method_index;
3318 {
3319 int dummy;
3320 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3321 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3322 }
3323
3324 const QMetaObject *smeta = sender->metaObject();
3325 const QMetaObject *rmeta = receiver->metaObject();
3326 if (signal_index == -1) {
3327 qCWarning(lcConnect, "QObject::connect: Can't find signal %s on instance of class %s",
3328 signal.methodSignature().constData(), smeta->className());
3329 return QMetaObject::Connection(nullptr);
3330 }
3331 if (method_index == -1) {
3332 qCWarning(lcConnect, "QObject::connect: Can't find method %s on instance of class %s",
3333 method.methodSignature().constData(), rmeta->className());
3334 return QMetaObject::Connection(nullptr);
3335 }
3336
3337 if (!QMetaObject::checkConnectArgs(signal.methodSignature().constData(),
3338 method.methodSignature().constData())) {
3339 qCWarning(lcConnect,
3340 "QObject::connect: Incompatible sender/receiver arguments"
3341 "\n %s::%s --> %s::%s",
3342 smeta->className(), signal.methodSignature().constData(), rmeta->className(),
3343 method.methodSignature().constData());
3344 return QMetaObject::Connection(nullptr);
3345 }
3346
3347 int *types = nullptr;
3348 if ((type == Qt::QueuedConnection) && !(types = queuedConnectionTypes(signal)))
3349 return QMetaObject::Connection(nullptr);
3350
3351#ifndef QT_NO_DEBUG
3352 check_and_warn_compat(smeta, signal, rmeta, method);
3353#endif
3354 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3355 sender, signal_index, signal.enclosingMetaObject(), receiver, method_index, nullptr, type, types));
3356 return handle;
3357}
3358
3359/*!
3360 \fn bool QObject::connect(const QObject *sender, const char *signal, const char *method, Qt::ConnectionType type) const
3361 \overload connect()
3362 \threadsafe
3363
3364 Connects \a signal from the \a sender object to this object's \a
3365 method.
3366
3367 Equivalent to connect(\a sender, \a signal, \c this, \a method, \a type).
3368
3369 Every connection you make emits a signal, so duplicate connections emit
3370 two signals. You can break a connection using disconnect().
3371
3372 \sa disconnect()
3373*/
3374
3375/*!
3376 \threadsafe
3377
3378 Disconnects \a signal in object \a sender from \a method in object
3379 \a receiver. Returns \c true if the connection is successfully broken;
3380 otherwise returns \c false.
3381
3382 A signal-slot connection is removed when either of the objects
3383 involved are destroyed.
3384
3385 disconnect() is typically used in three ways, as the following
3386 examples demonstrate.
3387 \list 1
3388 \li Disconnect everything connected to an object's signals:
3389
3390 \snippet code/src_corelib_kernel_qobject.cpp 26
3391
3392 equivalent to the non-static overloaded function
3393
3394 \snippet code/src_corelib_kernel_qobject.cpp 27
3395
3396 \li Disconnect everything connected to a specific signal:
3397
3398 \snippet code/src_corelib_kernel_qobject.cpp 28
3399
3400 equivalent to the non-static overloaded function
3401
3402 \snippet code/src_corelib_kernel_qobject.cpp 29
3403
3404 \li Disconnect a specific receiver:
3405
3406 \snippet code/src_corelib_kernel_qobject.cpp 30
3407
3408 equivalent to the non-static overloaded function
3409
3410 \snippet code/src_corelib_kernel_qobject.cpp 31
3411
3412 \endlist
3413
3414 \include includes/qobject.qdocinc disconnect-mismatch
3415 \include includes/qobject.qdocinc disconnect-queued
3416
3417 \nullptr may be used as a wildcard, meaning "any signal", "any receiving
3418 object", or "any slot in the receiving object", respectively.
3419
3420 The \a sender may never be \nullptr. (You cannot disconnect signals
3421 from more than one object in a single call.)
3422
3423 If \a signal is \nullptr, it disconnects \a receiver and \a method from
3424 any signal. If not, only the specified signal is disconnected.
3425
3426 If \a receiver is \nullptr, it disconnects anything connected to \a
3427 signal. If not, slots in objects other than \a receiver are not
3428 disconnected.
3429
3430 If \a method is \nullptr, it disconnects anything that is connected to \a
3431 receiver. If not, only slots named \a method will be disconnected,
3432 and all other slots are left alone. The \a method must be \nullptr
3433 if \a receiver is left out, so you cannot disconnect a
3434 specifically-named slot on all objects.
3435
3436 \include includes/qobject.qdocinc disconnect-all
3437
3438 \sa connect()
3439*/
3440bool QObject::disconnect(const QObject *sender, const char *signal,
3441 const QObject *receiver, const char *method)
3442{
3443 if (sender == nullptr || (receiver == nullptr && method != nullptr)) {
3444 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
3445 return false;
3446 }
3447
3448 const char *signal_arg = signal;
3449 if (signal) {
3450 if (!check_signal_macro(sender, signal, "disconnect", "unbind"))
3451 return false;
3452 ++signal; // skip code
3453 }
3454
3455 const char *method_arg = method;
3456 int membcode = -1;
3457 if (method) {
3458 membcode = extract_code(method);
3459 if (!check_method_code(membcode, receiver, method, "disconnect"))
3460 return false;
3461 ++method; // skip code
3462 }
3463
3464 QByteArray pinnedSignal;
3465 const QMetaObject *smeta = sender->metaObject();
3466 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3467 int signal_index = -1;
3468 QByteArrayView signalName;
3469 QArgumentTypeArray signalTypes;
3470 if (signal) {
3471 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3472 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3473 if (signal_index == -1) {
3474 pinnedSignal = QMetaObject::normalizedSignature(signal);
3475 signal = pinnedSignal.constData();
3476 signalTypes.clear();
3477 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3478 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3479 signalTypes);
3480 }
3481 if (signal_index == -1) {
3482 err_method_notfound(sender, signal_arg, "disconnect");
3483 err_info_about_objects("disconnect", sender, receiver);
3484 return false;
3485 }
3486 }
3487
3488 auto getMethodIndex = [](int code, const QMetaObject *mo, QByteArrayView name,
3489 const QArgumentTypeArray &types) {
3490 switch (code) {
3491 case QSLOT_CODE:
3492 return QMetaObjectPrivate::indexOfSlot(mo, name, types);
3493 case QSIGNAL_CODE:
3494 return QMetaObjectPrivate::indexOfSignal(mo, name, types);
3495 }
3496 return -1;
3497 };
3498
3499 QByteArray pinnedMethod;
3500 const QMetaObject *rmeta = receiver ? receiver->metaObject() : nullptr;
3501 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 7);
3502 int method_index = -1;
3503 QByteArrayView methodName;
3504 QArgumentTypeArray methodTypes;
3505 if (method) {
3506 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3507 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3508 if (method_index == -1) {
3509 pinnedMethod = QMetaObject::normalizedSignature(method);
3510 method = pinnedMethod.constData();
3511 methodTypes.clear();
3512 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3513 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3514 }
3515 if (method_index == -1) {
3516 err_method_notfound(receiver, method_arg, "disconnect");
3517 err_info_about_objects("disconnect", sender, receiver);
3518 return false;
3519 }
3520 }
3521
3522 /* We now iterate through all the sender's and receiver's meta
3523 * objects in order to also disconnect possibly shadowed signals
3524 * and slots with the same signature.
3525 */
3526 bool res = false;
3527 do {
3528 if (signal) {
3529 // Already computed the signal_index for `smeta` above
3530 if (smeta != sender->metaObject()) {
3531 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3532 signalTypes);
3533 }
3534 if (signal_index < 0)
3535 break;
3536 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3537 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3538 }
3539
3540 if (!method) {
3541 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1, nullptr);
3542 } else {
3543 do {
3544 // Already computed the method_index for receiver->metaObject() above
3545 if (rmeta != receiver->metaObject())
3546 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3547 if (method_index >= 0) {
3548#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
3549 check_and_warn_non_slot("disconnect", method, membcode, rmeta,
3550 rmeta->method(method_index));
3551#endif
3552 while (method_index < rmeta->methodOffset())
3553 rmeta = rmeta->superClass();
3554 }
3555 if (method_index < 0)
3556 break;
3557 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index, nullptr);
3558 } while ((rmeta = rmeta->superClass()));
3559 }
3560 } while (signal && (smeta = smeta->superClass()));
3561
3562 if (res) {
3563 if (!signal)
3564 const_cast<QObject *>(sender)->disconnectNotify(QMetaMethod());
3565 }
3566 return res;
3567}
3568
3569/*!
3570 \since 4.8
3571
3572 Disconnects \a signal in object \a sender from \a method in object
3573 \a receiver. Returns \c true if the connection is successfully broken;
3574 otherwise returns \c false.
3575
3576 This function provides the same possibilities like
3577 \c {disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method) }
3578 but uses QMetaMethod to represent the signal and the method to be disconnected.
3579
3580 Additionally this function returns false and no signals and slots disconnected
3581 if:
3582 \list 1
3583
3584 \li \a signal is not a member of sender class or one of its parent classes.
3585
3586 \li \a method is not a member of receiver class or one of its parent classes.
3587
3588 \li \a signal instance represents not a signal.
3589
3590 \endlist
3591
3592 \include includes/qobject.qdocinc disconnect-mismatch
3593 \include includes/qobject.qdocinc disconnect-queued
3594
3595 QMetaMethod() may be used as wildcard in the meaning "any signal" or "any slot in receiving object".
3596 In the same way \nullptr can be used for \a receiver in the meaning "any receiving object".
3597 In this case method should also be QMetaMethod(). \a sender parameter should be never \nullptr.
3598
3599 \include includes/qobject.qdocinc disconnect-all
3600
3601 \sa disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
3602 */
3603bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal,
3604 const QObject *receiver, const QMetaMethod &method)
3605{
3606 if (sender == nullptr || (receiver == nullptr && method.mobj != nullptr)) {
3607 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
3608 return false;
3609 }
3610 if (signal.mobj) {
3611 if (signal.methodType() != QMetaMethod::Signal) {
3612 qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s",
3613 "disconnect","unbind",
3614 sender->metaObject()->className(), signal.methodSignature().constData());
3615 return false;
3616 }
3617 }
3618 if (method.mobj) {
3619 if (method.methodType() == QMetaMethod::Constructor) {
3620 qCWarning(lcConnect, "QObject::disconnect: cannot use constructor as argument %s::%s",
3621 receiver->metaObject()->className(), method.methodSignature().constData());
3622 return false;
3623 }
3624 }
3625
3626 int signal_index;
3627 int method_index;
3628 {
3629 int dummy;
3630 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3631 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3632 }
3633 // If we are here sender is not nullptr. If signal is not nullptr while signal_index
3634 // is -1 then this signal is not a member of sender.
3635 if (signal.mobj && signal_index == -1) {
3636 qCWarning(lcConnect, "QObject::disconnect: signal %s not found on class %s",
3637 signal.methodSignature().constData(), sender->metaObject()->className());
3638 return false;
3639 }
3640 // If this condition is true then method is not a member of receiver.
3641 if (receiver && method.mobj && method_index == -1) {
3642 qCWarning(lcConnect, "QObject::disconnect: method %s not found on class %s",
3643 method.methodSignature().constData(), receiver->metaObject()->className());
3644 return false;
3645 }
3646
3647 if (!QMetaObjectPrivate::disconnect(sender, signal_index, signal.mobj, receiver, method_index, nullptr))
3648 return false;
3649
3650 if (!signal.isValid()) {
3651 // The signal is a wildcard, meaning all signals were disconnected.
3652 // QMetaObjectPrivate::disconnect() doesn't call disconnectNotify()
3653 // per connection in this case. Call it once now, with an invalid
3654 // QMetaMethod as argument, as documented.
3655 const_cast<QObject *>(sender)->disconnectNotify(signal);
3656 }
3657 return true;
3658}
3659
3660/*!
3661 \threadsafe
3662
3663 \fn bool QObject::disconnect(const char *signal, const QObject *receiver, const char *method) const
3664 \overload disconnect()
3665
3666 Disconnects \a signal from \a method of \a receiver.
3667
3668 \include includes/qobject.qdocinc disconnect-mismatch
3669 \include includes/qobject.qdocinc disconnect-queued
3670
3671 A signal-slot connection is removed when either of the objects
3672 involved are destroyed.
3673
3674 \include includes/qobject.qdocinc disconnect-all
3675*/
3676
3677/*!
3678 \fn bool QObject::disconnect(const QObject *receiver, const char *method) const
3679 \overload disconnect()
3680
3681 Disconnects all signals in this object from \a receiver's \a
3682 method.
3683
3684 \include includes/qobject.qdocinc disconnect-mismatch
3685 \include includes/qobject.qdocinc disconnect-queued
3686
3687 A signal-slot connection is removed when either of the objects
3688 involved are destroyed.
3689*/
3690
3691
3692/*!
3693 \since 5.0
3694
3695 This virtual function is called when something has been connected
3696 to \a signal in this object.
3697
3698 If you want to compare \a signal with a specific signal, you can
3699 use QMetaMethod::fromSignal() as follows:
3700
3701 \snippet code/src_corelib_kernel_qobject.cpp 32
3702
3703 \warning This function violates the object-oriented principle of
3704 modularity. However, it might be useful when you need to perform
3705 an expensive operation only if something is connected to a signal.
3706
3707 \warning This function is called from the thread which performs the
3708 connection, which may be a different thread from the thread in which
3709 this object lives. This function may also be called with a QObject internal
3710 mutex locked. It is therefore not allowed to re-enter any QObject
3711 functions, including isSignalConnected(), from your reimplementation. If
3712 you lock a mutex in your reimplementation, make sure that you don't call
3713 QObject functions with that mutex held in other places or it will result in
3714 a deadlock.
3715
3716 \sa connect(), disconnectNotify()
3717*/
3718
3719void QObject::connectNotify(const QMetaMethod &signal)
3720{
3721 Q_UNUSED(signal);
3722}
3723
3724/*!
3725 \since 5.0
3726
3727 This virtual function is called when something has been
3728 disconnected from \a signal in this object.
3729
3730 See connectNotify() for an example of how to compare
3731 \a signal with a specific signal.
3732
3733 If all signals were disconnected from this object (e.g., the
3734 signal argument to disconnect() was \nullptr), disconnectNotify()
3735 is only called once, and the \a signal will be an invalid
3736 QMetaMethod (QMetaMethod::isValid() returns \c false).
3737
3738 When a receiver living in another thread is destroyed, this function is
3739 called later, from this object's own thread; if that thread has no running
3740 event loop, it is not called at all. In every other case it is called right
3741 away, from the thread that is disconnecting the signal.
3742
3743 \warning This function violates the object-oriented principle of
3744 modularity. However, it might be useful for optimizing access to
3745 expensive resources.
3746
3747 \warning This function is called from the thread which performs the
3748 disconnection, which may be a different thread from the thread in which
3749 this object lives. This function may also be called with a QObject internal
3750 mutex locked. It is therefore not allowed to re-enter any QObject
3751 functions, including isSignalConnected(), from your reimplementation. If
3752 you lock a mutex in your reimplementation, make sure that you don't call
3753 QObject functions with that mutex held in other places or it will result in
3754 a deadlock.
3755
3756 \sa disconnect(), connectNotify()
3757*/
3758
3759void QObject::disconnectNotify(const QMetaMethod &signal)
3760{
3761 Q_UNUSED(signal);
3762}
3763
3764/*
3765 \internal
3766 convert a signal index from the method range to the signal range
3767 */
3768static int methodIndexToSignalIndex(const QMetaObject **base, int signal_index)
3769{
3770 if (signal_index < 0)
3771 return signal_index;
3772 const QMetaObject *metaObject = *base;
3773 while (metaObject && metaObject->methodOffset() > signal_index)
3774 metaObject = metaObject->superClass();
3775
3776 if (metaObject) {
3777 int signalOffset, methodOffset;
3778 computeOffsets(metaObject, &signalOffset, &methodOffset);
3779 if (signal_index < metaObject->methodCount())
3780 signal_index = QMetaObjectPrivate::originalClone(metaObject, signal_index - methodOffset) + signalOffset;
3781 else
3782 signal_index = signal_index - methodOffset + signalOffset;
3783 *base = metaObject;
3784 }
3785 return signal_index;
3786}
3787
3788/*!
3789 \internal
3790 \a types is a 0-terminated vector of meta types for queued
3791 connections.
3792
3793 if \a signal_index is -1, then we effectively connect *all* signals
3794 from the sender to the receiver's slot
3795 */
3796QMetaObject::Connection QMetaObject::connect(const QObject *sender, int signal_index,
3797 const QObject *receiver, int method_index, int type,
3798 int *types)
3799{
3800 const QMetaObject *smeta = sender->metaObject();
3801 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3802 return Connection(QMetaObjectPrivate::connect(sender, signal_index, smeta,
3803 receiver, method_index,
3804 nullptr, //FIXME, we could speed this connection up by computing the relative index
3805 type, types));
3806}
3807
3808/*!
3809 \internal
3810 Same as the QMetaObject::connect, but \a signal_index must be the result of QObjectPrivate::signalIndex
3811
3812 method_index is relative to the rmeta metaobject, if rmeta is \nullptr, then it is absolute index
3813
3814 the QObjectPrivate::Connection* has a refcount of 2, so it must be passed to a QMetaObject::Connection
3815 */
3816QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender,
3817 int signal_index, const QMetaObject *smeta,
3818 const QObject *receiver, int method_index,
3819 const QMetaObject *rmeta, int type, int *types)
3820{
3821 QObject *s = const_cast<QObject *>(sender);
3822 QObject *r = const_cast<QObject *>(receiver);
3823
3824 int method_offset = rmeta ? rmeta->methodOffset() : 0;
3825 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 6);
3826 QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall : nullptr;
3827
3828 QOrderedMutexLocker locker(signalSlotLock(sender),
3829 signalSlotLock(receiver));
3830
3831 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3832 if (type & Qt::UniqueConnection && scd) {
3833 if (scd->signalVectorCount() > signal_index) {
3834 const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
3835
3836 int method_index_absolute = method_index + method_offset;
3837
3838 while (c2) {
3839 if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute)
3840 return nullptr;
3841 c2 = c2->nextConnectionList.loadRelaxed();
3842 }
3843 }
3844 }
3845 type &= ~Qt::UniqueConnection;
3846
3847 const bool isSingleShot = type & Qt::SingleShotConnection;
3848 type &= ~Qt::SingleShotConnection;
3849
3850 Q_ASSERT(type >= 0);
3851 Q_ASSERT(type <= 3);
3852
3853 std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
3854 c->sender = s;
3855 c->signal_index = signal_index;
3856 c->receiver.storeRelaxed(r);
3857 QThreadData *td = r->d_func()->threadData.loadAcquire();
3858 td->ref();
3859 c->receiverThreadData.storeRelaxed(td);
3860 c->method_relative = method_index;
3861 c->method_offset = method_offset;
3862 c->connectionType = type;
3863 c->isSlotObject = false;
3864 c->argumentTypes.storeRelaxed(types);
3865 c->callFunction = callFunction;
3866 c->isSingleShot = isSingleShot;
3867
3868 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
3869
3870 locker.unlock();
3871 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3872 if (smethod.isValid())
3873 s->connectNotify(smethod);
3874
3875 return c.release();
3876}
3877
3878/*!
3879 \internal
3880 */
3881bool QMetaObject::disconnect(const QObject *sender, int signal_index,
3882 const QObject *receiver, int method_index)
3883{
3884 const QMetaObject *smeta = sender->metaObject();
3885 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3886 return QMetaObjectPrivate::disconnect(sender, signal_index, smeta,
3887 receiver, method_index, nullptr);
3888}
3889
3890/*!
3891 \internal
3892
3893Disconnect a single signal connection. If QMetaObject::connect() has been called
3894multiple times for the same sender, signal_index, receiver and method_index only
3895one of these connections will be removed.
3896 */
3897bool QMetaObject::disconnectOne(const QObject *sender, int signal_index,
3898 const QObject *receiver, int method_index)
3899{
3900 const QMetaObject *smeta = sender->metaObject();
3901 signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3902 return QMetaObjectPrivate::disconnect(sender, signal_index, smeta,
3903 receiver, method_index, nullptr,
3904 QMetaObjectPrivate::DisconnectOne);
3905}
3906
3907/*!
3908 \internal
3909 Helper function to remove the connection from the senders list and set the receivers to \nullptr
3910 */
3911bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::ConnectionData *connections, int signalIndex,
3912 const QObject *receiver, int method_index, void **slot,
3913 QBasicMutex *senderMutex, DisconnectType disconnectType)
3914{
3915 bool success = false;
3916
3917 auto &connectionList = connections->connectionsForSignal(signalIndex);
3918 auto *c = connectionList.first.loadRelaxed();
3919 while (c) {
3920 QObject *r = c->receiver.loadRelaxed();
3921 if (r && (receiver == nullptr || (r == receiver
3922 && (method_index < 0 || (!c->isSlotObject && c->method() == method_index))
3923 && (slot == nullptr || (c->isSlotObject && c->slotObj->compare(slot)))))) {
3924 bool needToUnlock = false;
3925 QBasicMutex *receiverMutex = nullptr;
3926 if (r) {
3927 receiverMutex = signalSlotLock(r);
3928 // need to relock this receiver and sender in the correct order
3929 needToUnlock = QOrderedMutexLocker::relock(senderMutex, receiverMutex);
3930 }
3931 if (c->receiver.loadRelaxed())
3932 connections->removeConnection(c);
3933
3934 if (needToUnlock)
3935 receiverMutex->unlock();
3936
3937 success = true;
3938
3939 if (disconnectType == DisconnectOne)
3940 return success;
3941 }
3942 c = c->nextConnectionList.loadRelaxed();
3943 }
3944 return success;
3945}
3946
3947/*!
3948 \internal
3949 Same as the QMetaObject::disconnect, but \a signal_index must be the result of QObjectPrivate::signalIndex
3950 */
3951bool QMetaObjectPrivate::disconnect(const QObject *sender,
3952 int signal_index, const QMetaObject *smeta,
3953 const QObject *receiver, int method_index, void **slot,
3954 DisconnectType disconnectType)
3955{
3956 if (!sender)
3957 return false;
3958
3959 QObject *s = const_cast<QObject *>(sender);
3960
3961 QBasicMutex *senderMutex = signalSlotLock(sender);
3962 QMutexLocker locker(senderMutex);
3963
3964 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3965 if (!scd)
3966 return false;
3967
3968 // Capture the message arguments now and emit the warning after unlocking:
3969 // qWarning() may re-enter connect/disconnect from the message handler and
3970 // deadlock on the lock held here (QTBUG-145216).
3971 struct WildcardDestroyedWarning
3972 {
3973 QByteArray className;
3974 QByteArray objectName;
3975 };
3976 std::optional<WildcardDestroyedWarning> wildcardDestroyedWarning;
3977
3978 bool success = false;
3979 {
3980 // prevent incoming connections changing the connections->receivers while unlocked
3981 QObjectPrivate::ConnectionDataPointer connections(scd);
3982
3983 if (signal_index < 0) {
3984 // wildcard disconnect - warn if this disconnects destroyed()
3985 if (!receiver && method_index < 0 && sender->d_func()->isSignalConnected(0)) {
3986 wildcardDestroyedWarning = WildcardDestroyedWarning{
3987 sender->metaObject()->className(),
3988 sender->objectName().toLocal8Bit()
3989 };
3990 }
3991 // remove from all connection lists
3992 for (int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
3993 if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
3994 success = true;
3995 }
3996 } else if (signal_index < scd->signalVectorCount()) {
3997 if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
3998 success = true;
3999 }
4000 }
4001
4002 locker.unlock();
4003
4004 if (wildcardDestroyedWarning) {
4005 qWarning("QObject::disconnect: wildcard call disconnects from destroyed signal of %s::%s",
4006 wildcardDestroyedWarning->className.constData(),
4007 wildcardDestroyedWarning->objectName.isEmpty()
4008 ? "unnamed"
4009 : wildcardDestroyedWarning->objectName.constData());
4010 }
4011
4012 if (success) {
4013 scd->cleanOrphanedConnections(s);
4014
4015 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
4016 if (smethod.isValid())
4017 s->disconnectNotify(smethod);
4018 }
4019
4020 return success;
4021}
4022
4023// Helpers for formatting the connect statements of connectSlotsByName()'s debug mode
4024static QByteArray formatConnectionSignature(const char *className, const QMetaMethod &method)
4025{
4026 const auto signature = method.methodSignature();
4027 Q_ASSERT(signature.endsWith(')'));
4028 const qsizetype openParen = signature.indexOf('(');
4029 const bool hasParameters = openParen > 0 && openParen < signature.size() - 2;
4030 QByteArray result;
4031 if (hasParameters) {
4032 const qsizetype len = signature.size() - openParen - 2;
4033 result += "qOverload<" + QByteArrayView{signature}.slice(openParen + 1, len) + ">(";
4034 }
4035 result += '&';
4036 result += className + QByteArrayLiteral("::") + method.name();
4037 if (hasParameters)
4038 result += ')';
4039 return result;
4040}
4041
4042static QByteArray msgConnect(const QMetaObject *senderMo, const QByteArray &senderName,
4043 const QMetaMethod &signal, const QObject *receiver, int receiverIndex)
4044{
4045 const auto receiverMo = receiver->metaObject();
4046 const auto slot = receiverMo->method(receiverIndex);
4047 QByteArray message = QByteArrayLiteral("QObject::connect(")
4048 + senderName + ", " + formatConnectionSignature(senderMo->className(), signal)
4049 + ", " + receiver->objectName().toLatin1() + ", "
4050 + formatConnectionSignature(receiverMo->className(), slot) + ");";
4051 return message;
4052}
4053
4054/*!
4055 \fn void QMetaObject::connectSlotsByName(QObject *object)
4056
4057 Searches recursively for all child objects of the given \a object, and connects
4058 matching signals from them to slots of \a object that follow the following form:
4059
4060 \snippet code/src_corelib_kernel_qobject.cpp 33
4061
4062 Let's assume our object has a child object of type \c{QPushButton} with
4063 the \l{QObject::objectName}{object name} \c{button1}. The slot to catch the
4064 button's \c{clicked()} signal would be:
4065
4066 \snippet code/src_corelib_kernel_qobject.cpp 34
4067
4068 If \a object itself has a properly set object name, its own signals are also
4069 connected to its respective slots.
4070
4071 \sa QObject::setObjectName()
4072 */
4073void QMetaObject::connectSlotsByName(QObject *o)
4074{
4075 if (!o)
4076 return;
4077 const QMetaObject *mo = o->metaObject();
4078 Q_ASSERT(mo);
4079 const QObjectList list = // list of all objects to look for matching signals including...
4080 o->findChildren<QObject *>() // all children of 'o'...
4081 << o; // and the object 'o' itself
4082
4083 // for each method/slot of o ...
4084 for (int i = 0; i < mo->methodCount(); ++i) {
4085 const QByteArray slotSignature = mo->method(i).methodSignature();
4086 const char *slot = slotSignature.constData();
4087 Q_ASSERT(slot);
4088
4089 // ...that starts with "on_", ...
4090 if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
4091 continue;
4092
4093 // ...we check each object in our list, ...
4094 bool foundIt = false;
4095 for (int j = 0; j < list.size(); ++j) {
4096 const QObject *co = list.at(j);
4097 const QByteArray coName = co->objectName().toLatin1();
4098
4099 // ...discarding those whose objectName is not fitting the pattern "on_<objectName>_...", ...
4100 if (coName.isEmpty() || qstrncmp(slot + 3, coName.constData(), coName.size()) || slot[coName.size()+3] != '_')
4101 continue;
4102
4103 const char *signal = slot + coName.size() + 4; // the 'signal' part of the slot name
4104
4105 // ...for the presence of a matching signal "on_<objectName>_<signal>".
4106 const QMetaObject *smeta;
4107 int sigIndex = co->d_func()->signalIndex(signal, &smeta);
4108 if (sigIndex < 0) {
4109 // if no exactly fitting signal (name + complete parameter type list) could be found
4110 // look for just any signal with the correct name and at least the slot's parameter list.
4111 // Note: if more than one of those signals exist, the one that gets connected is
4112 // chosen 'at random' (order of declaration in source file)
4113 QList<QByteArray> compatibleSignals;
4114 const QMetaObject *smo = co->metaObject();
4115 int sigLen = int(qstrlen(signal)) - 1; // ignore the trailing ')'
4116 for (int k = QMetaObjectPrivate::absoluteSignalCount(smo)-1; k >= 0; --k) {
4117 const QMetaMethod method = QMetaObjectPrivate::signal(smo, k);
4118 if (!qstrncmp(method.methodSignature().constData(), signal, sigLen)) {
4119 smeta = method.enclosingMetaObject();
4120 sigIndex = k;
4121 compatibleSignals.prepend(method.methodSignature());
4122 }
4123 }
4124 if (compatibleSignals.size() > 1)
4125 qCWarning(lcConnectSlotsByName) << "QMetaObject::connectSlotsByName: Connecting slot" << slot
4126 << "with the first of the following compatible signals:" << compatibleSignals;
4127 }
4128
4129 if (sigIndex < 0)
4130 continue;
4131
4132 // we connect it...
4133 if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) {
4134 foundIt = true;
4135 qCDebug(lcConnectSlotsByName, "%s",
4136 msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData());
4137 // ...and stop looking for further objects with the same name.
4138 // Note: the Designer will make sure each object name is unique in the above
4139 // 'list' but other code may create two child objects with the same name. In
4140 // this case one is chosen 'at random'.
4141 break;
4142 }
4143 }
4144 if (foundIt) {
4145 // we found our slot, now skip all overloads
4146 while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
4147 ++i;
4148 } else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
4149 // check if the slot has the following signature: "on_..._...(..."
4150 qsizetype iParen = slotSignature.indexOf('(');
4151 qsizetype iLastUnderscore = slotSignature.lastIndexOf('_', iParen - 1);
4152 if (iLastUnderscore > 3)
4153 qCWarning(lcConnectSlotsByName,
4154 "QMetaObject::connectSlotsByName: No matching signal for %s", slot);
4155 }
4156 }
4157}
4158
4159/*!
4160 \fn template<typename PointerToMemberFunction> QMetaObject::Connection QMetaObject::connect(
4161 const QObject *sender, const QMetaMethod &signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type)
4162
4163 \threadsafe
4164 \overload connect()
4165
4166 \since 6.10
4167
4168 Creates a connection of the given \a type from the \a signal in
4169 the \a sender object to the \a method in the \a receiver object.
4170 Returns a handle to the connection that can be used to disconnect
4171 it later.
4172
4173 The Connection handle will be invalid if it cannot create the
4174 connection, for example, the parameters were invalid.
4175 You can check if the QMetaObject::Connection is valid by casting
4176 it to a bool.
4177 Pass the returned handle to QObject::disconnect() to disconnect
4178 the connection.
4179
4180 A slot can be connected to a given signal if the signal has at
4181 least as many arguments as the slot. There must be an exact match
4182 between the corresponding signal and slot arguments, implicit
4183 conversions and type checking are not handled by this function.
4184 Overloaded slots need to be explicitly be resolved with
4185 help of \l qOverload.
4186 \a signal needs to be the meta-method of a signal, otherwise an
4187 invalid connection will be returned.
4188
4189 \sa QObject::connect(), QObject::disconnect()
4190 */
4191
4192/*!
4193 \fn template<typename Functor> QMetaObject::Connection QMetaObject::connect(
4194 const QObject *sender, const QMetaMethod &signal, const QObject *context, Functor functor, Qt::ConnectionType type)
4195
4196 \threadsafe
4197 \overload connect()
4198
4199 \since 6.10
4200
4201 Creates a connection of a given \a type from \a signal in
4202 \a sender object to \a functor to be placed in a specific event
4203 loop of \a context.
4204 Returns a handle to the connection that can be used to disconnect
4205 it later.
4206 This can be useful for connecting a signal retrieved from
4207 meta-object introspection to a lambda capturing local variables.
4208
4209 \note Qt::UniqueConnections do not work for lambdas, non-member
4210 functions and functors; they only apply to member functions.
4211
4212 The slot function can be any function or functor with with equal
4213 or fewer arguments than the signal. There must be an exact match
4214 between the corresponding signal and slot arguments, implicit
4215 conversions and type checking are not handled by this function.
4216 Overloaded functors need to be explicitly be resolved with
4217 help of \l qOverload.
4218 \a signal needs to be the meta-method of a signal, otherwise an
4219 invalid connection will be returned.
4220
4221 The connection will automatically disconnect if the sender or
4222 the context is destroyed.
4223 However, you should take care that any objects used within
4224 the functor are still alive when the signal is emitted.
4225
4226 \sa QObject::connect(), QObject::disconnect()
4227 */
4228QMetaObject::Connection QMetaObject::connectImpl(const QObject *sender, const QMetaMethod &signal,
4229 const QObject *receiver, void **slot,
4230 QtPrivate::QSlotObjectBase *slotObjRaw, Qt::ConnectionType type)
4231{
4232 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
4233 Q_ASSERT_X(slotObjRaw, "QMetaObject::connect", "Internal error, caller must not pass null slotObj");
4234
4235 const QMetaObject *senderMetaObject = sender->metaObject();
4236 if (!signal.isValid() || signal.methodType() != QMetaMethod::Signal) {
4237 connectWarning(sender, senderMetaObject, receiver, "invalid signal parameter");
4238 return QMetaObject::Connection();
4239 }
4240
4241 int signal_index;
4242 {
4243 int dummy;
4244 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
4245 }
4246
4247 if (signal_index == -1) {
4248 qCWarning(lcConnect, "QObject::connect: Can't find signal %s on instance of class %s",
4249 signal.methodSignature().constData(), senderMetaObject->className());
4250 return QMetaObject::Connection();
4251 }
4252
4253 return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj.release(), type, nullptr, senderMetaObject);
4254}
4255
4256/*!
4257 \internal
4258 A small RAII helper for QSlotObjectBase.
4259 Calls ref on construction and destroyLastRef in its dtor.
4260 Allows construction from a nullptr in which case it does nothing.
4261 */
4263 SlotObjectGuard() = default;
4264 // move would be fine, but we do not need it currently
4272
4274 { return m_slotObject.get(); }
4275
4278
4279 ~SlotObjectGuard() = default;
4280private:
4281 QtPrivate::SlotObjUniquePtr m_slotObject;
4282};
4283
4284/*!
4285 \internal
4286
4287 \a signal must be in the signal index range (see QObjectPrivate::signalIndex()).
4288*/
4289static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv)
4290{
4291 const int *argumentTypes = c->argumentTypes.loadRelaxed();
4292 if (!argumentTypes) {
4293 QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
4294 argumentTypes = queuedConnectionTypes(m);
4295 if (!argumentTypes) // cannot queue arguments
4296 argumentTypes = &DIRECT_CONNECTION_ONLY;
4297 if (!c->argumentTypes.testAndSetOrdered(nullptr, argumentTypes)) {
4298 if (argumentTypes != &DIRECT_CONNECTION_ONLY)
4299 delete[] argumentTypes;
4300 argumentTypes = c->argumentTypes.loadRelaxed();
4301 }
4302 }
4303 if (argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate
4304 return;
4305 int nargs = 1; // include return type
4306 while (argumentTypes[nargs - 1])
4307 ++nargs;
4308
4309 QMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
4310 QObject *receiver = c->receiver.loadRelaxed();
4311 if (!receiver) {
4312 // the connection has been disconnected before we got the lock
4313 return;
4314 }
4315
4316 SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj : nullptr };
4317 locker.unlock();
4318
4319 QVarLengthArray<const QtPrivate::QMetaTypeInterface *, 16> argTypes;
4320 argTypes.reserve(nargs);
4321 argTypes.emplace_back(nullptr); // return type
4322 for (int n = 1; n < nargs; ++n) {
4323 argTypes.emplace_back(QMetaType(argumentTypes[n - 1]).iface()); // convert type ids to QMetaTypeInterfaces
4324 }
4325
4326 auto ev = c->isSlotObject ?
4327 std::make_unique<QQueuedMetaCallEvent>(c->slotObj,
4328 sender, signal, nargs, argTypes.data(), argv) :
4329 std::make_unique<QQueuedMetaCallEvent>(c->method_offset, c->method_relative, c->callFunction,
4330 sender, signal, nargs, argTypes.data(), argv);
4331
4332 if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) {
4333 return;
4334 }
4335
4336 locker.relock();
4337 if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
4338 // the connection has been disconnected while we were unlocked
4339 locker.unlock();
4340 return;
4341 }
4342
4343 QCoreApplication::postEvent(receiver, ev.release());
4344}
4345
4346template <bool callbacks_enabled>
4347void doActivate(QObject *sender, int signal_index, void **argv)
4348{
4349 QObjectPrivate *sp = QObjectPrivate::get(sender);
4350
4351 if (sp->blockSig)
4352 return;
4353
4354 Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
4355
4356 if (sp->isDeclarativeSignalConnected(signal_index)
4357 && QAbstractDeclarativeData::signalEmitted) {
4358 Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
4359 QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
4360 signal_index, argv);
4361 }
4362
4363 const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() : nullptr;
4364
4365 void *empty_argv[] = { nullptr };
4366 if (!argv)
4367 argv = empty_argv;
4368
4369 bool senderDeleted = false;
4370 {
4371 QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadAcquire());
4372 if (!connections || !sp->maybeSignalConnected(signal_index)) {
4373 // The possible declarative connection is done, and nothing else is connected
4374 if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
4375 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4376 if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
4377 signal_spy_set->signal_end_callback(sender, signal_index);
4378 return;
4379 }
4380
4381 if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
4382 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4383
4384 // loadAcquire pairs with the storeRelease in resizeSignalVector(), ensuring
4385 // that all writes to the new SignalVector's contents are visible here.
4386 QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadAcquire();
4387
4388 const QObjectPrivate::ConnectionList *list;
4389 if (signal_index < signalVector->count())
4390 list = &signalVector->at(signal_index);
4391 else
4392 list = &signalVector->at(-1);
4393
4394 Qt::HANDLE currentThreadId = QThread::currentThreadId();
4395 bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
4396
4397 // We need to check against the highest connection id to ensure that signals added
4398 // during the signal emission are not emitted in this emission.
4399 uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
4400 do {
4401 QObjectPrivate::Connection *c = list->first.loadAcquire();
4402 if (!c)
4403 continue;
4404
4405 do {
4406 QObject * const receiver = c->receiver.loadRelaxed();
4407 if (!receiver)
4408 continue;
4409
4410 QThreadData *td = c->receiverThreadData.loadRelaxed();
4411 if (!td)
4412 continue;
4413
4414 bool receiverInSameThread;
4415 if (inSenderThread) {
4416 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4417 } else {
4418 // need to lock before reading the threadId, because moveToThread() could interfere
4419 QMutexLocker lock(signalSlotLock(receiver));
4420 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4421 }
4422
4423
4424 // determine if this connection should be sent immediately or
4425 // put into the event queue
4426 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
4427 || (c->connectionType == Qt::QueuedConnection)) {
4428 queued_activate(sender, signal_index, c, argv);
4429 continue;
4430#if QT_CONFIG(thread)
4431 } else if (c->connectionType == Qt::BlockingQueuedConnection) {
4432 if (receiverInSameThread) {
4433 qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
4434 "Sender is %s(%p), receiver is %s(%p)",
4435 sender->metaObject()->className(), sender,
4436 receiver->metaObject()->className(), receiver);
4437 }
4438
4439 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4440 continue;
4441
4442 QLatch latch(1);
4443 {
4444 QMutexLocker locker(signalSlotLock(receiver));
4445 if (!c->isSingleShot && !c->receiver.loadAcquire())
4446 continue;
4447 QMetaCallEvent *ev = c->isSlotObject ?
4448 new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &latch) :
4449 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
4450 sender, signal_index, argv, &latch);
4451 QCoreApplication::postEvent(receiver, ev);
4452 }
4453 latch.wait();
4454 continue;
4455#endif
4456 }
4457
4458 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4459 continue;
4460
4461 QObjectPrivate::Sender senderData(
4462 receiverInSameThread ? receiver : nullptr, sender, signal_index,
4463 receiverInSameThread ? QObjectPrivate::get(receiver)->connections.loadAcquire() : nullptr);
4464
4465 if (c->isSlotObject) {
4466 SlotObjectGuard obj{c->slotObj};
4467
4468 {
4469 Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
4470 obj->call(receiver, argv);
4471 }
4472 } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
4473 //we compare the vtable to make sure we are not in the destructor of the object.
4474 const int method_relative = c->method_relative;
4475 const auto callFunction = c->callFunction;
4476 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
4477 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)
4478 signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
4479
4480 {
4481 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
4482 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
4483 }
4484
4485 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
4486 signal_spy_set->slot_end_callback(receiver, methodIndex);
4487 } else {
4488 const int method = c->method_relative + c->method_offset;
4489
4490 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {
4491 signal_spy_set->slot_begin_callback(receiver, method, argv);
4492 }
4493
4494 {
4495 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
4496 QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
4497 }
4498
4499 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
4500 signal_spy_set->slot_end_callback(receiver, method);
4501 }
4502 } while ((c = c->nextConnectionList.loadAcquire()) != nullptr && c->id.loadAcquire() <= highestConnectionId);
4503
4504 } while (list != &signalVector->at(-1) &&
4505 //start over for all signals;
4506 ((list = &signalVector->at(-1)), true));
4507
4508 if (connections->currentConnectionId.loadRelaxed() == 0)
4509 senderDeleted = true;
4510 }
4511
4512 if (!senderDeleted) {
4513 sp->connections.loadAcquire()->cleanOrphanedConnections(sender);
4514
4515 if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
4516 signal_spy_set->signal_end_callback(sender, signal_index);
4517 }
4518}
4519
4520/*!
4521 \internal
4522 */
4523void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
4524 void **argv)
4525{
4526 int signal_index = local_signal_index + QMetaObjectPrivate::signalOffset(m);
4527
4528 if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
4529 doActivate<true>(sender, signal_index, argv);
4530 else
4531 doActivate<false>(sender, signal_index, argv);
4532}
4533
4534/*!
4535 \internal
4536 */
4537void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
4538{
4539 int signal_index = signalOffset + local_signal_index;
4540
4541 if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
4542 doActivate<true>(sender, signal_index, argv);
4543 else
4544 doActivate<false>(sender, signal_index, argv);
4545}
4546
4547/*!
4548 \internal
4549 signal_index comes from indexOfMethod()
4550*/
4551void QMetaObject::activate(QObject *sender, int signal_index, void **argv)
4552{
4553 const QMetaObject *mo = sender->metaObject();
4554 while (mo->methodOffset() > signal_index)
4555 mo = mo->superClass();
4556 activate(sender, mo, signal_index - mo->methodOffset(), argv);
4557}
4558
4559/*!
4560 \internal
4561 Returns the signal index used in the internal connections->receivers vector.
4562
4563 It is different from QMetaObject::indexOfSignal(): indexOfSignal is the same as indexOfMethod
4564 while QObjectPrivate::signalIndex is smaller because it doesn't give index to slots.
4565
4566 If \a meta is not \nullptr, it is set to the meta-object where the signal was found.
4567*/
4568int QObjectPrivate::signalIndex(const char *signalName,
4569 const QMetaObject **meta) const
4570{
4571 Q_Q(const QObject);
4572 const QMetaObject *base = q->metaObject();
4573 Q_ASSERT(QMetaObjectPrivate::get(base)->revision >= 7);
4574 QArgumentTypeArray types;
4575 QByteArrayView name = QMetaObjectPrivate::decodeMethodSignature(signalName, types);
4576 int relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, name, types);
4577 if (relative_index < 0)
4578 return relative_index;
4579 relative_index = QMetaObjectPrivate::originalClone(base, relative_index);
4580 if (meta)
4581 *meta = base;
4582 return relative_index + QMetaObjectPrivate::signalOffset(base);
4583}
4584
4585/*****************************************************************************
4586 Properties
4587 *****************************************************************************/
4588
4589/*!
4590 \fn bool QObject::setProperty(const char *name, const QVariant &value)
4591
4592 Sets the value of the object's \a name property to \a value.
4593
4594 If the property is defined in the class using Q_PROPERTY then
4595 true is returned on success and false otherwise. If the property
4596 is not defined using Q_PROPERTY, and therefore not listed in the
4597 meta-object, it is added as a dynamic property and false is returned.
4598
4599 Information about all available properties is provided through the
4600 metaObject() and dynamicPropertyNames().
4601
4602 Dynamic properties can be queried again using property() and can be
4603 removed by setting the property value to an invalid QVariant.
4604 Changing the value of a dynamic property causes a QDynamicPropertyChangeEvent
4605 to be sent to the object.
4606
4607 \b{Note:} Dynamic properties starting with "_q_" are reserved for internal
4608 purposes.
4609
4610 \sa property(), metaObject(), dynamicPropertyNames(), QMetaProperty::write()
4611*/
4612
4613/*!
4614 \fn bool QObject::setProperty(const char *name, QVariant &&value)
4615 \since 6.6
4616 \overload setProperty
4617*/
4618
4619bool QObject::doSetProperty(const char *name, const QVariant &value, QVariant *rvalue)
4620{
4621 Q_D(QObject);
4622 const QMetaObject *meta = metaObject();
4623 if (!name || !meta)
4624 return false;
4625
4626 int id = meta->indexOfProperty(name);
4627 if (id < 0) {
4628 d->ensureExtraData();
4629
4630 const qsizetype idx = d->extraData->propertyNames.indexOf(name);
4631
4632 if (!value.isValid()) {
4633 if (idx == -1)
4634 return false;
4635 d->extraData->propertyNames.removeAt(idx);
4636 d->extraData->propertyValues.removeAt(idx);
4637 } else {
4638 if (idx == -1) {
4639 d->extraData->propertyNames.append(name);
4640 q_choose_append(d->extraData->propertyValues, value, rvalue);
4641 } else {
4642 if (value.userType() == d->extraData->propertyValues.at(idx).userType()
4643 && value == d->extraData->propertyValues.at(idx))
4644 return false;
4645 q_choose_assign(d->extraData->propertyValues[idx], value, rvalue);
4646 }
4647 }
4648
4649 QDynamicPropertyChangeEvent ev(name);
4650 QCoreApplication::sendEvent(this, &ev);
4651
4652 return false;
4653 }
4654 QMetaProperty p = meta->property(id);
4655#ifndef QT_NO_DEBUG
4656 if (!p.isWritable())
4657 qWarning("%s::setProperty: Property \"%s\" invalid,"
4658 " read-only or does not exist", metaObject()->className(), name);
4659#endif
4660 return rvalue ? p.write(this, std::move(*rvalue)) : p.write(this, value);
4661}
4662
4663/*!
4664 Returns the value of the object's \a name property.
4665
4666 If no such property exists, the returned variant is invalid.
4667
4668 Information about all available properties is provided through the
4669 metaObject() and dynamicPropertyNames().
4670
4671 \sa setProperty(), QVariant::isValid(), metaObject(), dynamicPropertyNames()
4672*/
4673QVariant QObject::property(const char *name) const
4674{
4675 Q_D(const QObject);
4676 const QMetaObject *meta = metaObject();
4677 if (!name || !meta)
4678 return QVariant();
4679
4680 int id = meta->indexOfProperty(name);
4681 if (id < 0) {
4682 if (!d->extraData)
4683 return QVariant();
4684 const qsizetype i = d->extraData->propertyNames.indexOf(name);
4685 return d->extraData->propertyValues.value(i);
4686 }
4687 QMetaProperty p = meta->property(id);
4688#ifndef QT_NO_DEBUG
4689 if (!p.isReadable())
4690 qWarning("%s::property: Property \"%s\" invalid or does not exist",
4691 metaObject()->className(), name);
4692#endif
4693 return p.read(this);
4694}
4695
4696/*!
4697 \since 4.2
4698
4699 Returns the names of all properties that were dynamically added to
4700 the object using setProperty().
4701*/
4702QList<QByteArray> QObject::dynamicPropertyNames() const
4703{
4704 Q_D(const QObject);
4705 if (d->extraData)
4706 return d->extraData->propertyNames;
4707 return QList<QByteArray>();
4708}
4709
4710/*****************************************************************************
4711 QObject debugging output routines.
4712 *****************************************************************************/
4713
4714std::string QObjectPrivate::flagsForDumping() const
4715{
4716 return {};
4717}
4718
4719static void dumpRecursive(int level, const QObject *object)
4720{
4721 if (object) {
4722 const int indent = level * 4;
4723 qDebug("%*s%s::%ls %s", indent, "", object->metaObject()->className(),
4724 qUtf16Printable(object->objectName()),
4725 QObjectPrivate::get(object)->flagsForDumping().c_str());
4726 for (auto child : object->children())
4727 dumpRecursive(level + 1, child);
4728 }
4729}
4730
4731
4732/*!
4733 Dumps a tree of children to the debug output.
4734
4735 \note Before Qt 5.9, this function was not const.
4736
4737 \sa dumpObjectInfo()
4738*/
4739
4740void QObject::dumpObjectTree() const
4741{
4742 dumpRecursive(0, this);
4743}
4744
4745/*!
4746 Dumps information about signal connections, etc. for this object
4747 to the debug output.
4748
4749 \note Before Qt 5.9, this function was not const.
4750
4751 \sa dumpObjectTree()
4752*/
4753
4754void QObject::dumpObjectInfo() const
4755{
4756 qDebug("OBJECT %s::%s", metaObject()->className(),
4757 objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
4758
4759 Q_D(const QObject);
4760 QMutexLocker locker(signalSlotLock(this));
4761
4762 // first, look for connections where this object is the sender
4763 qDebug(" SIGNALS OUT");
4764
4765 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
4766 if (cd && cd->signalVectorCount() > 0) {
4767 QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
4768 for (int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
4769 const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
4770 if (!c)
4771 continue;
4772 const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index);
4773 qDebug(" signal: %s", signal.methodSignature().constData());
4774
4775 // receivers
4776 while (c) {
4777 if (!c->receiver.loadRelaxed()) {
4778 qDebug(" <Disconnected receiver>");
4779 c = c->nextConnectionList.loadRelaxed();
4780 continue;
4781 }
4782 if (c->isSlotObject) {
4783 qDebug(" <functor or function pointer>");
4784 c = c->nextConnectionList.loadRelaxed();
4785 continue;
4786 }
4787 const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
4788 const QMetaMethod method = receiverMetaObject->method(c->method());
4789 qDebug(" --> %s::%s %s",
4790 receiverMetaObject->className(),
4791 c->receiver.loadRelaxed()->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
4792 method.methodSignature().constData());
4793 c = c->nextConnectionList.loadRelaxed();
4794 }
4795 }
4796 } else {
4797 qDebug( " <None>" );
4798 }
4799
4800 // now look for connections where this object is the receiver
4801 qDebug(" SIGNALS IN");
4802
4803 if (cd && cd->senders) {
4804 for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
4805 QByteArray slotName = QByteArrayLiteral("<unknown>");
4806 if (!s->isSlotObject) {
4807 const QMetaMethod slot = metaObject()->method(s->method());
4808 slotName = slot.methodSignature();
4809 }
4810 qDebug(" <-- %s::%s %s",
4811 s->sender->metaObject()->className(),
4812 s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()),
4813 slotName.constData());
4814 }
4815 } else {
4816 qDebug(" <None>");
4817 }
4818}
4819
4820
4821#ifndef QT_NO_DEBUG_STREAM
4822void QObjectPrivate::writeToDebugStream(QDebug &dbg) const
4823{
4824 Q_Q(const QObject);
4825 dbg.nospace() << q->metaObject()->className() << '(' << (const void *)q;
4826 if (!q->objectName().isEmpty())
4827 dbg << ", name = " << q->objectName();
4828 dbg << ')';
4829}
4830
4831QDebug operator<<(QDebug dbg, const QObject *o)
4832{
4833 QDebugStateSaver saver(dbg);
4834 if (!o)
4835 return dbg << "QObject(0x0)";
4836
4837 const QObjectPrivate *d = QObjectPrivate::get(o);
4838 d->writeToDebugStream(dbg);
4839 return dbg;
4840}
4841#endif
4842
4843/*!
4844 \macro Q_CLASSINFO(Name, Value)
4845 \relates QObject
4846
4847 This macro associates extra information to the class, which is available
4848 using QObject::metaObject(). The extra information takes the form of a
4849 \a Name string and a \a Value literal string.
4850
4851 Example:
4852
4853 \snippet code/src_corelib_kernel_qobject.cpp 35
4854
4855 Qt makes use of the macro in \l{Qt D-Bus} and \l{Qt Qml} modules.
4856 For instance, when defining \l{QML Object Types} in C++, you can
4857 designate a property as the \e default one:
4858
4859 \snippet code/doc_src_properties.cpp 7
4860
4861 \sa QMetaObject::classInfo()
4862 \sa {Using Qt D-Bus Adaptors}
4863 \sa {Defining QML Types from C++}
4864*/
4865
4866/*!
4867 \macro Q_INTERFACES(...)
4868 \relates QObject
4869
4870 This macro tells Qt which interfaces the class implements. This
4871 is used when implementing plugins.
4872
4873 \sa Q_DECLARE_INTERFACE(), Q_PLUGIN_METADATA(), {How to Create Qt Plugins}
4874*/
4875
4876/*!
4877 \macro Q_PROPERTY(...)
4878 \relates QObject
4879
4880 This macro is used for declaring properties in classes that
4881 inherit QObject. Properties behave like class data members, but
4882 they have additional features accessible through the \l
4883 {Meta-Object System}.
4884
4885 \snippet code/doc_src_properties.cpp 0
4886
4887 The property name and type and the \c READ function are required.
4888 The type can be any type supported by QVariant, or it can be a
4889 user-defined type. The other items are optional, but a \c WRITE
4890 function is common. The attributes default to true except \c USER,
4891 which defaults to false.
4892
4893 For example:
4894
4895 \snippet code/src_corelib_kernel_qobject.cpp 37
4896
4897 For more details about how to use this macro, and a more detailed
4898 example of its use, see the discussion on \l {Qt's Property System}.
4899
4900 \sa {Qt's Property System}
4901*/
4902
4903/*!
4904 \macro Q_ENUMS(...)
4905 \relates QObject
4906 \deprecated [5.5]
4907
4908 In new code, you should prefer the use of the Q_ENUM() macro, which makes the
4909 type available also to the meta type system.
4910 For instance, QMetaEnum::fromType() will not work with types declared with Q_ENUMS().
4911
4912 This macro registers one or several enum types to the meta-object
4913 system.
4914
4915 If you want to register an enum that is declared in another class,
4916 the enum must be fully qualified with the name of the class
4917 defining it. In addition, the class \e defining the enum has to
4918 inherit QObject as well as declare the enum using Q_ENUMS().
4919
4920 \sa {Qt's Property System}
4921*/
4922
4923/*!
4924 \macro Q_FLAGS(...)
4925 \relates QObject
4926 \deprecated [5.5]
4927
4928 This macro registers one or several \l{QFlags}{flags types} with the
4929 meta-object system. It is typically used in a class definition to declare
4930 that values of a given enum can be used as flags and combined using the
4931 bitwise OR operator.
4932
4933 \note This macro takes care of registering individual flag values
4934 with the meta-object system, so it is unnecessary to use Q_ENUMS()
4935 in addition to this macro.
4936
4937 In new code, you should prefer the use of the Q_FLAG() macro, which makes the
4938 type available also to the meta type system.
4939
4940 \sa {Qt's Property System}
4941*/
4942
4943/*!
4944 \macro Q_ENUM(...)
4945 \relates QObject
4946 \since 5.5
4947
4948 This macro registers an enum type with the meta-object system.
4949 It must be placed after the enum declaration in a class that has the Q_OBJECT,
4950 Q_GADGET or Q_GADGET_EXPORT macro. For namespaces use \l Q_ENUM_NS() instead.
4951
4952 For example:
4953
4954 \snippet code/src_corelib_kernel_qobject.cpp 38
4955
4956 Enumerations that are declared with Q_ENUM have their QMetaEnum registered in the
4957 enclosing QMetaObject. You can also use QMetaEnum::fromType() to get the QMetaEnum.
4958
4959 Registered enumerations are automatically registered also to the Qt meta
4960 type system, making them known to QMetaType without the need to use
4961 Q_DECLARE_METATYPE(). This will enable useful features; for example, if used
4962 in a QVariant, you can convert them to strings. Likewise, passing them to
4963 QDebug will print out their names.
4964
4965 \sa {Qt's Property System}
4966*/
4967
4968
4969/*!
4970 \macro Q_FLAG(...)
4971 \relates QObject
4972 \since 5.5
4973
4974 This macro registers a single \l{QFlags}{flags type} with the
4975 meta-object system. It is typically used in a class definition to declare
4976 that values of a given enum can be used as flags and combined using the
4977 bitwise OR operator. For namespaces use \l Q_FLAG_NS() instead.
4978
4979 The macro must be placed after the enum declaration. The declaration of
4980 the flags type is done using the \l Q_DECLARE_FLAGS() macro.
4981
4982 For example, in QItemSelectionModel, the
4983 \l{QItemSelectionModel::SelectionFlags}{SelectionFlags} flag is
4984 declared in the following way:
4985
4986 \quotefromfile itemmodels/qitemselectionmodel.h
4987
4988 \skipto class Q_CORE_EXPORT QItemSelectionModel
4989 \printuntil Q_OBJECT
4990
4991 \dots
4992
4993 \skipto public:
4994 \printuntil Q_FLAG(SelectionFlags)
4995
4996 \skipuntil Q_DISABLE_COPY
4997 \printto Q_DECLARE_OPERATORS_FOR_FLAGS
4998
4999 \note The Q_FLAG macro takes care of registering individual flag values
5000 with the meta-object system, so it is unnecessary to use Q_ENUM()
5001 in addition to this macro.
5002
5003 \sa {Qt's Property System}
5004*/
5005
5006/*!
5007 \macro Q_ENUM_NS(...)
5008 \relates QObject
5009 \since 5.8
5010
5011 This macro registers an enum type with the meta-object system.
5012 It must be placed after the enum declaration in a namespace that
5013 has the Q_NAMESPACE macro. It is the same as \l Q_ENUM but in a
5014 namespace.
5015
5016 Enumerations that are declared with Q_ENUM_NS have their QMetaEnum
5017 registered in the enclosing QMetaObject. You can also use
5018 QMetaEnum::fromType() to get the QMetaEnum.
5019
5020 Registered enumerations are automatically registered also to the Qt meta
5021 type system, making them known to QMetaType without the need to use
5022 Q_DECLARE_METATYPE(). This will enable useful features; for example, if
5023 used in a QVariant, you can convert them to strings. Likewise, passing them
5024 to QDebug will print out their names.
5025
5026 \sa {Qt's Property System}
5027*/
5028
5029
5030/*!
5031 \macro Q_FLAG_NS(...)
5032 \relates QObject
5033 \since 5.8
5034
5035 This macro registers a single \l{QFlags}{flags type} with the
5036 meta-object system. It is used in a namespace that has the
5037 Q_NAMESPACE macro, to declare that values of a given enum can be
5038 used as flags and combined using the bitwise OR operator.
5039 It is the same as \l Q_FLAG but in a namespace.
5040
5041 The macro must be placed after the enum declaration.
5042
5043 \note The Q_FLAG_NS macro takes care of registering individual flag
5044 values with the meta-object system, so it is unnecessary to use
5045 Q_ENUM_NS() in addition to this macro.
5046
5047 \sa {Qt's Property System}
5048*/
5049
5050/*!
5051 \macro Q_OBJECT
5052 \relates QObject
5053
5054 The Q_OBJECT macro is used to enable meta-object features, such as dynamic
5055 properties, signals, and slots.
5056
5057 You can add the Q_OBJECT macro to any section of a class definition that
5058 declares its own signals and slots or that uses other services provided by
5059 Qt's meta-object system.
5060
5061//! [qobject-macros-private-access-specifier]
5062 \note This macro expansion ends with a \c private: access specifier. If you
5063 declare members immediately after this macro, those members will also be
5064 private. To add public (or protected) members right after the macro, use a
5065 \c {public:} (or \c {protected:}) access specifier.
5066//! [qobject-macros-private-access-specifier]
5067
5068 Example:
5069
5070 \snippet signalsandslots/signalsandslots.h 1
5071 \codeline
5072 \snippet signalsandslots/signalsandslots.h 2
5073 \snippet signalsandslots/signalsandslots.h 3
5074
5075 \note This macro requires the class to be a subclass of QObject. Use
5076 Q_GADGET or Q_GADGET_EXPORT instead of Q_OBJECT to enable the meta object
5077 system's support for enums in a class that is not a QObject subclass.
5078
5079 \sa {Meta-Object System}, {Signals and Slots}, {Qt's Property System}
5080*/
5081
5082/*!
5083 \macro Q_GADGET
5084 \relates QObject
5085
5086 The Q_GADGET macro is a lighter version of the Q_OBJECT macro for classes
5087 that do not inherit from QObject but still want to use some of the
5088 reflection capabilities offered by QMetaObject.
5089
5090 \include qobject.cpp qobject-macros-private-access-specifier
5091
5092 Q_GADGETs can have Q_ENUM, Q_PROPERTY and Q_INVOKABLE, but they cannot have
5093 signals or slots.
5094
5095 Q_GADGET makes a class member, \c{staticMetaObject}, available.
5096 \c{staticMetaObject} is of type QMetaObject and provides access to the
5097 enums declared with Q_ENUM.
5098
5099 \sa Q_GADGET_EXPORT
5100*/
5101
5102/*!
5103 \macro Q_GADGET_EXPORT(EXPORT_MACRO)
5104 \relates QObject
5105 \since 6.3
5106
5107 The Q_GADGET_EXPORT macro works exactly like the Q_GADGET macro.
5108 However, the \c{staticMetaObject} variable that is made available (see
5109 Q_GADGET) is declared with the supplied \a EXPORT_MACRO qualifier. This is
5110 useful if the object needs to be exported from a dynamic library, but the
5111 enclosing class as a whole should not be (e.g. because it consists of mostly
5112 inline functions).
5113
5114 \include qobject.cpp qobject-macros-private-access-specifier
5115
5116 For example:
5117
5118 \code
5119 class Point {
5120 Q_GADGET_EXPORT(EXPORT_MACRO)
5121 Q_PROPERTY(int x MEMBER x)
5122 Q_PROPERTY(int y MEMBER y)
5123 ~~~
5124 \endcode
5125
5126 \sa Q_GADGET, {Creating Shared Libraries}
5127*/
5128
5129/*!
5130 \macro Q_NAMESPACE
5131 \relates QObject
5132 \since 5.8
5133
5134 The Q_NAMESPACE macro can be used to add QMetaObject capabilities
5135 to a namespace.
5136
5137 Q_NAMESPACEs can have Q_CLASSINFO, Q_ENUM_NS, Q_FLAG_NS, but they
5138 cannot have Q_ENUM, Q_FLAG, Q_PROPERTY, Q_INVOKABLE, signals nor slots.
5139
5140 Q_NAMESPACE makes an external variable, \c{staticMetaObject}, available.
5141 \c{staticMetaObject} is of type QMetaObject and provides access to the
5142 enums declared with Q_ENUM_NS/Q_FLAG_NS.
5143
5144 For example:
5145
5146 \code
5147 namespace test {
5148 Q_NAMESPACE
5149 ...
5150 \endcode
5151
5152 \sa Q_NAMESPACE_EXPORT
5153*/
5154
5155/*!
5156 \macro Q_NAMESPACE_EXPORT(EXPORT_MACRO)
5157 \relates QObject
5158 \since 5.14
5159
5160 The Q_NAMESPACE_EXPORT macro can be used to add QMetaObject capabilities
5161 to a namespace.
5162
5163 It works exactly like the Q_NAMESPACE macro. However, the external
5164 \c{staticMetaObject} variable that gets defined in the namespace
5165 is declared with the supplied \a EXPORT_MACRO qualifier. This is
5166 useful if the object needs to be exported from a dynamic library.
5167
5168 For example:
5169
5170 \code
5171 namespace test {
5172 Q_NAMESPACE_EXPORT(EXPORT_MACRO)
5173 ...
5174 \endcode
5175
5176 \sa Q_NAMESPACE, {Creating Shared Libraries}
5177*/
5178
5179/*!
5180 \macro Q_MOC_INCLUDE
5181 \relates QObject
5182 \since 6.0
5183
5184 The Q_MOC_INCLUDE macro can be used within or outside a class, and tell the
5185 \l{moc}{Meta Object Compiler} to add an include.
5186
5187 \code
5188 // Put this in your code and the generated code will include this header.
5189 Q_MOC_INCLUDE("myheader.h")
5190 \endcode
5191
5192 This is useful if the types you use as properties or signal/slots arguments
5193 are forward declared.
5194*/
5195
5196/*!
5197 \macro Q_SIGNALS
5198 \relates QObject
5199
5200 Use this macro to replace the \c signals keyword in class
5201 declarations, when you want to use Qt Signals and Slots with a
5202 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5203
5204 The macro is normally used when \c no_keywords is specified with
5205 the \c CONFIG variable in the \c .pro file, but it can be used
5206 even when \c no_keywords is \e not specified.
5207*/
5208
5209/*!
5210 \macro Q_SIGNAL
5211 \relates QObject
5212
5213 This is an additional macro that allows you to mark a single
5214 function as a signal. It can be quite useful, especially when you
5215 use a 3rd-party source code parser which doesn't understand a \c
5216 signals or \c Q_SIGNALS groups.
5217
5218 Use this macro to replace the \c signals keyword in class
5219 declarations, when you want to use Qt Signals and Slots with a
5220 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5221
5222 The macro is normally used when \c no_keywords is specified with
5223 the \c CONFIG variable in the \c .pro file, but it can be used
5224 even when \c no_keywords is \e not specified.
5225*/
5226
5227/*!
5228 \macro Q_SLOTS
5229 \relates QObject
5230
5231 Use this macro to replace the \c slots keyword in class
5232 declarations, when you want to use Qt Signals and Slots with a
5233 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5234
5235 The macro is normally used when \c no_keywords is specified with
5236 the \c CONFIG variable in the \c .pro file, but it can be used
5237 even when \c no_keywords is \e not specified.
5238*/
5239
5240/*!
5241 \macro Q_SLOT
5242 \relates QObject
5243
5244 This is an additional macro that allows you to mark a single
5245 function as a slot. It can be quite useful, especially when you
5246 use a 3rd-party source code parser which doesn't understand a \c
5247 slots or \c Q_SLOTS groups.
5248
5249 Use this macro to replace the \c slots keyword in class
5250 declarations, when you want to use Qt Signals and Slots with a
5251 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5252
5253 The macro is normally used when \c no_keywords is specified with
5254 the \c CONFIG variable in the \c .pro file, but it can be used
5255 even when \c no_keywords is \e not specified.
5256*/
5257
5258/*!
5259 \macro Q_EMIT
5260 \relates QObject
5261
5262 Use this macro to replace the \c emit keyword for emitting
5263 signals, when you want to use Qt Signals and Slots with a
5264 \l{3rd Party Signals and Slots} {3rd party signal/slot mechanism}.
5265
5266 The macro is normally used when \c no_keywords is specified with
5267 the \c CONFIG variable in the \c .pro file, but it can be used
5268 even when \c no_keywords is \e not specified.
5269*/
5270
5271/*!
5272 \macro Q_INVOKABLE
5273 \relates QObject
5274
5275 Apply this macro to declarations of member functions to allow them to
5276 be invoked via the meta-object system. The macro is written before
5277 the return type, as shown in the following example:
5278
5279 \snippet qmetaobject-invokable/window.h Window class with invokable method
5280
5281 The \c invokableMethod() function is marked up using Q_INVOKABLE, causing
5282 it to be registered with the meta-object system and enabling it to be
5283 invoked using QMetaObject::invokeMethod().
5284 Since \c normalMethod() function is not registered in this way, it cannot
5285 be invoked using QMetaObject::invokeMethod().
5286
5287 If an invokable member function returns a pointer to a QObject or a
5288 subclass of QObject and it is invoked from QML, special ownership rules
5289 apply. See \l{qtqml-cppintegration-data.html}{Data Type Conversion Between QML and C++}
5290 for more information.
5291*/
5292
5293/*!
5294 \macro Q_REVISION
5295 \relates QObject
5296
5297 Apply this macro to declarations of member functions to tag them with a
5298 revision number in the meta-object system. The macro is written before
5299 the return type, as shown in the following example:
5300
5301 \snippet qmetaobject-revision/window.h Window class with revision
5302
5303 This is useful when using the meta-object system to dynamically expose
5304 objects to another API, as you can match the version expected by multiple
5305 versions of the other API. Consider the following simplified example:
5306
5307 \snippet qmetaobject-revision/main.cpp Window class using revision
5308
5309 Using the same Window class as the previous example, the newProperty and
5310 newMethod would only be exposed in this code when the expected version is
5311 \c{2.1} or greater.
5312
5313 Since all methods are considered to be in revision \c{0} if untagged, a tag
5314 of \c{Q_REVISION(0)} or \c{Q_REVISION(0, 0)} is invalid and ignored.
5315
5316 You can pass one or two integer parameters to \c{Q_REVISION}. If you pass
5317 one parameter, it denotes the minor version only. This means that the major
5318 version is unspecified. If you pass two, the first parameter is the major
5319 version and the second parameter is the minor version.
5320
5321 This tag is not used by the meta-object system itself. Currently this is only
5322 used by the QtQml module.
5323
5324 For a more generic string tag, see \l QMetaMethod::tag()
5325
5326 \sa QMetaMethod::revision()
5327*/
5328
5329/*!
5330 \macro Q_SET_OBJECT_NAME(Object)
5331 \relates QObject
5332 \since 5.0
5333
5334 This macro assigns \a Object the objectName "Object".
5335
5336 It doesn't matter whether \a Object is a pointer or not, the
5337 macro figures that out by itself.
5338
5339 \sa QObject::objectName()
5340*/
5341
5342/*!
5343 \macro QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
5344 \relates QObject
5345 \since 5.8
5346
5347 Defining this macro will disable narrowing and floating-point-to-integral
5348 conversions between the arguments carried by a signal and the arguments
5349 accepted by a slot, when the signal and the slot are connected using the
5350 PMF-based syntax.
5351
5352 \sa QObject::connect
5353*/
5354
5355/*!
5356 \macro QT_NO_CONTEXTLESS_CONNECT
5357 \relates QObject
5358 \since 6.7
5359
5360 Defining this macro will disable the overload of QObject::connect() that
5361 connects a signal to a functor, without also specifying a QObject
5362 as a receiver/context object (that is, the 3-arguments overload
5363 of QObject::connect()).
5364
5365 Using the context-less overload is error prone, because it is easy
5366 to connect to functors that depend on some local state of the
5367 receiving end. If such local state gets destroyed, the connection
5368 does not get automatically disconnected.
5369
5370 Moreover, such connections are always direct connections, which may
5371 cause issues in multithreaded scenarios (for instance, if the
5372 signal is emitted from another thread).
5373
5374 \sa QObject::connect, Qt::ConnectionType
5375*/
5376
5377/*!
5378 \since 6.12
5379 \macro QT_NO_DISCONNECT_CONST_CONNECTION
5380 \relates QObject
5381
5382 Disables the \c{const &} overload of
5383 \l{QObject::disconnect(QMetaObject::Connection&)}{QObject::disconnect()} to
5384 force callers to pass non-const objects.
5385
5386 Passing non-const objects is preferred, because they can be reset
5387 immediately, releasing resources sooner. Different versions of Qt handle
5388 the const overload differently. In older Qt versions, calling the const
5389 overload with a Connection originally declared \c{const} may invoke
5390 undefined behavior. Current Qt versions are safe in this regard, but future
5391 Qt versions may remove the const overload, or have it delay releasing
5392 resources until the Connection object is reassigned or destroyed.
5393
5394 Passing non-const objects avoids all of the issues above.
5395
5396 Code that compiles with this macro set also compiles (and doesn't invoke
5397 undefined behavior) without the macro enabled, and in all Qt versions since
5398 5.0.
5399*/
5400
5401/*!
5402 \typedef QObjectList
5403 \relates QObject
5404
5405 Synonym for QList<QObject *>.
5406*/
5407
5408/*!
5409 \fn template<typename PointerToMemberFunction> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type)
5410 \overload connect()
5411 \threadsafe
5412
5413 Creates a connection of the given \a type from the \a signal in
5414 the \a sender object to the \a method in the \a receiver object.
5415 Returns a handle to the connection that can be used to disconnect
5416 it later.
5417
5418 The signal must be a function declared as a signal in the header.
5419 The slot function can be any member function that can be connected
5420 to the signal.
5421 A slot can be connected to a given signal if the signal has at
5422 least as many arguments as the slot, and there is an implicit
5423 conversion between the types of the corresponding arguments in the
5424 signal and the slot.
5425
5426 Example:
5427
5428 \snippet code/src_corelib_kernel_qobject.cpp 44
5429
5430 This example ensures that the label always displays the current
5431 line edit text.
5432
5433 A signal can be connected to many slots and signals. Many signals
5434 can be connected to one slot.
5435
5436 If a signal is connected to several slots, the slots are activated
5437 in the same order as the order the connection was made, when the
5438 signal is emitted
5439
5440 The function returns an handle to a connection if it successfully
5441 connects the signal to the slot. The Connection handle will be invalid
5442 if it cannot create the connection, for example, if QObject is unable
5443 to verify the existence of \a signal (if it was not declared as a signal)
5444 You can check if the QMetaObject::Connection is valid by casting it to a bool.
5445
5446 By default, a signal is emitted for every connection you make;
5447 two signals are emitted for duplicate connections. You can break
5448 all of these connections with a single disconnect() call.
5449 If you pass the Qt::UniqueConnection \a type, the connection will only
5450 be made if it is not a duplicate. If there is already a duplicate
5451 (exact same signal to the exact same slot on the same objects),
5452 the connection will fail and connect will return an invalid QMetaObject::Connection.
5453
5454 The optional \a type parameter describes the type of connection
5455 to establish. In particular, it determines whether a particular
5456 signal is delivered to a slot immediately or queued for delivery
5457 at a later time. If the signal is queued, the parameters must be
5458 of types that are known to Qt's meta-object system, because Qt
5459 needs to copy the arguments to store them in an event behind the
5460 scenes. If you try to use a queued connection and get the error
5461 message
5462
5463 \snippet code/src_corelib_kernel_qobject.cpp 25
5464
5465 make sure to declare the argument type with Q_DECLARE_METATYPE
5466
5467 Overloaded functions can be resolved with help of \l qOverload.
5468
5469 \sa {Differences between String-Based and Functor-Based Connections}
5470 */
5471
5472/*!
5473 \fn template<typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
5474
5475 \threadsafe
5476 \overload connect()
5477
5478 Creates a connection from \a signal in
5479 \a sender object to \a functor, and returns a handle to the connection
5480
5481 The signal must be a function declared as a signal in the header.
5482 The slot function can be any function or functor that can be connected
5483 to the signal.
5484 A slot function can be connected to a given signal if the signal has at
5485 least as many arguments as the slot function. There must exist implicit
5486 conversion between the types of the corresponding arguments in the
5487 signal and the slot.
5488
5489 Example:
5490
5491 \snippet code/src_corelib_kernel_qobject.cpp 45
5492
5493 Lambda expressions can also be used:
5494
5495 \snippet code/src_corelib_kernel_qobject.cpp 46
5496
5497 The connection will automatically disconnect if the sender is destroyed.
5498 However, you should take care that any objects used within the functor
5499 are still alive when the signal is emitted.
5500
5501 For this reason, it is recommended to use the overload of connect()
5502 that also takes a QObject as a receiver/context. It is possible
5503 to disable the usage of the context-less overload by defining the
5504 \c{QT_NO_CONTEXTLESS_CONNECT} macro.
5505
5506 Overloaded functions can be resolved with help of \l qOverload.
5507
5508 */
5509
5510/*!
5511 \fn template<typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type)
5512
5513 \threadsafe
5514 \overload connect()
5515
5516 \since 5.2
5517
5518 Creates a connection of a given \a type from \a signal in
5519 \a sender object to \a functor to be placed in a specific event
5520 loop of \a context, and returns a handle to the connection.
5521
5522 \note Qt::UniqueConnections do not work for lambdas, non-member functions
5523 and functors; they only apply to connecting to member functions.
5524
5525 The signal must be a function declared as a signal in the header.
5526 The slot function can be any function or functor that can be connected
5527 to the signal.
5528 A slot function can be connected to a given signal if the signal has at
5529 least as many arguments as the slot function. There must exist implicit
5530 conversion between the types of the corresponding arguments in the
5531 signal and the slot.
5532
5533 Example:
5534
5535 \snippet code/src_corelib_kernel_qobject.cpp 50_someFunction
5536 \snippet code/src_corelib_kernel_qobject.cpp 50
5537
5538 Lambda expressions can also be used:
5539
5540 \snippet code/src_corelib_kernel_qobject.cpp 51
5541
5542 The connection will automatically disconnect if the sender or the context
5543 is destroyed.
5544 However, you should take care that any objects used within the functor
5545 are still alive when the signal is emitted.
5546
5547 Overloaded functions can be resolved with help of \l qOverload.
5548 */
5549
5550/*!
5551 \internal
5552
5553 Implementation of the template version of connect
5554
5555 \a sender is the sender object
5556 \a signal is a pointer to a pointer to a member signal of the sender
5557 \a receiver is the receiver object, may not be \nullptr, will be equal to sender when
5558 connecting to a static function or a functor
5559 \a slot a pointer only used when using Qt::UniqueConnection
5560 \a type the Qt::ConnectionType passed as argument to connect
5561 \a types an array of integer with the metatype id of the parameter of the signal
5562 to be used with queued connection
5563 must stay valid at least for the whole time of the connection, this function
5564 do not take ownership. typically static data.
5565 If \nullptr, then the types will be computed when the signal is emit in a queued
5566 connection from the types from the signature.
5567 \a senderMetaObject is the metaobject used to lookup the signal, the signal must be in
5568 this metaobject
5569 */
5570QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,
5571 const QObject *receiver, void **slot,
5572 QtPrivate::QSlotObjectBase *slotObjRaw, Qt::ConnectionType type,
5573 const int *types, const QMetaObject *senderMetaObject)
5574{
5575 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5576 Q_ASSERT_X(slotObjRaw, "QObject::connect", "Internal error, caller must not pass null slotObj");
5577 if (!signal) {
5578 connectWarning(sender, senderMetaObject, receiver, "invalid nullptr parameter");
5579 return QMetaObject::Connection();
5580 }
5581
5582 int signal_index = -1;
5583 void *args[] = { &signal_index, signal };
5584 for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
5585 senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
5586 if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
5587 break;
5588 }
5589 if (!senderMetaObject) {
5590 connectWarning(sender, senderMetaObject, receiver, "signal not found");
5591 return QMetaObject::Connection(nullptr);
5592 }
5593 signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
5594 return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj.release(), type, types, senderMetaObject);
5595}
5596
5597/*!
5598 \internal
5599
5600 Internal version of connect used by the template version of QObject::connect (called via connectImpl) and
5601 also used by the QObjectPrivate::connect version used by QML. The signal_index is expected to be relative
5602 to the number of signals.
5603 */
5604QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index,
5605 const QObject *receiver, void **slot,
5606 QtPrivate::QSlotObjectBase *slotObjRaw, int type,
5607 const int *types, const QMetaObject *senderMetaObject)
5608{
5609 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5610 Q_ASSERT(senderMetaObject);
5611 Q_ASSERT(slotObj);
5612
5613 if (!sender || !receiver) {
5614 connectWarning(sender, senderMetaObject, receiver, "invalid nullptr parameter");
5615 return QMetaObject::Connection();
5616 }
5617
5618 if (type & Qt::UniqueConnection && !slot) {
5619 connectWarning(sender, senderMetaObject, receiver, "unique connections require a pointer to member function of a QObject subclass");
5620 return QMetaObject::Connection();
5621 }
5622
5623 QObject *s = const_cast<QObject *>(sender);
5624 QObject *r = const_cast<QObject *>(receiver);
5625
5626 QOrderedMutexLocker locker(signalSlotLock(sender),
5627 signalSlotLock(receiver));
5628
5629 if (type & Qt::UniqueConnection) {
5630 QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
5631 if (connections && connections->signalVectorCount() > signal_index) {
5632 const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
5633
5634 while (c2) {
5635 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot))
5636 return QMetaObject::Connection();
5637 c2 = c2->nextConnectionList.loadRelaxed();
5638 }
5639 }
5640 }
5641 type &= ~Qt::UniqueConnection;
5642
5643 const bool isSingleShot = type & Qt::SingleShotConnection;
5644 type &= ~Qt::SingleShotConnection;
5645
5646 Q_ASSERT(type >= 0);
5647 Q_ASSERT(type <= 3);
5648
5649 std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
5650 c->sender = s;
5651 c->signal_index = signal_index;
5652 QThreadData *td = r->d_func()->threadData.loadAcquire();
5653 td->ref();
5654 c->receiverThreadData.storeRelaxed(td);
5655 c->receiver.storeRelaxed(r);
5656 c->connectionType = type;
5657 c->isSlotObject = true;
5658 c->slotObj = slotObj.release();
5659 if (types) {
5660 c->argumentTypes.storeRelaxed(types);
5661 c->ownArgumentTypes = false;
5662 }
5663 c->isSingleShot = isSingleShot;
5664
5665 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
5666 QMetaObject::Connection ret(c.release());
5667 locker.unlock();
5668
5669 QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
5670 Q_ASSERT(method.isValid());
5671 s->connectNotify(method);
5672
5673 return ret;
5674}
5675
5676#ifndef QT_NO_DISCONNECT_CONST_CONNECTION
5677/*!
5678 Disconnects \a connection and resets it to
5679 \l{QMetaObject::Connection::operator bool()}{invalid}.
5680
5681 If \a connection is invalid or has already been disconnected, do nothing
5682 and return false.
5683
5684 \note Future versions of Qt may only accept non-const objects here.
5685
5686 \sa QT_NO_DISCONNECT_CONST_CONNECTION
5687 \sa connect()
5688 */
5689bool QObject::disconnect(const QMetaObject::Connection &connection)
5690{
5691 // keep in sync with non-const overload
5692 QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(connection.d_ptr);
5693 if (!c)
5694 return false;
5695 const bool disconnected = QObjectPrivate::removeConnection(c);
5696 connection.d_ptr = nullptr;
5697 c->deref(); // has been removed from the QMetaObject::Connection object
5698 return disconnected;
5699}
5700#endif // QT_NO_DISCONNECT_CONST_CONNECTION
5701
5702/*!
5703 \since 6.12
5704 \fn bool QObject::disconnect(QMetaObject::Connection &connection)
5705 \fn bool QObject::disconnect(QMetaObject::Connection &&connection)
5706
5707 Disconnect a connection.
5708
5709 If \a connection is
5710 \l{QMetaObject::Connection::operator bool()}{invalid}
5711 or has already been disconnected, do nothing and return false.
5712
5713 \note In Qt versions prior to 6.12, this function took only by \c{const-&}.
5714
5715 \sa connect()
5716 */
5717bool QObject::disconnect(QMetaObject::Connection &connection)
5718{
5719 // keep in sync with the overload above
5720 QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(connection.d_ptr);
5721 if (!c)
5722 return false;
5723 const bool disconnected = QObjectPrivate::removeConnection(c);
5724 connection.d_ptr = nullptr;
5725 c->deref(); // has been removed from the QMetaObject::Connection object
5726 return disconnected;
5727}
5728
5729/*! \fn template<typename PointerToMemberFunction> bool QObject::disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method)
5730 \overload disconnect()
5731 \threadsafe
5732
5733 Disconnects \a signal in object \a sender from \a method in object
5734 \a receiver. Returns \c true if the connection is successfully broken;
5735 otherwise returns \c false.
5736
5737 A signal-slot connection is removed when either of the objects
5738 involved are destroyed.
5739
5740 disconnect() is typically used in three ways, as the following
5741 examples demonstrate.
5742 \list 1
5743 \li Disconnect everything connected to an object's signals:
5744
5745 \snippet code/src_corelib_kernel_qobject.cpp 26
5746
5747 \li Disconnect everything connected to a specific signal:
5748
5749 \snippet code/src_corelib_kernel_qobject.cpp 47
5750
5751 \li Disconnect a specific receiver:
5752
5753 \snippet code/src_corelib_kernel_qobject.cpp 30
5754
5755 \li Disconnect a connection from one specific signal to a specific slot:
5756
5757 \snippet code/src_corelib_kernel_qobject.cpp 48
5758
5759
5760 \endlist
5761
5762 \nullptr may be used as a wildcard, meaning "any signal", "any receiving
5763 object", or "any slot in the receiving object", respectively.
5764
5765 The \a sender may never be \nullptr. (You cannot disconnect signals
5766 from more than one object in a single call.)
5767
5768 If \a signal is \nullptr, it disconnects \a receiver and \a method from
5769 any signal. If not, only the specified signal is disconnected.
5770
5771 If \a receiver is \nullptr, it disconnects anything connected to \a
5772 signal. If not, only slots in the specified receiver are disconnected.
5773 disconnect() with a non-null \a receiver also disconnects slot functions
5774 that were connected with \a receiver as their context object.
5775
5776 If \a method is \nullptr, it disconnects anything that is connected to \a
5777 receiver. If not, only slots named \a method will be disconnected,
5778 and all other slots are left alone. The \a method must be \nullptr
5779 if \a receiver is left out, so you cannot disconnect a
5780 specifically-named slot on all objects.
5781
5782 \note It is not possible to use this overload to disconnect signals
5783 connected to functors or lambda expressions. That is because it is not
5784 possible to compare them. Instead, use the overload that takes a
5785 QMetaObject::Connection.
5786
5787 \note Unless \a method is \nullptr, this function will also not break
5788 connections that were made using the string-based version of connect(). To
5789 break such connections, use the corresponding string-based overload of
5790 disconnect().
5791
5792 \sa connect()
5793*/
5794
5795bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot, const QMetaObject *senderMetaObject)
5796{
5797 if (sender == nullptr || (receiver == nullptr && slot != nullptr)) {
5798 qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
5799 return false;
5800 }
5801
5802 int signal_index = -1;
5803 if (signal) {
5804 void *args[] = { &signal_index, signal };
5805 for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
5806 senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
5807 if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
5808 break;
5809 }
5810 if (!senderMetaObject) {
5811 qCWarning(lcConnect, "QObject::disconnect: signal not found in %s", sender->metaObject()->className());
5812 return false;
5813 }
5814 signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
5815 }
5816
5817 return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1, slot);
5818}
5819
5820/*!
5821 \internal
5822 Used by QML to connect a signal by index to a slot implemented in JavaScript
5823 (wrapped in a custom QSlotObjectBase subclass).
5824
5825 This version of connect assumes that sender and receiver are the same object.
5826
5827 The signal_index is an index relative to the number of methods.
5828 */
5829QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type)
5830{
5831 return QObjectPrivate::connect(sender, signal_index, sender, slotObj, type);
5832}
5833
5834/*!
5835 \internal
5836 Used by QML to connect a signal by index to a slot implemented in JavaScript
5837 (wrapped in a custom QSlotObjectBase subclass).
5838
5839 This is an overload that should be used when \a sender and \a receiver are
5840 different objects.
5841
5842 The signal_index is an index relative to the number of methods.
5843 */
5844QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index,
5845 const QObject *receiver,
5846 QtPrivate::QSlotObjectBase *slotObjRaw,
5847 Qt::ConnectionType type)
5848{
5849 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5850 Q_ASSERT_X(slotObjRaw, "QObjectPrivate::connect", "Internal error, caller must not pass null slotObj");
5851 if (!sender) {
5852 connectWarning(sender, nullptr, receiver, "invalid nullptr parameter");
5853 return QMetaObject::Connection();
5854 }
5855 const QMetaObject *senderMetaObject = sender->metaObject();
5856 signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
5857
5858 return connectImpl(sender, signal_index, receiver, /*slot*/ nullptr, slotObj.release(),
5859 type, /*types*/ nullptr, senderMetaObject);
5860}
5861
5862/*!
5863 \internal
5864 Used by QML to disconnect a signal by index that's connected to a slot implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass)
5865 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
5866 required for the disconnect.
5867
5868 This version of disconnect assumes that sender and receiver are the same object.
5869 */
5870bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, void **slot)
5871{
5872 return QObjectPrivate::disconnect(sender, signal_index, sender, slot);
5873}
5874
5875/*!
5876 \internal
5877
5878 Used by QML to disconnect a signal by index that's connected to a slot
5879 implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass) In the
5880 QML case the slot is not a pointer to a pointer to the function to disconnect,
5881 but instead it is a pointer to an array of internal values required for the
5882 disconnect.
5883
5884 This is an overload that should be used when \a sender and \a receiver are
5885 different objects.
5886 */
5887bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, const QObject *receiver,
5888 void **slot)
5889{
5890 const QMetaObject *senderMetaObject = sender->metaObject();
5891 signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
5892
5893 return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1,
5894 slot);
5895}
5896
5897/*!
5898 \internal
5899 \threadsafe
5900*/
5901inline bool QObjectPrivate::removeConnection(QObjectPrivate::Connection *c)
5902{
5903 if (!c)
5904 return false;
5905 QObject *receiver = c->receiver.loadRelaxed();
5906 if (!receiver)
5907 return false;
5908
5909 QBasicMutex *senderMutex = signalSlotLock(c->sender);
5910 QBasicMutex *receiverMutex = signalSlotLock(receiver);
5911
5912 QObjectPrivate::ConnectionData *connections;
5913 {
5914 QOrderedMutexLocker locker(senderMutex, receiverMutex);
5915
5916 // load receiver once again and recheck to ensure nobody else has removed the connection in the meantime
5917 receiver = c->receiver.loadRelaxed();
5918 if (!receiver)
5919 return false;
5920
5921 connections = QObjectPrivate::get(c->sender)->connections.loadRelaxed();
5922 Q_ASSERT(connections);
5923 connections->removeConnection(c);
5924
5925 c->sender->disconnectNotify(QMetaObjectPrivate::signal(c->sender->metaObject(), c->signal_index));
5926 // We must not hold the receiver mutex, else we risk dead-locking; we also only need the sender mutex
5927 // It is however vital to hold the senderMutex before calling cleanOrphanedConnections, as otherwise
5928 // another thread might modify/delete the connection
5929 if (receiverMutex != senderMutex) {
5930 receiverMutex->unlock();
5931 }
5932 connections->cleanOrphanedConnections(c->sender, ConnectionData::AlreadyLockedAndTemporarilyReleasingLock);
5933 senderMutex->unlock(); // now both sender and receiver mutex have been manually unlocked
5934 locker.dismiss(); // so we dismiss the QOrderedMutexLocker
5935 }
5936
5937 return true;
5938}
5939
5940/*!
5941 \internal
5942
5943 Used by QPropertyAdaptorSlotObject to get an existing instance for a property, if available
5944 */
5945QtPrivate::QPropertyAdaptorSlotObject *
5946QObjectPrivate::getPropertyAdaptorSlotObject(const QMetaProperty &property)
5947{
5948 if (auto conns = connections.loadAcquire()) {
5949 Q_Q(QObject);
5950 const QMetaObject *metaObject = q->metaObject();
5951 int signal_index = methodIndexToSignalIndex(&metaObject, property.notifySignalIndex());
5952 if (signal_index >= conns->signalVectorCount())
5953 return nullptr;
5954 const auto &connectionList = conns->connectionsForSignal(signal_index);
5955 for (auto c = connectionList.first.loadRelaxed(); c;
5956 c = c->nextConnectionList.loadRelaxed()) {
5957 if (c->isSlotObject) {
5958 if (auto p = QtPrivate::QPropertyAdaptorSlotObject::cast(c->slotObj,
5959 property.propertyIndex()))
5960 return p;
5961 }
5962 }
5963 }
5964 return nullptr;
5965}
5966
5967/*! \class QMetaObject::Connection
5968 \inmodule QtCore
5969 Represents a handle to a signal-slot (or signal-functor) connection.
5970
5971 It can be used to check if the connection is valid and to disconnect it using
5972 QObject::disconnect(). For a signal-functor connection without a context object,
5973 it is the only way to selectively disconnect that connection.
5974
5975 As Connection is just a handle, the underlying signal-slot connection is unaffected
5976 when Connection is destroyed or reassigned.
5977 */
5978
5979/*!
5980 Create a copy of the handle to the \a other connection
5981 */
5982QMetaObject::Connection::Connection(const QMetaObject::Connection &other) : d_ptr(other.d_ptr)
5983{
5984 if (d_ptr)
5985 static_cast<QObjectPrivate::Connection *>(d_ptr)->ref();
5986}
5987
5988/*!
5989 Assigns \a other to this connection and returns a reference to this connection.
5990*/
5991QMetaObject::Connection &QMetaObject::Connection::operator=(const QMetaObject::Connection &other)
5992{
5993 if (other.d_ptr != d_ptr) {
5994 if (d_ptr)
5995 static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
5996 d_ptr = other.d_ptr;
5997 if (other.d_ptr)
5998 static_cast<QObjectPrivate::Connection *>(other.d_ptr)->ref();
5999 }
6000 return *this;
6001}
6002
6003/*!
6004 \fn QMetaObject::Connection::Connection();
6005
6006 Creates a Connection instance.
6007*/
6008
6009/*!
6010 Destructor for QMetaObject::Connection.
6011*/
6012QMetaObject::Connection::~Connection()
6013{
6014 if (d_ptr)
6015 static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
6016}
6017
6018/*! \internal Returns true if the object is still connected */
6019bool QMetaObject::Connection::isConnected_helper() const
6020{
6021 Q_ASSERT(d_ptr); // we're only called from operator RestrictedBool() const
6022 QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(d_ptr);
6023
6024 return c->receiver.loadRelaxed();
6025}
6026
6027
6028/*!
6029 \fn QMetaObject::Connection::operator bool() const
6030
6031 Returns \c true if the connection is valid.
6032
6033 The connection is valid if the call to QObject::connect succeeded.
6034 The connection is invalid if QObject::connect was not able to find
6035 the signal or the slot, or if the arguments do not match.
6036 */
6037
6038QT_END_NAMESPACE
6039
6040#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:3067
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:3768
QObject * qt_qFindChild_helper(const QObject *parent, QAnyStringView name, const QMetaObject &mo, Qt::FindChildOptions options)
Definition qobject.cpp:2289
static const char * extract_location(const char *member)
Definition qobject.cpp:2708
ConnectionEnd
Definition qobject.cpp:2782
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:2764
static Q_DECL_COLD_FUNCTION void connectWarning(const QObject *sender, const QMetaObject *senderMetaObject, const QObject *receiver, const char *message)
Definition qobject.cpp:2808
static bool check_method_code(int code, const QObject *object, const char *method, const char *func)
Definition qobject.cpp:2735
static Q_DECL_COLD_FUNCTION void err_info_about_object(const char *func, const QObject *o, ConnectionEnd end)
Definition qobject.cpp:2784
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:2242
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:2702
static bool check_signal_macro(const QObject *sender, const char *signal, const char *func, const char *op)
Definition qobject.cpp:2719
static Q_DECL_COLD_FUNCTION void err_info_about_objects(const char *func, const QObject *sender, const QObject *receiver)
Definition qobject.cpp:2801
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, QAnyStringView name, const QMetaObject &mo, QList< void * > *list, Qt::FindChildOptions options)
Definition qobject.cpp:2252
Q_CORE_EXPORT const char * qFlagLocation(const char *method)
Definition qobject.cpp:2696
SlotObjectGuard()=default