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

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