373 TaggedSignalVector c =
nullptr;
375 std::unique_lock<QBasicMutex> lock(*senderMutex, std::defer_lock_t{});
376 if (lockPolicy == NeedToLock)
378 if (ref.loadAcquire() > 1)
384 c = orphaned.exchange(
nullptr, std::memory_order_relaxed);
388 if (lockPolicy == AlreadyLockedAndTemporarilyReleasingLock) {
389 senderMutex->unlock();
398inline void QObjectPrivate::ConnectionData::deleteOrphaned(TaggedSignalVector o)
401 TaggedSignalVector next =
nullptr;
402 if (SignalVector *v =
static_cast<SignalVector *>(o)) {
403 next = v->nextInOrphanList;
406 QObjectPrivate::Connection *c =
static_cast<Connection *>(o);
407 next = c->nextInOrphanList;
408 Q_ASSERT(!c->receiver.loadRelaxed());
418
419
420
421
422
423bool QObjectPrivate::isSignalConnected(uint signalIndex,
bool checkDeclarative)
const
425 if (checkDeclarative && isDeclarativeSignalConnected(signalIndex))
428 ConnectionData *cd = connections.loadAcquire();
431 SignalVector *signalVector = cd->signalVector.loadRelaxed();
435 if (signalVector->at(-1).first.loadRelaxed())
438 if (signalIndex < uint(cd->signalVectorCount())) {
439 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadRelaxed();
441 if (c->receiver.loadRelaxed())
443 c = c->nextConnectionList.loadRelaxed();
449bool QObjectPrivate::maybeSignalConnected(uint signalIndex)
const
451 ConnectionData *cd = connections.loadAcquire();
454 SignalVector *signalVector = cd->signalVector.loadRelaxed();
458 if (signalVector->at(-1).first.loadAcquire())
461 if (signalIndex < uint(cd->signalVectorCount())) {
462 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadAcquire();
468void QObjectPrivate::reinitBindingStorageAfterThreadMove()
470 bindingStorage.reinitAfterThreadMove();
471 for (
int i = 0; i < children.size(); ++i)
472 children[i]->d_func()->reinitBindingStorageAfterThreadMove();
476
477
478QAbstractMetaCallEvent::~QAbstractMetaCallEvent()
487
488
489
490
491
492QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative,
493 QObjectPrivate::StaticMetaCallFunction callFunction,
494 const QObject *sender,
int signalId,
495 void **args, QLatch *latch)
496 : QAbstractMetaCallEvent(sender, signalId, latch),
497 d{
nullptr, args, callFunction, 0, method_offset, method_relative}
502
503
504
505
506
507QMetaCallEvent::QMetaCallEvent(QtPrivate::QSlotObjectBase *slotO,
508 const QObject *sender,
int signalId,
509 void **args, QLatch *latch)
510 : QAbstractMetaCallEvent(sender, signalId, latch),
511 d{QtPrivate::SlotObjUniquePtr{slotO}, args,
nullptr, 0, 0, ushort(-1)}
518
519
520
521
522
523QMetaCallEvent::QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotO,
524 const QObject *sender,
int signalId,
525 void **args, QLatch *latch)
526 : QAbstractMetaCallEvent(sender, signalId, latch),
527 d{std::move(slotO), args,
nullptr, 0, 0, ushort(-1)}
532
533
534QMetaCallEvent::QMetaCallEvent(
const QObject *sender,
int signalId, Data &&data)
535 : QAbstractMetaCallEvent(sender, signalId),
541
542
543void QMetaCallEvent::placeMetaCall(QObject *object)
546 d.slotObj_->call(object, d.args_);
547 }
else if (d.callFunction_ && d.method_offset_ <= object->metaObject()->methodOffset()) {
548 d.callFunction_(object, QMetaObject::InvokeMetaMethod, d.method_relative_, d.args_);
550 QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod,
551 d.method_offset_ + d.method_relative_, d.args_);
556
557
558
559
560QQueuedMetaCallEvent::QQueuedMetaCallEvent(ushort method_offset, ushort method_relative,
561 QObjectPrivate::StaticMetaCallFunction callFunction,
562 const QObject *sender,
int signalId,
int argCount,
563 const QtPrivate::QMetaTypeInterface *
const *argTypes,
564 const void *
const *argValues)
565 : QMetaCallEvent(sender, signalId, {
nullptr,
nullptr, callFunction, argCount,
566 method_offset, method_relative}),
569 copyArgValues(argCount, argTypes, argValues);
573
574
575
576
577QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
578 const QObject *sender,
int signalId,
int argCount,
579 const QtPrivate::QMetaTypeInterface *
const *argTypes,
580 const void *
const *argValues)
581 : QMetaCallEvent(sender, signalId, {QtPrivate::SlotObjUniquePtr(slotObj),
nullptr,
nullptr, argCount,
587 copyArgValues(argCount, argTypes, argValues);
591
592
593
594
595QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,
596 const QObject *sender,
int signalId,
int argCount,
597 const QtPrivate::QMetaTypeInterface *
const *argTypes,
598 const void *
const *argValues)
599 : QMetaCallEvent(sender, signalId, {std::move(slotObj),
nullptr,
nullptr, argCount,
603 copyArgValues(argCount, argTypes, argValues);
607
608
609QQueuedMetaCallEvent::~QQueuedMetaCallEvent()
611 const QMetaType *t =
reinterpret_cast<QMetaType *>(d.args_ + d.nargs_);
612 int inplaceIndex = 0;
613 for (
int i = 0; i < d.nargs_; ++i) {
614 if (t[i].isValid() && d.args_[i]) {
615 if (typeFitsInPlace(t[i]) && inplaceIndex < InplaceValuesCapacity) {
617 void *where = &valuesPrealloc_[inplaceIndex++].storage;
618 t[i].destruct(where);
621 t[i].destroy(d.args_[i]);
626 if (
static_cast<
void *>(d.args_) != prealloc_)
627 QtPrivate::sizedFree(d.args_, d.nargs_, PtrAndTypeSize);
632
633
634inline void QQueuedMetaCallEvent::allocArgs()
639 void *
const memory = d.nargs_ * PtrAndTypeSize >
sizeof(prealloc_) ?
640 calloc(d.nargs_, PtrAndTypeSize) : prealloc_;
643 d.args_ =
static_cast<
void **>(memory);
647
648
649inline void QQueuedMetaCallEvent::copyArgValues(
int argCount,
const QtPrivate::QMetaTypeInterface *
const *argTypes,
650 const void *
const *argValues)
653 void **args = d.args_;
654 QMetaType *types =
reinterpret_cast<QMetaType *>(d.args_ + d.nargs_);
655 int inplaceIndex = 0;
658 types[0] = QMetaType();
663 for (
int n = 1; n < argCount; ++n) {
664 types[n] = QMetaType(argTypes[n]);
665 if (typeFitsInPlace(types[n]) && inplaceIndex < InplaceValuesCapacity) {
667 void *where = &valuesPrealloc_[inplaceIndex++].storage;
668 types[n].construct(where, argValues[n]);
672 args[n] = types[n].create(argValues[n]);
678
679
680inline bool QQueuedMetaCallEvent::typeFitsInPlace(
const QMetaType type)
682 return (q20::cmp_less_equal(type.sizeOf(),
sizeof(ArgValueStorage)) &&
683 q20::cmp_less_equal(type.alignOf(),
alignof(ArgValueStorage)));
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
711
712
713
714
717
718
719
720
721
724
725
726
727
728
729
732
733
734
735
736
737
738
739
740
741
742
745
746
747
748
749
750
753
754
755
756
757
758
759
762
763
764
765
766
767
768
769
770
773
774
775
776
777
778
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
935
936
943 if (parent && parentThreadData != currentThreadData) {
944 QThread *parentThread = parentThreadData->thread.loadAcquire();
945 QThread *currentThread = currentThreadData->thread.loadAcquire();
946 qWarning(
"QObject: Cannot create children for a parent that is in a different thread.\n"
947 "(Parent is %s(%p), parent's thread is %s(%p), current thread is %s(%p)",
948 parent->metaObject()->className(),
950 parentThread ? parentThread->metaObject()->className() :
"QThread",
952 currentThread ? currentThread->metaObject()->className() :
"QThread",
960
961
962
963
964
965
966
967
968
969
970
971
972
974QObject::QObject(QObject *parent)
975 : QObject(*
new QObjectPrivate, parent)
980
981
982QObject::QObject(QObjectPrivate &dd, QObject *parent)
985 Q_ASSERT_X(
this != parent, Q_FUNC_INFO,
"Cannot parent a QObject to itself");
989 auto threadData = (parent && !parent->thread()) ? parent->d_func()->threadData.loadRelaxed() : QThreadData::current();
991 d->threadData.storeRelaxed(threadData);
994 if (!check_parent_thread(parent, parent ? parent->d_func()->threadData.loadRelaxed() :
nullptr, threadData))
996 if (d->willBeWidget) {
999 d->parent->d_func()->children.append(
this);
1006 threadData->deref();
1010 if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
1011 reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(
this);
1012 Q_TRACE(QObject_ctor,
this);
1047 d->wasDeleted =
true;
1050 if (!d->bindingStorage.isValid()) {
1053 if (QThread *ownThread = thread()) {
1054 auto *privThread =
static_cast<QThreadPrivate *>(
1055 QObjectPrivate::get(ownThread));
1056 privThread->removeObjectWithPendingBindingStatusChange(
this);
1062 d->clearBindingStorage();
1064 QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.loadRelaxed();
1065 if (sharedRefcount) {
1066 if (sharedRefcount->strongref.loadRelaxed() > 0) {
1067 qWarning(
"QObject: shared QObject was deleted directly. The program is malformed and may crash.");
1072 sharedRefcount->strongref.storeRelaxed(0);
1073 if (!sharedRefcount->weakref.deref())
1074 delete sharedRefcount;
1077 if (!d->wasWidget && d->isSignalConnected(0)) {
1078 emit destroyed(
this);
1081 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::destroyed)
1082 QAbstractDeclarativeData::destroyed(d->declarativeData,
this);
1084 QObjectPrivate::ConnectionData *cd = d->connections.loadAcquire();
1086 if (cd->currentSender) {
1087 cd->currentSender->receiverDeleted();
1088 cd->currentSender =
nullptr;
1091 QBasicMutex *signalSlotMutex = signalSlotLock(
this);
1092 QMutexLocker locker(signalSlotMutex);
1095 int receiverCount = cd->signalVectorCount();
1096 for (
int signal = -1; signal < receiverCount; ++signal) {
1097 QObjectPrivate::ConnectionList &connectionList = cd->connectionsForSignal(signal);
1099 while (QObjectPrivate::Connection *c = connectionList.first.loadRelaxed()) {
1100 Q_ASSERT(c->receiver.loadAcquire());
1102 QBasicMutex *m = signalSlotLock(c->receiver.loadRelaxed());
1103 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1104 if (c == connectionList.first.loadAcquire() && c->receiver.loadAcquire()) {
1105 cd->removeConnection(c);
1106 Q_ASSERT(connectionList.first.loadRelaxed() != c);
1114
1115 while (QObjectPrivate::Connection *node = cd->senders) {
1116 Q_ASSERT(node->receiver.loadAcquire());
1117 QObject *sender = node->sender;
1121 sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), node->signal_index));
1122 QBasicMutex *m = signalSlotLock(sender);
1123 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1125 if (node != cd->senders) {
1127 Q_ASSERT(needToUnlock);
1132 QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections.loadRelaxed();
1133 Q_ASSERT(senderData);
1135 QtPrivate::QSlotObjectBase *slotObj =
nullptr;
1136 if (node->isSlotObject) {
1137 slotObj = node->slotObj;
1138 node->isSlotObject =
false;
1141 senderData->removeConnection(node);
1143
1144
1145
1146
1147
1148
1149
1150 const bool locksAreTheSame = signalSlotMutex == m;
1151 if (!locksAreTheSame)
1153 senderData->cleanOrphanedConnections(
1155 QObjectPrivate::ConnectionData::AlreadyLockedAndTemporarilyReleasingLock
1160 if (locksAreTheSame)
1163 slotObj->destroyIfLastRef();
1169 cd->currentConnectionId.storeRelaxed(0);
1171 if (cd && !cd->ref.deref())
1173 d->connections.storeRelaxed(
nullptr);
1175 if (!d->children.isEmpty())
1176 d->deleteChildren();
1178 if (Q_UNLIKELY(qtHookData[QHooks::RemoveQObject]))
1179 reinterpret_cast<QHooks::RemoveQObjectCallback>(qtHookData[QHooks::RemoveQObject])(
this);
1181 Q_TRACE(QObject_dtor,
this);
1184 d->setParent_helper(
nullptr);
1450bool QObject::event(QEvent *e)
1452 switch (e->type()) {
1454 timerEvent((QTimerEvent *)e);
1457 case QEvent::ChildAdded:
1458 case QEvent::ChildPolished:
1459 case QEvent::ChildRemoved:
1460 childEvent((QChildEvent *)e);
1463 case QEvent::DeferredDelete:
1467 case QEvent::MetaCall:
1469 QAbstractMetaCallEvent *mce =
static_cast<QAbstractMetaCallEvent*>(e);
1471 QObjectPrivate::ConnectionData *connections = d_func()->connections.loadAcquire();
1473 QMutexLocker locker(signalSlotLock(
this));
1474 d_func()->ensureConnectionData();
1475 connections = d_func()->connections.loadRelaxed();
1477 QObjectPrivate::Sender sender(
this,
const_cast<QObject*>(mce->sender()), mce->signalId(), connections);
1479 mce->placeMetaCall(
this);
1483 case QEvent::ThreadChange: {
1485 QThreadData *threadData = d->threadData.loadRelaxed();
1486 QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
1487 if (eventDispatcher) {
1488 QList<QAbstractEventDispatcher::TimerInfoV2> timers = eventDispatcher->timersForObject(
this);
1489 if (!timers.isEmpty()) {
1490 const bool res = eventDispatcher->unregisterTimers(
this);
1492 Q_ASSERT_X(res, Q_FUNC_INFO,
1493 "QAbstractEventDispatcher::unregisterTimers() returned false,"
1494 " but there are timers associated with this object.");
1495 auto reRegisterTimers = [
this, timers = std::move(timers)]() {
1496 QAbstractEventDispatcher *eventDispatcher =
1497 d_func()->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
1498 for (
const auto &ti : timers)
1499 eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType,
this);
1501 QMetaObject::invokeMethod(
this, std::move(reRegisterTimers), Qt::QueuedConnection);
1508 if (e->type() >= QEvent::User) {
1705bool QObject::moveToThread(QThread *targetThread QT6_IMPL_NEW_OVERLOAD_TAIL)
1709 if (d->threadData.loadRelaxed()->thread.loadAcquire() == targetThread) {
1714 if (d->parent !=
nullptr) {
1715 qWarning(
"QObject::moveToThread: Cannot move objects with a parent");
1719 qWarning(
"QObject::moveToThread: Widgets cannot be moved to a new thread");
1722 if (!d->bindingStorage.isEmpty()) {
1723 qWarning(
"QObject::moveToThread: Can not move objects that contain bindings or are used in bindings to a new thread.");
1727 QThreadData *currentData = QThreadData::current();
1728 QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) :
nullptr;
1729 QThreadData *thisThreadData = d->threadData.loadAcquire();
1730 if (!thisThreadData->thread.loadRelaxed() && currentData == targetData) {
1732 currentData = thisThreadData;
1733 }
else if (thisThreadData != currentData) {
1734 qWarning(
"QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
1735 "Cannot move to target thread (%p)\n",
1736 currentData->thread.loadRelaxed(), thisThreadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() :
nullptr);
1739 qWarning(
"You might be loading two sets of Qt binaries into the same process. "
1740 "Check that all plugins are compiled against the right Qt binaries. Export "
1741 "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.");
1748 d->moveToThread_helper();
1751 targetData =
new QThreadData(0);
1754 QMutexLocker l(signalSlotLock(
this));
1756 QOrderedMutexLocker locker(¤tData->postEventList.mutex,
1757 &targetData->postEventList.mutex);
1763 auto threadPrivate = targetThread
1764 ?
static_cast<QThreadPrivate *>(QThreadPrivate::get(targetThread))
1766 QBindingStatus *bindingStatus = threadPrivate
1767 ? threadPrivate->bindingStatus()
1769 if (threadPrivate && !bindingStatus) {
1770 bindingStatus = threadPrivate->addObjectWithPendingBindingStatusChange(
this);
1772 d_func()->setThreadData_helper(currentData, targetData, bindingStatus);
1777 currentData->deref();
1793void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status)
1799 this->bindingStorage.bindingStatus = status;
1803 qsizetype eventsMoved = 0;
1804 for (qsizetype i = 0; i < currentData->postEventList.size(); ++i) {
1805 const QPostEvent &pe = currentData->postEventList.at(i);
1808 if (pe.receiver == q) {
1810 targetData->postEventList.addEvent(pe);
1811 const_cast<QPostEvent &>(pe).event =
nullptr;
1815 if (eventsMoved > 0 && targetData->hasEventDispatcher()) {
1816 targetData->canWait =
false;
1817 targetData->eventDispatcher.loadRelaxed()->wakeUp();
1821 ConnectionData *cd = connections.loadAcquire();
1823 if (cd->currentSender) {
1824 cd->currentSender->receiverDeleted();
1825 cd->currentSender =
nullptr;
1830 auto *c = cd->senders;
1832 QObject *r = c->receiver.loadRelaxed();
1836 QThreadData *old = c->receiverThreadData.loadRelaxed();
1839 c->receiverThreadData.storeRelaxed(targetData);
1849 threadData.loadRelaxed()->deref();
1852 threadData.storeRelease(targetData);
1854 for (
int i = 0; i < children.size(); ++i) {
1855 QObject *child = children.at(i);
1856 child->d_func()->setThreadData_helper(currentData, targetData, status);
2285void QObjectPrivate::setParent_helper(QObject *o)
2288 Q_ASSERT_X(q != o, Q_FUNC_INFO,
"Cannot parent a QObject to itself");
2290 const auto checkForParentChildLoops = qScopeGuard([&](){
2294 if (++depth == CheckForParentChildLoopsWarnDepth) {
2295 qWarning(
"QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
2296 "this is undefined behavior",
2297 q, q->metaObject()->className(), qPrintable(q->objectName()));
2308 QObjectPrivate *parentD = parent->d_func();
2309 if (parentD->isDeletingChildren && wasDeleted
2310 && parentD->currentChildBeingDeleted == q) {
2314 const qsizetype index = parentD->children.indexOf(q);
2317 }
else if (parentD->isDeletingChildren) {
2318 parentD->children[index] =
nullptr;
2320 parentD->children.removeAt(index);
2321 if (sendChildEvents && parentD->receiveChildEvents) {
2322 QChildEvent e(QEvent::ChildRemoved, q);
2323 QCoreApplication::sendEvent(parent, &e);
2329 if (receiveParentEvents) {
2330 Q_ASSERT(!isWidget);
2331 QEvent e(QEvent::ParentAboutToChange);
2332 QCoreApplication::sendEvent(q, &e);
2339 if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) {
2340 qWarning(
"QObject::setParent: Cannot set parent, new parent is in a different thread");
2344 parent->d_func()->children.append(q);
2345 if (sendChildEvents && parent->d_func()->receiveChildEvents) {
2347 QChildEvent e(QEvent::ChildAdded, q);
2348 QCoreApplication::sendEvent(parent, &e);
2353 if (receiveParentEvents) {
2354 Q_ASSERT(!isWidget);
2355 QEvent e(QEvent::ParentChange);
2356 QCoreApplication::sendEvent(q, &e);
3051QMetaObject::Connection QObject::connect(
const QObject *sender,
const char *signal,
3052 const QObject *receiver,
const char *method,
3053 Qt::ConnectionType type)
3055 if (sender ==
nullptr || receiver ==
nullptr || signal ==
nullptr || method ==
nullptr) {
3056 qCWarning(lcConnect,
"QObject::connect: Cannot connect %s::%s to %s::%s",
3057 sender ? sender->metaObject()->className() :
"(nullptr)",
3058 (signal && *signal) ? signal + 1 :
"(nullptr)",
3059 receiver ? receiver->metaObject()->className() :
"(nullptr)",
3060 (method && *method) ? method + 1 :
"(nullptr)");
3061 return QMetaObject::Connection(
nullptr);
3064 if (!check_signal_macro(sender, signal,
"connect",
"bind"))
3065 return QMetaObject::Connection(
nullptr);
3067 int membcode = extract_code(method);
3068 if (!check_method_code(membcode, receiver, method,
"connect"))
3069 return QMetaObject::Connection(
nullptr);
3071 QByteArray pinnedSignal;
3072 const QMetaObject *smeta = sender->metaObject();
3073 const char *signal_arg = signal;
3075 QByteArrayView signalView{signal};
3076 QArgumentTypeArray signalTypes;
3077 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3078 QByteArrayView signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3079 int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3080 if (signal_index < 0) {
3082 pinnedSignal = QMetaObjectPrivate::normalizedSignature(signalView);
3083 signalView = pinnedSignal;
3085 signalTypes.clear();
3086 signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3087 smeta = sender->metaObject();
3088 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3090 if (signal_index < 0) {
3091 err_method_notfound(sender, signal_arg,
"connect");
3092 err_info_about_objects(
"connect", sender, receiver);
3093 return QMetaObject::Connection(
nullptr);
3095 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3096 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3098 QByteArray pinnedMethod;
3099 const char *method_arg = method;
3101 QByteArrayView methodView{method};
3103 QArgumentTypeArray methodTypes;
3104 QByteArrayView methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3105 const QMetaObject *rmeta = receiver->metaObject();
3106 int method_index_relative = -1;
3107 Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
3110 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3111 &rmeta, methodName, methodTypes);
3114 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3115 &rmeta, methodName, methodTypes);
3119 if (method_index_relative < 0) {
3121 pinnedMethod = QMetaObjectPrivate::normalizedSignature(methodView);
3122 methodView = pinnedMethod;
3124 methodTypes.clear();
3125 methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3127 rmeta = receiver->metaObject();
3130 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3131 &rmeta, methodName, methodTypes);
3134 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3135 &rmeta, methodName, methodTypes);
3140 if (method_index_relative < 0) {
3141 err_method_notfound(receiver, method_arg,
"connect");
3142 err_info_about_objects(
"connect", sender, receiver);
3143 return QMetaObject::Connection(
nullptr);
3146 if (!QMetaObjectPrivate::checkConnectArgs(signalTypes, methodTypes)) {
3148 "QObject::connect: Incompatible sender/receiver arguments"
3149 "\n %s::%s --> %s::%s",
3150 sender->metaObject()->className(), signalView.constData(),
3151 receiver->metaObject()->className(), methodView.constData());
3152 return QMetaObject::Connection(
nullptr);
3157 int *types =
nullptr;
3158 if (type == Qt::QueuedConnection && !(types = queuedConnectionTypes(signalTypes))) {
3159 return QMetaObject::Connection(
nullptr);
3162 QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
3164 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3165 check_and_warn_compat(smeta, smethod, rmeta, rmethod);
3168#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
3169 check_and_warn_non_slot(
"connect", method, membcode, rmeta, rmethod);
3172 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3173 sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
3197QMetaObject::Connection QObject::connect(
const QObject *sender,
const QMetaMethod &signal,
3198 const QObject *receiver,
const QMetaMethod &method,
3199 Qt::ConnectionType type)
3201 if (sender ==
nullptr
3202 || receiver ==
nullptr
3203 || signal.methodType() != QMetaMethod::Signal
3204 || method.methodType() == QMetaMethod::Constructor) {
3205 qCWarning(lcConnect,
"QObject::connect: Cannot connect %s::%s to %s::%s",
3206 sender ? sender->metaObject()->className() :
"(nullptr)",
3207 signal.methodSignature().constData(),
3208 receiver ? receiver->metaObject()->className() :
"(nullptr)",
3209 method.methodSignature().constData());
3210 return QMetaObject::Connection(
nullptr);
3217 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3218 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3221 const QMetaObject *smeta = sender->metaObject();
3222 const QMetaObject *rmeta = receiver->metaObject();
3223 if (signal_index == -1) {
3224 qCWarning(lcConnect,
"QObject::connect: Can't find signal %s on instance of class %s",
3225 signal.methodSignature().constData(), smeta->className());
3226 return QMetaObject::Connection(
nullptr);
3228 if (method_index == -1) {
3229 qCWarning(lcConnect,
"QObject::connect: Can't find method %s on instance of class %s",
3230 method.methodSignature().constData(), rmeta->className());
3231 return QMetaObject::Connection(
nullptr);
3234 if (!QMetaObject::checkConnectArgs(signal.methodSignature().constData(),
3235 method.methodSignature().constData())) {
3237 "QObject::connect: Incompatible sender/receiver arguments"
3238 "\n %s::%s --> %s::%s",
3239 smeta->className(), signal.methodSignature().constData(), rmeta->className(),
3240 method.methodSignature().constData());
3241 return QMetaObject::Connection(
nullptr);
3244 int *types =
nullptr;
3245 if ((type == Qt::QueuedConnection) && !(types = queuedConnectionTypes(signal)))
3246 return QMetaObject::Connection(
nullptr);
3249 check_and_warn_compat(smeta, signal, rmeta, method);
3251 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3252 sender, signal_index, signal.enclosingMetaObject(), receiver, method_index,
nullptr, type, types));
3337bool QObject::disconnect(
const QObject *sender,
const char *signal,
3338 const QObject *receiver,
const char *method)
3340 if (sender ==
nullptr || (receiver ==
nullptr && method !=
nullptr)) {
3341 qCWarning(lcConnect,
"QObject::disconnect: Unexpected nullptr parameter");
3345 const char *signal_arg = signal;
3347 if (!check_signal_macro(sender, signal,
"disconnect",
"unbind"))
3352 const char *method_arg = method;
3355 membcode = extract_code(method);
3356 if (!check_method_code(membcode, receiver, method,
"disconnect"))
3361 QByteArray pinnedSignal;
3362 const QMetaObject *smeta = sender->metaObject();
3363 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3364 int signal_index = -1;
3365 QByteArrayView signalName;
3366 QArgumentTypeArray signalTypes;
3368 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3369 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3370 if (signal_index == -1) {
3371 pinnedSignal = QMetaObject::normalizedSignature(signal);
3372 signal = pinnedSignal.constData();
3373 signalTypes.clear();
3374 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3375 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3378 if (signal_index == -1) {
3379 err_method_notfound(sender, signal_arg,
"disconnect");
3380 err_info_about_objects(
"disconnect", sender, receiver);
3385 auto getMethodIndex = [](
int code,
const QMetaObject *mo, QByteArrayView name,
3386 const QArgumentTypeArray &types) {
3389 return QMetaObjectPrivate::indexOfSlot(mo, name, types);
3391 return QMetaObjectPrivate::indexOfSignal(mo, name, types);
3396 QByteArray pinnedMethod;
3397 const QMetaObject *rmeta = receiver ? receiver->metaObject() :
nullptr;
3398 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 7);
3399 int method_index = -1;
3400 QByteArrayView methodName;
3401 QArgumentTypeArray methodTypes;
3403 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3404 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3405 if (method_index == -1) {
3406 pinnedMethod = QMetaObject::normalizedSignature(method);
3407 method = pinnedMethod.constData();
3408 methodTypes.clear();
3409 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3410 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3412 if (method_index == -1) {
3413 err_method_notfound(receiver, method_arg,
"disconnect");
3414 err_info_about_objects(
"disconnect", sender, receiver);
3420
3421
3422
3427 if (smeta != sender->metaObject()) {
3428 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3431 if (signal_index < 0)
3433 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3434 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3438 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1,
nullptr);
3442 if (rmeta != receiver->metaObject())
3443 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3444 if (method_index >= 0) {
3445#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
3446 check_and_warn_non_slot(
"disconnect", method, membcode, rmeta,
3447 rmeta->method(method_index));
3449 while (method_index < rmeta->methodOffset())
3450 rmeta = rmeta->superClass();
3452 if (method_index < 0)
3454 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index,
nullptr);
3455 }
while ((rmeta = rmeta->superClass()));
3457 }
while (signal && (smeta = smeta->superClass()));
3461 const_cast<QObject *>(sender)->disconnectNotify(QMetaMethod());
3500bool QObject::disconnect(
const QObject *sender,
const QMetaMethod &signal,
3501 const QObject *receiver,
const QMetaMethod &method)
3503 if (sender ==
nullptr || (receiver ==
nullptr && method.mobj !=
nullptr)) {
3504 qCWarning(lcConnect,
"QObject::disconnect: Unexpected nullptr parameter");
3508 if (signal.methodType() != QMetaMethod::Signal) {
3509 qCWarning(lcConnect,
"QObject::%s: Attempt to %s non-signal %s::%s",
3510 "disconnect",
"unbind",
3511 sender->metaObject()->className(), signal.methodSignature().constData());
3516 if (method.methodType() == QMetaMethod::Constructor) {
3517 qCWarning(lcConnect,
"QObject::disconnect: cannot use constructor as argument %s::%s",
3518 receiver->metaObject()->className(), method.methodSignature().constData());
3527 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3528 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3532 if (signal.mobj && signal_index == -1) {
3533 qCWarning(lcConnect,
"QObject::disconnect: signal %s not found on class %s",
3534 signal.methodSignature().constData(), sender->metaObject()->className());
3538 if (receiver && method.mobj && method_index == -1) {
3539 qCWarning(lcConnect,
"QObject::disconnect: method %s not found on class %s",
3540 method.methodSignature().constData(), receiver->metaObject()->className());
3544 if (!QMetaObjectPrivate::disconnect(sender, signal_index, signal.mobj, receiver, method_index,
nullptr))
3547 if (!signal.isValid()) {
3552 const_cast<QObject *>(sender)->disconnectNotify(signal);
3709 int signal_index,
const QMetaObject *smeta,
3710 const QObject *receiver,
int method_index,
3711 const QMetaObject *rmeta,
int type,
int *types)
3713 QObject *s =
const_cast<QObject *>(sender);
3714 QObject *r =
const_cast<QObject *>(receiver);
3716 int method_offset = rmeta ? rmeta->methodOffset() : 0;
3718 QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall :
nullptr;
3720 QOrderedMutexLocker locker(signalSlotLock(sender),
3721 signalSlotLock(receiver));
3723 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3724 if (type & Qt::UniqueConnection && scd) {
3725 if (scd->signalVectorCount() > signal_index) {
3726 const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
3728 int method_index_absolute = method_index + method_offset;
3731 if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute)
3733 c2 = c2->nextConnectionList.loadRelaxed();
3737 type &= ~Qt::UniqueConnection;
3739 const bool isSingleShot = type & Qt::SingleShotConnection;
3740 type &= ~Qt::SingleShotConnection;
3742 Q_ASSERT(type >= 0);
3743 Q_ASSERT(type <= 3);
3745 std::unique_ptr<QObjectPrivate::Connection> c{
new QObjectPrivate::Connection};
3747 c->signal_index = signal_index;
3748 c->receiver.storeRelaxed(r);
3749 QThreadData *td = r->d_func()->threadData.loadAcquire();
3751 c->receiverThreadData.storeRelaxed(td);
3752 c->method_relative = method_index;
3753 c->method_offset = method_offset;
3754 c->connectionType = type;
3755 c->isSlotObject =
false;
3756 c->argumentTypes.storeRelaxed(types);
3757 c->callFunction = callFunction;
3758 c->isSingleShot = isSingleShot;
3760 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
3763 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3764 if (smethod.isValid())
3765 s->connectNotify(smethod);
3843bool QMetaObjectPrivate::disconnect(
const QObject *sender,
3844 int signal_index,
const QMetaObject *smeta,
3845 const QObject *receiver,
int method_index,
void **slot,
3846 DisconnectType disconnectType)
3851 QObject *s =
const_cast<QObject *>(sender);
3853 QBasicMutex *senderMutex = signalSlotLock(sender);
3854 QMutexLocker locker(senderMutex);
3856 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3860 bool success =
false;
3863 QObjectPrivate::ConnectionDataPointer connections(scd);
3865 if (signal_index < 0) {
3867 if (!receiver && method_index < 0 && sender->d_func()->isSignalConnected(0)) {
3868 qWarning(
"QObject::disconnect: wildcard call disconnects from destroyed signal of"
3869 " %s::%s", sender->metaObject()->className(),
3870 sender->objectName().isEmpty()
3872 : sender->objectName().toLocal8Bit().data());
3875 for (
int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
3876 if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
3879 }
else if (signal_index < scd->signalVectorCount()) {
3880 if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
3887 scd->cleanOrphanedConnections(s);
3889 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3890 if (smethod.isValid())
3891 s->disconnectNotify(smethod);
3947void QMetaObject::connectSlotsByName(QObject *o)
3951 const QMetaObject *mo = o->metaObject();
3953 const QObjectList list =
3954 o->findChildren<QObject *>()
3958 for (
int i = 0; i < mo->methodCount(); ++i) {
3959 const QByteArray slotSignature = mo->method(i).methodSignature();
3960 const char *slot = slotSignature.constData();
3964 if (slot[0] !=
'o' || slot[1] !=
'n' || slot[2] !=
'_')
3968 bool foundIt =
false;
3969 for (
int j = 0; j < list.size(); ++j) {
3970 const QObject *co = list.at(j);
3971 const QByteArray coName = co->objectName().toLatin1();
3974 if (coName.isEmpty() || qstrncmp(slot + 3, coName.constData(), coName.size()) || slot[coName.size()+3] !=
'_')
3977 const char *signal = slot + coName.size() + 4;
3980 const QMetaObject *smeta;
3981 int sigIndex = co->d_func()->signalIndex(signal, &smeta);
3987 QList<QByteArray> compatibleSignals;
3988 const QMetaObject *smo = co->metaObject();
3989 int sigLen =
int(qstrlen(signal)) - 1;
3990 for (
int k = QMetaObjectPrivate::absoluteSignalCount(smo)-1; k >= 0; --k) {
3991 const QMetaMethod method = QMetaObjectPrivate::signal(smo, k);
3992 if (!qstrncmp(method.methodSignature().constData(), signal, sigLen)) {
3993 smeta = method.enclosingMetaObject();
3995 compatibleSignals.prepend(method.methodSignature());
3998 if (compatibleSignals.size() > 1)
3999 qCWarning(lcConnectSlotsByName) <<
"QMetaObject::connectSlotsByName: Connecting slot" << slot
4000 <<
"with the first of the following compatible signals:" << compatibleSignals;
4007 if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) {
4009 qCDebug(lcConnectSlotsByName,
"%s",
4010 msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData());
4020 while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
4022 }
else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
4024 qsizetype iParen = slotSignature.indexOf(
'(');
4025 qsizetype iLastUnderscore = slotSignature.lastIndexOf(
'_', iParen - 1);
4026 if (iLastUnderscore > 3)
4028 "QMetaObject::connectSlotsByName: No matching signal for %s", slot);
4162static void queued_activate(QObject *sender,
int signal, QObjectPrivate::Connection *c,
void **argv)
4164 const int *argumentTypes = c->argumentTypes.loadRelaxed();
4165 if (!argumentTypes) {
4166 QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
4167 argumentTypes = queuedConnectionTypes(m);
4169 argumentTypes = &DIRECT_CONNECTION_ONLY;
4170 if (!c->argumentTypes.testAndSetOrdered(
nullptr, argumentTypes)) {
4171 if (argumentTypes != &DIRECT_CONNECTION_ONLY)
4172 delete[] argumentTypes;
4173 argumentTypes = c->argumentTypes.loadRelaxed();
4176 if (argumentTypes == &DIRECT_CONNECTION_ONLY)
4179 while (argumentTypes[nargs - 1])
4182 QMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
4183 QObject *receiver = c->receiver.loadRelaxed();
4189 SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj :
nullptr };
4192 QVarLengthArray<
const QtPrivate::QMetaTypeInterface *, 16> argTypes;
4193 argTypes.reserve(nargs);
4194 argTypes.emplace_back(
nullptr);
4195 for (
int n = 1; n < nargs; ++n) {
4196 argTypes.emplace_back(QMetaType(argumentTypes[n - 1]).iface());
4199 auto ev = c->isSlotObject ?
4200 std::make_unique<QQueuedMetaCallEvent>(c->slotObj,
4201 sender, signal, nargs, argTypes.data(), argv) :
4202 std::make_unique<QQueuedMetaCallEvent>(c->method_offset, c->method_relative, c->callFunction,
4203 sender, signal, nargs, argTypes.data(), argv);
4205 if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) {
4210 if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
4216 QCoreApplication::postEvent(receiver, ev.release());
4220void doActivate(QObject *sender,
int signal_index,
void **argv)
4222 QObjectPrivate *sp = QObjectPrivate::get(sender);
4227 Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
4229 if (sp->isDeclarativeSignalConnected(signal_index)
4230 && QAbstractDeclarativeData::signalEmitted) {
4231 Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
4232 QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
4233 signal_index, argv);
4236 const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() :
nullptr;
4238 void *empty_argv[] = {
nullptr };
4242 if (!sp->maybeSignalConnected(signal_index)) {
4244 if (callbacks_enabled && signal_spy_set->signal_begin_callback !=
nullptr)
4245 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4246 if (callbacks_enabled && signal_spy_set->signal_end_callback !=
nullptr)
4247 signal_spy_set->signal_end_callback(sender, signal_index);
4251 if (callbacks_enabled && signal_spy_set->signal_begin_callback !=
nullptr)
4252 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4254 bool senderDeleted =
false;
4256 Q_ASSERT(sp->connections.loadRelaxed());
4257 QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadAcquire());
4258 QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();
4260 const QObjectPrivate::ConnectionList *list;
4261 if (signal_index < signalVector->count())
4262 list = &signalVector->at(signal_index);
4264 list = &signalVector->at(-1);
4266 Qt::HANDLE currentThreadId = QThread::currentThreadId();
4267 bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
4271 uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
4273 QObjectPrivate::Connection *c = list->first.loadRelaxed();
4278 QObject *
const receiver = c->receiver.loadRelaxed();
4282 QThreadData *td = c->receiverThreadData.loadRelaxed();
4286 bool receiverInSameThread;
4287 if (inSenderThread) {
4288 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4291 QMutexLocker lock(signalSlotLock(receiver));
4292 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4298 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
4299 || (c->connectionType == Qt::QueuedConnection)) {
4300 queued_activate(sender, signal_index, c, argv);
4302#if QT_CONFIG(thread)
4303 }
else if (c->connectionType == Qt::BlockingQueuedConnection) {
4304 if (receiverInSameThread) {
4305 qWarning(
"Qt: Dead lock detected while activating a BlockingQueuedConnection: "
4306 "Sender is %s(%p), receiver is %s(%p)",
4307 sender->metaObject()->className(), sender,
4308 receiver->metaObject()->className(), receiver);
4311 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4316 QMutexLocker locker(signalSlotLock(receiver));
4317 if (!c->isSingleShot && !c->receiver.loadAcquire())
4319 QMetaCallEvent *ev = c->isSlotObject ?
4320 new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &latch) :
4321 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
4322 sender, signal_index, argv, &latch);
4323 QCoreApplication::postEvent(receiver, ev);
4330 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4333 QObjectPrivate::Sender senderData(
4334 receiverInSameThread ? receiver :
nullptr, sender, signal_index,
4335 receiverInSameThread ? QObjectPrivate::get(receiver)->connections.loadAcquire() :
nullptr);
4337 if (c->isSlotObject) {
4338 SlotObjectGuard obj{c->slotObj};
4341 Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
4342 obj->call(receiver, argv);
4344 }
else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
4346 const int method_relative = c->method_relative;
4347 const auto callFunction = c->callFunction;
4348 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
4349 if (callbacks_enabled && signal_spy_set->slot_begin_callback !=
nullptr)
4350 signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
4353 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
4354 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
4357 if (callbacks_enabled && signal_spy_set->slot_end_callback !=
nullptr)
4358 signal_spy_set->slot_end_callback(receiver, methodIndex);
4360 const int method = c->method_relative + c->method_offset;
4362 if (callbacks_enabled && signal_spy_set->slot_begin_callback !=
nullptr) {
4363 signal_spy_set->slot_begin_callback(receiver, method, argv);
4367 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
4368 QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
4371 if (callbacks_enabled && signal_spy_set->slot_end_callback !=
nullptr)
4372 signal_spy_set->slot_end_callback(receiver, method);
4374 }
while ((c = c->nextConnectionList.loadRelaxed()) !=
nullptr && c->id <= highestConnectionId);
4376 }
while (list != &signalVector->at(-1) &&
4378 ((list = &signalVector->at(-1)),
true));
4380 if (connections->currentConnectionId.loadRelaxed() == 0)
4381 senderDeleted =
true;
4383 if (!senderDeleted) {
4384 sp->connections.loadAcquire()->cleanOrphanedConnections(sender);
4386 if (callbacks_enabled && signal_spy_set->signal_end_callback !=
nullptr)
4387 signal_spy_set->signal_end_callback(sender, signal_index);
4625void QObject::dumpObjectInfo()
const
4627 qDebug(
"OBJECT %s::%s", metaObject()->className(),
4628 objectName().isEmpty() ?
"unnamed" : objectName().toLocal8Bit().data());
4631 QMutexLocker locker(signalSlotLock(
this));
4634 qDebug(
" SIGNALS OUT");
4636 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
4637 if (cd && cd->signalVectorCount() > 0) {
4638 QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
4639 for (
int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
4640 const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
4643 const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index);
4644 qDebug(
" signal: %s", signal.methodSignature().constData());
4648 if (!c->receiver.loadRelaxed()) {
4649 qDebug(
" <Disconnected receiver>");
4650 c = c->nextConnectionList.loadRelaxed();
4653 if (c->isSlotObject) {
4654 qDebug(
" <functor or function pointer>");
4655 c = c->nextConnectionList.loadRelaxed();
4658 const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
4659 const QMetaMethod method = receiverMetaObject->method(c->method());
4660 qDebug(
" --> %s::%s %s",
4661 receiverMetaObject->className(),
4662 c->receiver.loadRelaxed()->objectName().isEmpty() ?
"unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
4663 method.methodSignature().constData());
4664 c = c->nextConnectionList.loadRelaxed();
4668 qDebug(
" <None>" );
4672 qDebug(
" SIGNALS IN");
4674 if (cd && cd->senders) {
4675 for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
4676 QByteArray slotName = QByteArrayLiteral(
"<unknown>");
4677 if (!s->isSlotObject) {
4678 const QMetaMethod slot = metaObject()->method(s->method());
4679 slotName = slot.methodSignature();
4681 qDebug(
" <-- %s::%s %s",
4682 s->sender->metaObject()->className(),
4683 s->sender->objectName().isEmpty() ?
"unnamed" : qPrintable(s->sender->objectName()),
4684 slotName.constData());
5475QMetaObject::Connection QObjectPrivate::connectImpl(
const QObject *sender,
int signal_index,
5476 const QObject *receiver,
void **slot,
5477 QtPrivate::QSlotObjectBase *slotObjRaw,
int type,
5478 const int *types,
const QMetaObject *senderMetaObject)
5480 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5482 if (!sender || !receiver || !slotObj || !senderMetaObject) {
5483 connectWarning(sender, senderMetaObject, receiver,
"invalid nullptr parameter");
5484 return QMetaObject::Connection();
5487 if (type & Qt::UniqueConnection && !slot) {
5488 connectWarning(sender, senderMetaObject, receiver,
"unique connections require a pointer to member function of a QObject subclass");
5489 return QMetaObject::Connection();
5492 QObject *s =
const_cast<QObject *>(sender);
5493 QObject *r =
const_cast<QObject *>(receiver);
5495 QOrderedMutexLocker locker(signalSlotLock(sender),
5496 signalSlotLock(receiver));
5498 if (type & Qt::UniqueConnection && slot) {
5499 QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
5500 if (connections && connections->signalVectorCount() > signal_index) {
5501 const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
5504 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot))
5505 return QMetaObject::Connection();
5506 c2 = c2->nextConnectionList.loadRelaxed();
5510 type &= ~Qt::UniqueConnection;
5512 const bool isSingleShot = type & Qt::SingleShotConnection;
5513 type &= ~Qt::SingleShotConnection;
5515 Q_ASSERT(type >= 0);
5516 Q_ASSERT(type <= 3);
5518 std::unique_ptr<QObjectPrivate::Connection> c{
new QObjectPrivate::Connection};
5520 c->signal_index = signal_index;
5521 QThreadData *td = r->d_func()->threadData.loadAcquire();
5523 c->receiverThreadData.storeRelaxed(td);
5524 c->receiver.storeRelaxed(r);
5525 c->connectionType = type;
5526 c->isSlotObject =
true;
5527 c->slotObj = slotObj.release();
5529 c->argumentTypes.storeRelaxed(types);
5530 c->ownArgumentTypes =
false;
5532 c->isSingleShot = isSingleShot;
5534 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
5535 QMetaObject::Connection ret(c.release());
5538 QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
5539 Q_ASSERT(method.isValid());
5540 s->connectNotify(method);