380 std::unique_lock<QBasicMutex> lock(*senderMutex, std::defer_lock_t{});
381 if (lockPolicy == NeedToLock)
383 if (ref.loadAcquire() > 1)
389 c = orphaned.exchange(
nullptr, std::memory_order_relaxed);
393 if (lockPolicy == AlreadyLockedAndTemporarilyReleasingLock) {
394 senderMutex->unlock();
403inline void QObjectPrivate::ConnectionData::deleteOrphaned(TaggedSignalVector o)
406 TaggedSignalVector next =
nullptr;
407 if (SignalVector *v =
static_cast<SignalVector *>(o)) {
408 next = v->nextInOrphanList;
411 QObjectPrivate::Connection *c =
static_cast<Connection *>(o);
412 next = c->nextInOrphanList;
413 Q_ASSERT(!c->receiver.loadRelaxed());
423
424
425
426
427
428bool QObjectPrivate::isSignalConnected(uint signalIndex,
bool checkDeclarative)
const
430 if (checkDeclarative && isDeclarativeSignalConnected(signalIndex))
433 ConnectionData *cd = connections.loadAcquire();
436 SignalVector *signalVector = cd->signalVector.loadRelaxed();
440 if (signalVector->at(-1).first.loadRelaxed())
443 if (signalIndex < uint(cd->signalVectorCount())) {
444 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadRelaxed();
446 if (c->receiver.loadRelaxed())
448 c = c->nextConnectionList.loadRelaxed();
454bool QObjectPrivate::maybeSignalConnected(uint signalIndex)
const
456 ConnectionData *cd = connections.loadAcquire();
459 SignalVector *signalVector = cd->signalVector.loadRelaxed();
463 if (signalVector->at(-1).first.loadAcquire())
466 if (signalIndex < uint(cd->signalVectorCount())) {
467 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadAcquire();
473void QObjectPrivate::reinitBindingStorageAfterThreadMove()
475 bindingStorage.reinitAfterThreadMove();
476 for (
int i = 0; i < children.size(); ++i)
477 children[i]->d_func()->reinitBindingStorageAfterThreadMove();
481
482
483QAbstractMetaCallEvent::~QAbstractMetaCallEvent()
492
493
494
495
496
497QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative,
498 QObjectPrivate::StaticMetaCallFunction callFunction,
499 const QObject *sender,
int signalId,
500 void **args, QLatch *latch)
501 : QAbstractMetaCallEvent(sender, signalId, latch),
502 d{
nullptr, args, callFunction, 0, method_offset, method_relative}
507
508
509
510
511
512QMetaCallEvent::QMetaCallEvent(QtPrivate::QSlotObjectBase *slotO,
513 const QObject *sender,
int signalId,
514 void **args, QLatch *latch)
515 : QAbstractMetaCallEvent(sender, signalId, latch),
516 d{QtPrivate::SlotObjUniquePtr{slotO}, args,
nullptr, 0, 0, ushort(-1)}
523
524
525
526
527
528QMetaCallEvent::QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotO,
529 const QObject *sender,
int signalId,
530 void **args, QLatch *latch)
531 : QAbstractMetaCallEvent(sender, signalId, latch),
532 d{std::move(slotO), args,
nullptr, 0, 0, ushort(-1)}
537
538
539QMetaCallEvent::QMetaCallEvent(
const QObject *sender,
int signalId, Data &&data)
540 : QAbstractMetaCallEvent(sender, signalId),
546
547
548void QMetaCallEvent::placeMetaCall(QObject *object)
551 d.slotObj_->call(object, d.args_);
552 }
else if (d.callFunction_ && d.method_offset_ <= object->metaObject()->methodOffset()) {
553 d.callFunction_(object, QMetaObject::InvokeMetaMethod, d.method_relative_, d.args_);
555 QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod,
556 d.method_offset_ + d.method_relative_, d.args_);
561
562
563
564
565QQueuedMetaCallEvent::QQueuedMetaCallEvent(ushort method_offset, ushort method_relative,
566 QObjectPrivate::StaticMetaCallFunction callFunction,
567 const QObject *sender,
int signalId,
int argCount,
568 const QtPrivate::QMetaTypeInterface *
const *argTypes,
569 const void *
const *argValues)
570 : QMetaCallEvent(sender, signalId, {
nullptr,
nullptr, callFunction, argCount,
571 method_offset, method_relative}),
574 copyArgValues(argCount, argTypes, argValues);
578
579
580
581
582QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
583 const QObject *sender,
int signalId,
int argCount,
584 const QtPrivate::QMetaTypeInterface *
const *argTypes,
585 const void *
const *argValues)
586 : QMetaCallEvent(sender, signalId, {QtPrivate::SlotObjUniquePtr(slotObj),
nullptr,
nullptr, argCount,
592 copyArgValues(argCount, argTypes, argValues);
596
597
598
599
600QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,
601 const QObject *sender,
int signalId,
int argCount,
602 const QtPrivate::QMetaTypeInterface *
const *argTypes,
603 const void *
const *argValues)
604 : QMetaCallEvent(sender, signalId, {std::move(slotObj),
nullptr,
nullptr, argCount,
608 copyArgValues(argCount, argTypes, argValues);
612
613
614QQueuedMetaCallEvent::~QQueuedMetaCallEvent()
616 const QMetaType *t =
reinterpret_cast<QMetaType *>(d.args_ + d.nargs_);
617 int inplaceIndex = 0;
618 for (
int i = 0; i < d.nargs_; ++i) {
619 if (t[i].isValid() && d.args_[i]) {
620 if (typeFitsInPlace(t[i]) && inplaceIndex < InplaceValuesCapacity) {
622 void *where = &valuesPrealloc_[inplaceIndex++].storage;
623 t[i].destruct(where);
626 t[i].destroy(d.args_[i]);
631 if (
static_cast<
void *>(d.args_) != prealloc_)
632 QtPrivate::sizedFree(d.args_, d.nargs_, PtrAndTypeSize);
637
638
639inline void QQueuedMetaCallEvent::allocArgs()
644 void *
const memory = d.nargs_ * PtrAndTypeSize >
sizeof(prealloc_) ?
645 calloc(d.nargs_, PtrAndTypeSize) : prealloc_;
648 d.args_ =
static_cast<
void **>(memory);
652
653
654inline void QQueuedMetaCallEvent::copyArgValues(
int argCount,
const QtPrivate::QMetaTypeInterface *
const *argTypes,
655 const void *
const *argValues)
658 void **args = d.args_;
659 QMetaType *types =
reinterpret_cast<QMetaType *>(d.args_ + d.nargs_);
660 int inplaceIndex = 0;
663 types[0] = QMetaType();
668 for (
int n = 1; n < argCount; ++n) {
669 types[n] = QMetaType(argTypes[n]);
670 if (typeFitsInPlace(types[n]) && inplaceIndex < InplaceValuesCapacity) {
672 void *where = &valuesPrealloc_[inplaceIndex++].storage;
673 types[n].construct(where, argValues[n]);
677 args[n] = types[n].create(argValues[n]);
683
684
685inline bool QQueuedMetaCallEvent::typeFitsInPlace(
const QMetaType type)
687 return (q20::cmp_less_equal(type.sizeOf(),
sizeof(ArgValueStorage)) &&
688 q20::cmp_less_equal(type.alignOf(),
alignof(ArgValueStorage)));
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
716
717
718
719
722
723
724
725
726
729
730
731
732
733
734
737
738
739
740
741
742
743
744
745
746
747
750
751
752
753
754
755
758
759
760
761
762
763
764
767
768
769
770
771
772
773
774
775
778
779
780
781
782
783
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
933
934
935
936
937
940
941
948 if (parent && parentThreadData != currentThreadData) {
949 QThread *parentThread = parentThreadData->thread.loadAcquire();
950 QThread *currentThread = currentThreadData->thread.loadAcquire();
951 qWarning(
"QObject: Cannot create children for a parent that is in a different thread.\n"
952 "(Parent is %s(%p), parent's thread is %s(%p), current thread is %s(%p)",
953 parent->metaObject()->className(),
955 parentThread ? parentThread->metaObject()->className() :
"QThread",
957 currentThread ? currentThread->metaObject()->className() :
"QThread",
965
966
967
968
969
970
971
972
973
974
975
976
977
979QObject::QObject(QObject *parent)
980 : QObject(*
new QObjectPrivate, parent)
985
986
987QObject::QObject(QObjectPrivate &dd, QObject *parent)
990 Q_ASSERT_X(
this != parent, Q_FUNC_INFO,
"Cannot parent a QObject to itself");
994 auto threadData = (parent && !parent->thread()) ? parent->d_func()->threadData.loadRelaxed() : QThreadData::current();
996 d->threadData.storeRelaxed(threadData);
999 if (!check_parent_thread(parent, parent ? parent->d_func()->threadData.loadRelaxed() :
nullptr, threadData))
1001 if (d->willBeWidget) {
1004 d->parent->d_func()->children.append(
this);
1011 threadData->deref();
1015 if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
1016 reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(
this);
1017 Q_TRACE(QObject_ctor,
this);
1052 d->wasDeleted =
true;
1055 if (!d->bindingStorage.isValid()) {
1058 if (QThread *ownThread = thread()) {
1059 auto *privThread =
static_cast<QThreadPrivate *>(
1060 QObjectPrivate::get(ownThread));
1061 privThread->removeObjectWithPendingBindingStatusChange(
this);
1067 d->clearBindingStorage();
1069 QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.loadRelaxed();
1070 if (sharedRefcount) {
1071 if (sharedRefcount->strongref.loadRelaxed() > 0) {
1072 qWarning(
"QObject: shared QObject was deleted directly. The program is malformed and may crash.");
1077 sharedRefcount->strongref.storeRelaxed(0);
1078 if (!sharedRefcount->weakref.deref())
1079 delete sharedRefcount;
1082 if (!d->wasWidget && d->isSignalConnected(0)) {
1083 emit destroyed(
this);
1086 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::destroyed)
1087 QAbstractDeclarativeData::destroyed(d->declarativeData,
this);
1089 QObjectPrivate::ConnectionData *cd = d->connections.loadAcquire();
1091 if (cd->currentSender) {
1092 cd->currentSender->receiverDeleted();
1093 cd->currentSender =
nullptr;
1096 QBasicMutex *signalSlotMutex = signalSlotLock(
this);
1097 QMutexLocker locker(signalSlotMutex);
1100 int receiverCount = cd->signalVectorCount();
1101 for (
int signal = -1; signal < receiverCount; ++signal) {
1102 QObjectPrivate::ConnectionList &connectionList = cd->connectionsForSignal(signal);
1104 while (QObjectPrivate::Connection *c = connectionList.first.loadRelaxed()) {
1105 Q_ASSERT(c->receiver.loadAcquire());
1107 QBasicMutex *m = signalSlotLock(c->receiver.loadRelaxed());
1108 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1109 if (c == connectionList.first.loadAcquire() && c->receiver.loadAcquire()) {
1110 cd->removeConnection(c);
1111 Q_ASSERT(connectionList.first.loadRelaxed() != c);
1119
1120 while (QObjectPrivate::Connection *node = cd->senders) {
1121 Q_ASSERT(node->receiver.loadAcquire());
1122 QObject *sender = node->sender;
1126 sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), node->signal_index));
1127 QBasicMutex *m = signalSlotLock(sender);
1128 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1130 if (node != cd->senders) {
1132 Q_ASSERT(needToUnlock);
1137 QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections.loadRelaxed();
1138 Q_ASSERT(senderData);
1140 QtPrivate::QSlotObjectBase *slotObj =
nullptr;
1141 if (node->isSlotObject) {
1142 slotObj = node->slotObj;
1143 node->isSlotObject =
false;
1146 senderData->removeConnection(node);
1148
1149
1150
1151
1152
1153
1154
1155 const bool locksAreTheSame = signalSlotMutex == m;
1156 if (!locksAreTheSame)
1158 senderData->cleanOrphanedConnections(
1160 QObjectPrivate::ConnectionData::AlreadyLockedAndTemporarilyReleasingLock
1165 if (locksAreTheSame)
1168 slotObj->destroyIfLastRef();
1174 cd->currentConnectionId.storeRelaxed(0);
1176 if (cd && !cd->ref.deref())
1178 d->connections.storeRelaxed(
nullptr);
1180 if (!d->children.isEmpty())
1181 d->deleteChildren();
1183 if (Q_UNLIKELY(qtHookData[QHooks::RemoveQObject]))
1184 reinterpret_cast<QHooks::RemoveQObjectCallback>(qtHookData[QHooks::RemoveQObject])(
this);
1186 Q_TRACE(QObject_dtor,
this);
1189 d->setParent_helper(
nullptr);
1454bool QObject::event(QEvent *e)
1456 switch (e->type()) {
1458 timerEvent((QTimerEvent *)e);
1461 case QEvent::ChildAdded:
1462 case QEvent::ChildPolished:
1463 case QEvent::ChildRemoved:
1464 childEvent((QChildEvent *)e);
1467 case QEvent::DeferredDelete:
1471 case QEvent::MetaCall:
1473 QAbstractMetaCallEvent *mce =
static_cast<QAbstractMetaCallEvent*>(e);
1475 QObjectPrivate::ConnectionData *connections = d_func()->connections.loadAcquire();
1477 QMutexLocker locker(signalSlotLock(
this));
1478 d_func()->ensureConnectionData();
1479 connections = d_func()->connections.loadRelaxed();
1481 QObjectPrivate::Sender sender(
this,
const_cast<QObject*>(mce->sender()), mce->signalId(), connections);
1483 mce->placeMetaCall(
this);
1487 case QEvent::ThreadChange: {
1489 QThreadData *threadData = d->threadData.loadRelaxed();
1490 QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
1491 if (eventDispatcher) {
1492 QList<QAbstractEventDispatcher::TimerInfoV2> timers = eventDispatcher->timersForObject(
this);
1493 if (!timers.isEmpty()) {
1494 const bool res = eventDispatcher->unregisterTimers(
this);
1496 Q_ASSERT_X(res, Q_FUNC_INFO,
1497 "QAbstractEventDispatcher::unregisterTimers() returned false,"
1498 " but there are timers associated with this object.");
1499 auto reRegisterTimers = [
this, timers = std::move(timers)]() {
1500 QAbstractEventDispatcher *eventDispatcher =
1501 d_func()->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
1502 for (
const auto &ti : timers)
1503 eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType,
this);
1505 QMetaObject::invokeMethod(
this, std::move(reRegisterTimers), Qt::QueuedConnection);
1512 if (e->type() >= QEvent::User) {
1709bool QObject::moveToThread(QThread *targetThread QT6_IMPL_NEW_OVERLOAD_TAIL)
1713 if (d->threadData.loadRelaxed()->thread.loadAcquire() == targetThread) {
1718 if (d->parent !=
nullptr) {
1719 qWarning(
"QObject::moveToThread: Cannot move objects with a parent");
1723 qWarning(
"QObject::moveToThread: Widgets cannot be moved to a new thread");
1726 if (!d->bindingStorage.isEmpty()) {
1727 qWarning(
"QObject::moveToThread: Can not move objects that contain bindings or are used in bindings to a new thread.");
1731 QThreadData *currentData = QThreadData::current();
1732 QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) :
nullptr;
1733 QThreadData *thisThreadData = d->threadData.loadAcquire();
1734 if (!thisThreadData->thread.loadRelaxed() && currentData == targetData) {
1736 currentData = thisThreadData;
1737 }
else if (thisThreadData != currentData) {
1738 qWarning(
"QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
1739 "Cannot move to target thread (%p)\n",
1740 currentData->thread.loadRelaxed(), thisThreadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() :
nullptr);
1743 qWarning(
"You might be loading two sets of Qt binaries into the same process. "
1744 "Check that all plugins are compiled against the right Qt binaries. Export "
1745 "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.");
1752 d->moveToThread_helper();
1755 targetData =
new QThreadData(0);
1758 QMutexLocker l(signalSlotLock(
this));
1760 QOrderedMutexLocker locker(¤tData->postEventList.mutex,
1761 &targetData->postEventList.mutex);
1767 auto threadPrivate = targetThread
1768 ?
static_cast<QThreadPrivate *>(QThreadPrivate::get(targetThread))
1770 QBindingStatus *bindingStatus = threadPrivate
1771 ? threadPrivate->bindingStatus()
1773 if (threadPrivate && !bindingStatus) {
1774 bindingStatus = threadPrivate->addObjectWithPendingBindingStatusChange(
this);
1776 d_func()->setThreadData_helper(currentData, targetData, bindingStatus);
1781 currentData->deref();
1797void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status)
1803 this->bindingStorage.bindingStatus = status;
1807 qsizetype eventsMoved = 0;
1808 for (qsizetype i = 0; i < currentData->postEventList.size(); ++i) {
1809 const QPostEvent &pe = currentData->postEventList.at(i);
1812 if (pe.receiver == q) {
1814 targetData->postEventList.addEvent(pe);
1815 const_cast<QPostEvent &>(pe).event =
nullptr;
1819 if (eventsMoved > 0 && targetData->hasEventDispatcher()) {
1820 targetData->canWait =
false;
1821 targetData->eventDispatcher.loadRelaxed()->wakeUp();
1825 ConnectionData *cd = connections.loadAcquire();
1827 if (cd->currentSender) {
1828 cd->currentSender->receiverDeleted();
1829 cd->currentSender =
nullptr;
1834 auto *c = cd->senders;
1836 QObject *r = c->receiver.loadRelaxed();
1840 QThreadData *old = c->receiverThreadData.loadRelaxed();
1843 c->receiverThreadData.storeRelaxed(targetData);
1853 threadData.loadRelaxed()->deref();
1856 threadData.storeRelease(targetData);
1858 for (
int i = 0; i < children.size(); ++i) {
1859 QObject *child = children.at(i);
1860 child->d_func()->setThreadData_helper(currentData, targetData, status);
2290void QObjectPrivate::setParent_helper(QObject *o)
2293 Q_ASSERT_X(q != o, Q_FUNC_INFO,
"Cannot parent a QObject to itself");
2295 const auto checkForParentChildLoops = qScopeGuard([&](){
2299 if (++depth == CheckForParentChildLoopsWarnDepth) {
2300 qWarning(
"QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
2301 "this is undefined behavior",
2302 q, q->metaObject()->className(), qPrintable(q->objectName()));
2313 QObjectPrivate *parentD = parent->d_func();
2314 if (parentD->isDeletingChildren && wasDeleted
2315 && parentD->currentChildBeingDeleted == q) {
2319 const qsizetype index = parentD->children.indexOf(q);
2322 }
else if (parentD->isDeletingChildren) {
2323 parentD->children[index] =
nullptr;
2325 parentD->children.removeAt(index);
2326 if (sendChildEvents && parentD->receiveChildEvents) {
2327 QChildEvent e(QEvent::ChildRemoved, q);
2328 QCoreApplication::sendEvent(parent, &e);
2334 if (receiveParentEvents) {
2335 Q_ASSERT(!isWidget);
2336 QEvent e(QEvent::ParentAboutToChange);
2337 QCoreApplication::sendEvent(q, &e);
2344 if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) {
2345 qWarning(
"QObject::setParent: Cannot set parent, new parent is in a different thread");
2349 parent->d_func()->children.append(q);
2350 if (sendChildEvents && parent->d_func()->receiveChildEvents) {
2352 QChildEvent e(QEvent::ChildAdded, q);
2353 QCoreApplication::sendEvent(parent, &e);
2358 if (receiveParentEvents) {
2359 Q_ASSERT(!isWidget);
2360 QEvent e(QEvent::ParentChange);
2361 QCoreApplication::sendEvent(q, &e);
3085QMetaObject::Connection QObject::connect(
const QObject *sender,
const char *signal,
3086 const QObject *receiver,
const char *method,
3087 Qt::ConnectionType type)
3089 if (sender ==
nullptr || receiver ==
nullptr || signal ==
nullptr || method ==
nullptr) {
3090 qCWarning(lcConnect,
"QObject::connect: Cannot connect %s::%s to %s::%s",
3091 sender ? sender->metaObject()->className() :
"(nullptr)",
3092 (signal && *signal) ? signal + 1 :
"(nullptr)",
3093 receiver ? receiver->metaObject()->className() :
"(nullptr)",
3094 (method && *method) ? method + 1 :
"(nullptr)");
3095 return QMetaObject::Connection(
nullptr);
3098 if (!check_signal_macro(sender, signal,
"connect",
"bind"))
3099 return QMetaObject::Connection(
nullptr);
3101 int membcode = extract_code(method);
3102 if (!check_method_code(membcode, receiver, method,
"connect"))
3103 return QMetaObject::Connection(
nullptr);
3105 QByteArray pinnedSignal;
3106 const QMetaObject *smeta = sender->metaObject();
3107 const char *signal_arg = signal;
3109 QByteArrayView signalView{signal};
3110 QArgumentTypeArray signalTypes;
3111 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3112 QByteArrayView signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3113 int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3114 if (signal_index < 0) {
3116 pinnedSignal = QMetaObjectPrivate::normalizedSignature(signalView);
3117 signalView = pinnedSignal;
3119 signalTypes.clear();
3120 signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3121 smeta = sender->metaObject();
3122 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3124 if (signal_index < 0) {
3125 err_method_notfound(sender, signal_arg,
"connect");
3126 err_info_about_objects(
"connect", sender, receiver);
3127 return QMetaObject::Connection(
nullptr);
3129 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3130 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3132 QByteArray pinnedMethod;
3133 const char *method_arg = method;
3135 QByteArrayView methodView{method};
3137 QArgumentTypeArray methodTypes;
3138 QByteArrayView methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3139 const QMetaObject *rmeta = receiver->metaObject();
3140 int method_index_relative = -1;
3141 Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
3144 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3145 &rmeta, methodName, methodTypes);
3148 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3149 &rmeta, methodName, methodTypes);
3153 if (method_index_relative < 0) {
3155 pinnedMethod = QMetaObjectPrivate::normalizedSignature(methodView);
3156 methodView = pinnedMethod;
3158 methodTypes.clear();
3159 methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3161 rmeta = receiver->metaObject();
3164 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3165 &rmeta, methodName, methodTypes);
3168 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3169 &rmeta, methodName, methodTypes);
3174 if (method_index_relative < 0) {
3175 err_method_notfound(receiver, method_arg,
"connect");
3176 err_info_about_objects(
"connect", sender, receiver);
3177 return QMetaObject::Connection(
nullptr);
3180 if (!QMetaObjectPrivate::checkConnectArgs(signalTypes, methodTypes)) {
3182 "QObject::connect: Incompatible sender/receiver arguments"
3183 "\n %s::%s --> %s::%s",
3184 sender->metaObject()->className(), signalView.constData(),
3185 receiver->metaObject()->className(), methodView.constData());
3186 return QMetaObject::Connection(
nullptr);
3191 int *types =
nullptr;
3192 if (type == Qt::QueuedConnection && !(types = queuedConnectionTypes(signalTypes))) {
3193 return QMetaObject::Connection(
nullptr);
3196 QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
3198 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3199 check_and_warn_compat(smeta, smethod, rmeta, rmethod);
3202#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
3203 check_and_warn_non_slot(
"connect", method, membcode, rmeta, rmethod);
3206 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3207 sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
3231QMetaObject::Connection QObject::connect(
const QObject *sender,
const QMetaMethod &signal,
3232 const QObject *receiver,
const QMetaMethod &method,
3233 Qt::ConnectionType type)
3235 if (sender ==
nullptr
3236 || receiver ==
nullptr
3237 || signal.methodType() != QMetaMethod::Signal
3238 || method.methodType() == QMetaMethod::Constructor) {
3239 qCWarning(lcConnect,
"QObject::connect: Cannot connect %s::%s to %s::%s",
3240 sender ? sender->metaObject()->className() :
"(nullptr)",
3241 signal.methodSignature().constData(),
3242 receiver ? receiver->metaObject()->className() :
"(nullptr)",
3243 method.methodSignature().constData());
3244 return QMetaObject::Connection(
nullptr);
3251 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3252 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3255 const QMetaObject *smeta = sender->metaObject();
3256 const QMetaObject *rmeta = receiver->metaObject();
3257 if (signal_index == -1) {
3258 qCWarning(lcConnect,
"QObject::connect: Can't find signal %s on instance of class %s",
3259 signal.methodSignature().constData(), smeta->className());
3260 return QMetaObject::Connection(
nullptr);
3262 if (method_index == -1) {
3263 qCWarning(lcConnect,
"QObject::connect: Can't find method %s on instance of class %s",
3264 method.methodSignature().constData(), rmeta->className());
3265 return QMetaObject::Connection(
nullptr);
3268 if (!QMetaObject::checkConnectArgs(signal.methodSignature().constData(),
3269 method.methodSignature().constData())) {
3271 "QObject::connect: Incompatible sender/receiver arguments"
3272 "\n %s::%s --> %s::%s",
3273 smeta->className(), signal.methodSignature().constData(), rmeta->className(),
3274 method.methodSignature().constData());
3275 return QMetaObject::Connection(
nullptr);
3278 int *types =
nullptr;
3279 if ((type == Qt::QueuedConnection) && !(types = queuedConnectionTypes(signal)))
3280 return QMetaObject::Connection(
nullptr);
3283 check_and_warn_compat(smeta, signal, rmeta, method);
3285 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3286 sender, signal_index, signal.enclosingMetaObject(), receiver, method_index,
nullptr, type, types));
3371bool QObject::disconnect(
const QObject *sender,
const char *signal,
3372 const QObject *receiver,
const char *method)
3374 if (sender ==
nullptr || (receiver ==
nullptr && method !=
nullptr)) {
3375 qCWarning(lcConnect,
"QObject::disconnect: Unexpected nullptr parameter");
3379 const char *signal_arg = signal;
3381 if (!check_signal_macro(sender, signal,
"disconnect",
"unbind"))
3386 const char *method_arg = method;
3389 membcode = extract_code(method);
3390 if (!check_method_code(membcode, receiver, method,
"disconnect"))
3395 QByteArray pinnedSignal;
3396 const QMetaObject *smeta = sender->metaObject();
3397 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3398 int signal_index = -1;
3399 QByteArrayView signalName;
3400 QArgumentTypeArray signalTypes;
3402 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3403 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3404 if (signal_index == -1) {
3405 pinnedSignal = QMetaObject::normalizedSignature(signal);
3406 signal = pinnedSignal.constData();
3407 signalTypes.clear();
3408 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3409 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3412 if (signal_index == -1) {
3413 err_method_notfound(sender, signal_arg,
"disconnect");
3414 err_info_about_objects(
"disconnect", sender, receiver);
3419 auto getMethodIndex = [](
int code,
const QMetaObject *mo, QByteArrayView name,
3420 const QArgumentTypeArray &types) {
3423 return QMetaObjectPrivate::indexOfSlot(mo, name, types);
3425 return QMetaObjectPrivate::indexOfSignal(mo, name, types);
3430 QByteArray pinnedMethod;
3431 const QMetaObject *rmeta = receiver ? receiver->metaObject() :
nullptr;
3432 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 7);
3433 int method_index = -1;
3434 QByteArrayView methodName;
3435 QArgumentTypeArray methodTypes;
3437 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3438 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3439 if (method_index == -1) {
3440 pinnedMethod = QMetaObject::normalizedSignature(method);
3441 method = pinnedMethod.constData();
3442 methodTypes.clear();
3443 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3444 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3446 if (method_index == -1) {
3447 err_method_notfound(receiver, method_arg,
"disconnect");
3448 err_info_about_objects(
"disconnect", sender, receiver);
3454
3455
3456
3461 if (smeta != sender->metaObject()) {
3462 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3465 if (signal_index < 0)
3467 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3468 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3472 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1,
nullptr);
3476 if (rmeta != receiver->metaObject())
3477 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3478 if (method_index >= 0) {
3479#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
3480 check_and_warn_non_slot(
"disconnect", method, membcode, rmeta,
3481 rmeta->method(method_index));
3483 while (method_index < rmeta->methodOffset())
3484 rmeta = rmeta->superClass();
3486 if (method_index < 0)
3488 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index,
nullptr);
3489 }
while ((rmeta = rmeta->superClass()));
3491 }
while (signal && (smeta = smeta->superClass()));
3495 const_cast<QObject *>(sender)->disconnectNotify(QMetaMethod());
3534bool QObject::disconnect(
const QObject *sender,
const QMetaMethod &signal,
3535 const QObject *receiver,
const QMetaMethod &method)
3537 if (sender ==
nullptr || (receiver ==
nullptr && method.mobj !=
nullptr)) {
3538 qCWarning(lcConnect,
"QObject::disconnect: Unexpected nullptr parameter");
3542 if (signal.methodType() != QMetaMethod::Signal) {
3543 qCWarning(lcConnect,
"QObject::%s: Attempt to %s non-signal %s::%s",
3544 "disconnect",
"unbind",
3545 sender->metaObject()->className(), signal.methodSignature().constData());
3550 if (method.methodType() == QMetaMethod::Constructor) {
3551 qCWarning(lcConnect,
"QObject::disconnect: cannot use constructor as argument %s::%s",
3552 receiver->metaObject()->className(), method.methodSignature().constData());
3561 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3562 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3566 if (signal.mobj && signal_index == -1) {
3567 qCWarning(lcConnect,
"QObject::disconnect: signal %s not found on class %s",
3568 signal.methodSignature().constData(), sender->metaObject()->className());
3572 if (receiver && method.mobj && method_index == -1) {
3573 qCWarning(lcConnect,
"QObject::disconnect: method %s not found on class %s",
3574 method.methodSignature().constData(), receiver->metaObject()->className());
3578 if (!QMetaObjectPrivate::disconnect(sender, signal_index, signal.mobj, receiver, method_index,
nullptr))
3581 if (!signal.isValid()) {
3586 const_cast<QObject *>(sender)->disconnectNotify(signal);
3743 int signal_index,
const QMetaObject *smeta,
3744 const QObject *receiver,
int method_index,
3745 const QMetaObject *rmeta,
int type,
int *types)
3747 QObject *s =
const_cast<QObject *>(sender);
3748 QObject *r =
const_cast<QObject *>(receiver);
3750 int method_offset = rmeta ? rmeta->methodOffset() : 0;
3752 QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall :
nullptr;
3754 QOrderedMutexLocker locker(signalSlotLock(sender),
3755 signalSlotLock(receiver));
3757 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3758 if (type & Qt::UniqueConnection && scd) {
3759 if (scd->signalVectorCount() > signal_index) {
3760 const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
3762 int method_index_absolute = method_index + method_offset;
3765 if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute)
3767 c2 = c2->nextConnectionList.loadRelaxed();
3771 type &= ~Qt::UniqueConnection;
3773 const bool isSingleShot = type & Qt::SingleShotConnection;
3774 type &= ~Qt::SingleShotConnection;
3776 Q_ASSERT(type >= 0);
3777 Q_ASSERT(type <= 3);
3779 std::unique_ptr<QObjectPrivate::Connection> c{
new QObjectPrivate::Connection};
3781 c->signal_index = signal_index;
3782 c->receiver.storeRelaxed(r);
3783 QThreadData *td = r->d_func()->threadData.loadAcquire();
3785 c->receiverThreadData.storeRelaxed(td);
3786 c->method_relative = method_index;
3787 c->method_offset = method_offset;
3788 c->connectionType = type;
3789 c->isSlotObject =
false;
3790 c->argumentTypes.storeRelaxed(types);
3791 c->callFunction = callFunction;
3792 c->isSingleShot = isSingleShot;
3794 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
3797 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3798 if (smethod.isValid())
3799 s->connectNotify(smethod);
3877bool QMetaObjectPrivate::disconnect(
const QObject *sender,
3878 int signal_index,
const QMetaObject *smeta,
3879 const QObject *receiver,
int method_index,
void **slot,
3880 DisconnectType disconnectType)
3885 QObject *s =
const_cast<QObject *>(sender);
3887 QBasicMutex *senderMutex = signalSlotLock(sender);
3888 QMutexLocker locker(senderMutex);
3890 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3894 bool success =
false;
3897 QObjectPrivate::ConnectionDataPointer connections(scd);
3899 if (signal_index < 0) {
3901 if (!receiver && method_index < 0 && sender->d_func()->isSignalConnected(0)) {
3902 qWarning(
"QObject::disconnect: wildcard call disconnects from destroyed signal of"
3903 " %s::%s", sender->metaObject()->className(),
3904 sender->objectName().isEmpty()
3906 : sender->objectName().toLocal8Bit().data());
3909 for (
int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
3910 if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
3913 }
else if (signal_index < scd->signalVectorCount()) {
3914 if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
3921 scd->cleanOrphanedConnections(s);
3923 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3924 if (smethod.isValid())
3925 s->disconnectNotify(smethod);
3981void QMetaObject::connectSlotsByName(QObject *o)
3985 const QMetaObject *mo = o->metaObject();
3987 const QObjectList list =
3988 o->findChildren<QObject *>()
3992 for (
int i = 0; i < mo->methodCount(); ++i) {
3993 const QByteArray slotSignature = mo->method(i).methodSignature();
3994 const char *slot = slotSignature.constData();
3998 if (slot[0] !=
'o' || slot[1] !=
'n' || slot[2] !=
'_')
4002 bool foundIt =
false;
4003 for (
int j = 0; j < list.size(); ++j) {
4004 const QObject *co = list.at(j);
4005 const QByteArray coName = co->objectName().toLatin1();
4008 if (coName.isEmpty() || qstrncmp(slot + 3, coName.constData(), coName.size()) || slot[coName.size()+3] !=
'_')
4011 const char *signal = slot + coName.size() + 4;
4014 const QMetaObject *smeta;
4015 int sigIndex = co->d_func()->signalIndex(signal, &smeta);
4021 QList<QByteArray> compatibleSignals;
4022 const QMetaObject *smo = co->metaObject();
4023 int sigLen =
int(qstrlen(signal)) - 1;
4024 for (
int k = QMetaObjectPrivate::absoluteSignalCount(smo)-1; k >= 0; --k) {
4025 const QMetaMethod method = QMetaObjectPrivate::signal(smo, k);
4026 if (!qstrncmp(method.methodSignature().constData(), signal, sigLen)) {
4027 smeta = method.enclosingMetaObject();
4029 compatibleSignals.prepend(method.methodSignature());
4032 if (compatibleSignals.size() > 1)
4033 qCWarning(lcConnectSlotsByName) <<
"QMetaObject::connectSlotsByName: Connecting slot" << slot
4034 <<
"with the first of the following compatible signals:" << compatibleSignals;
4041 if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) {
4043 qCDebug(lcConnectSlotsByName,
"%s",
4044 msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData());
4054 while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
4056 }
else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
4058 qsizetype iParen = slotSignature.indexOf(
'(');
4059 qsizetype iLastUnderscore = slotSignature.lastIndexOf(
'_', iParen - 1);
4060 if (iLastUnderscore > 3)
4062 "QMetaObject::connectSlotsByName: No matching signal for %s", slot);
4196static void queued_activate(QObject *sender,
int signal, QObjectPrivate::Connection *c,
void **argv)
4198 const int *argumentTypes = c->argumentTypes.loadRelaxed();
4199 if (!argumentTypes) {
4200 QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
4201 argumentTypes = queuedConnectionTypes(m);
4203 argumentTypes = &DIRECT_CONNECTION_ONLY;
4204 if (!c->argumentTypes.testAndSetOrdered(
nullptr, argumentTypes)) {
4205 if (argumentTypes != &DIRECT_CONNECTION_ONLY)
4206 delete[] argumentTypes;
4207 argumentTypes = c->argumentTypes.loadRelaxed();
4210 if (argumentTypes == &DIRECT_CONNECTION_ONLY)
4213 while (argumentTypes[nargs - 1])
4216 QMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
4217 QObject *receiver = c->receiver.loadRelaxed();
4223 SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj :
nullptr };
4226 QVarLengthArray<
const QtPrivate::QMetaTypeInterface *, 16> argTypes;
4227 argTypes.reserve(nargs);
4228 argTypes.emplace_back(
nullptr);
4229 for (
int n = 1; n < nargs; ++n) {
4230 argTypes.emplace_back(QMetaType(argumentTypes[n - 1]).iface());
4233 auto ev = c->isSlotObject ?
4234 std::make_unique<QQueuedMetaCallEvent>(c->slotObj,
4235 sender, signal, nargs, argTypes.data(), argv) :
4236 std::make_unique<QQueuedMetaCallEvent>(c->method_offset, c->method_relative, c->callFunction,
4237 sender, signal, nargs, argTypes.data(), argv);
4239 if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) {
4244 if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
4250 QCoreApplication::postEvent(receiver, ev.release());
4254void doActivate(QObject *sender,
int signal_index,
void **argv)
4256 QObjectPrivate *sp = QObjectPrivate::get(sender);
4261 Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
4263 if (sp->isDeclarativeSignalConnected(signal_index)
4264 && QAbstractDeclarativeData::signalEmitted) {
4265 Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
4266 QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
4267 signal_index, argv);
4270 const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() :
nullptr;
4272 void *empty_argv[] = {
nullptr };
4276 if (!sp->maybeSignalConnected(signal_index)) {
4278 if (callbacks_enabled && signal_spy_set->signal_begin_callback !=
nullptr)
4279 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4280 if (callbacks_enabled && signal_spy_set->signal_end_callback !=
nullptr)
4281 signal_spy_set->signal_end_callback(sender, signal_index);
4285 if (callbacks_enabled && signal_spy_set->signal_begin_callback !=
nullptr)
4286 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4288 bool senderDeleted =
false;
4290 Q_ASSERT(sp->connections.loadRelaxed());
4291 QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadAcquire());
4294 QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadAcquire();
4296 const QObjectPrivate::ConnectionList *list;
4297 if (signal_index < signalVector->count())
4298 list = &signalVector->at(signal_index);
4300 list = &signalVector->at(-1);
4302 Qt::HANDLE currentThreadId = QThread::currentThreadId();
4303 bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
4307 uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
4309 QObjectPrivate::Connection *c = list->first.loadAcquire();
4314 QObject *
const receiver = c->receiver.loadRelaxed();
4318 QThreadData *td = c->receiverThreadData.loadRelaxed();
4322 bool receiverInSameThread;
4323 if (inSenderThread) {
4324 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4327 QMutexLocker lock(signalSlotLock(receiver));
4328 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4334 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
4335 || (c->connectionType == Qt::QueuedConnection)) {
4336 queued_activate(sender, signal_index, c, argv);
4338#if QT_CONFIG(thread)
4339 }
else if (c->connectionType == Qt::BlockingQueuedConnection) {
4340 if (receiverInSameThread) {
4341 qWarning(
"Qt: Dead lock detected while activating a BlockingQueuedConnection: "
4342 "Sender is %s(%p), receiver is %s(%p)",
4343 sender->metaObject()->className(), sender,
4344 receiver->metaObject()->className(), receiver);
4347 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4352 QMutexLocker locker(signalSlotLock(receiver));
4353 if (!c->isSingleShot && !c->receiver.loadAcquire())
4355 QMetaCallEvent *ev = c->isSlotObject ?
4356 new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &latch) :
4357 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
4358 sender, signal_index, argv, &latch);
4359 QCoreApplication::postEvent(receiver, ev);
4366 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4369 QObjectPrivate::Sender senderData(
4370 receiverInSameThread ? receiver :
nullptr, sender, signal_index,
4371 receiverInSameThread ? QObjectPrivate::get(receiver)->connections.loadAcquire() :
nullptr);
4373 if (c->isSlotObject) {
4374 SlotObjectGuard obj{c->slotObj};
4377 Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
4378 obj->call(receiver, argv);
4380 }
else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
4382 const int method_relative = c->method_relative;
4383 const auto callFunction = c->callFunction;
4384 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
4385 if (callbacks_enabled && signal_spy_set->slot_begin_callback !=
nullptr)
4386 signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
4389 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
4390 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
4393 if (callbacks_enabled && signal_spy_set->slot_end_callback !=
nullptr)
4394 signal_spy_set->slot_end_callback(receiver, methodIndex);
4396 const int method = c->method_relative + c->method_offset;
4398 if (callbacks_enabled && signal_spy_set->slot_begin_callback !=
nullptr) {
4399 signal_spy_set->slot_begin_callback(receiver, method, argv);
4403 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
4404 QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
4407 if (callbacks_enabled && signal_spy_set->slot_end_callback !=
nullptr)
4408 signal_spy_set->slot_end_callback(receiver, method);
4410 }
while ((c = c->nextConnectionList.loadAcquire()) !=
nullptr && c->id.loadAcquire() <= highestConnectionId);
4412 }
while (list != &signalVector->at(-1) &&
4414 ((list = &signalVector->at(-1)),
true));
4416 if (connections->currentConnectionId.loadRelaxed() == 0)
4417 senderDeleted =
true;
4419 if (!senderDeleted) {
4420 sp->connections.loadAcquire()->cleanOrphanedConnections(sender);
4422 if (callbacks_enabled && signal_spy_set->signal_end_callback !=
nullptr)
4423 signal_spy_set->signal_end_callback(sender, signal_index);
4661void QObject::dumpObjectInfo()
const
4663 qDebug(
"OBJECT %s::%s", metaObject()->className(),
4664 objectName().isEmpty() ?
"unnamed" : objectName().toLocal8Bit().data());
4667 QMutexLocker locker(signalSlotLock(
this));
4670 qDebug(
" SIGNALS OUT");
4672 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
4673 if (cd && cd->signalVectorCount() > 0) {
4674 QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
4675 for (
int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
4676 const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
4679 const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index);
4680 qDebug(
" signal: %s", signal.methodSignature().constData());
4684 if (!c->receiver.loadRelaxed()) {
4685 qDebug(
" <Disconnected receiver>");
4686 c = c->nextConnectionList.loadRelaxed();
4689 if (c->isSlotObject) {
4690 qDebug(
" <functor or function pointer>");
4691 c = c->nextConnectionList.loadRelaxed();
4694 const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
4695 const QMetaMethod method = receiverMetaObject->method(c->method());
4696 qDebug(
" --> %s::%s %s",
4697 receiverMetaObject->className(),
4698 c->receiver.loadRelaxed()->objectName().isEmpty() ?
"unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
4699 method.methodSignature().constData());
4700 c = c->nextConnectionList.loadRelaxed();
4704 qDebug(
" <None>" );
4708 qDebug(
" SIGNALS IN");
4710 if (cd && cd->senders) {
4711 for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
4712 QByteArray slotName = QByteArrayLiteral(
"<unknown>");
4713 if (!s->isSlotObject) {
4714 const QMetaMethod slot = metaObject()->method(s->method());
4715 slotName = slot.methodSignature();
4717 qDebug(
" <-- %s::%s %s",
4718 s->sender->metaObject()->className(),
4719 s->sender->objectName().isEmpty() ?
"unnamed" : qPrintable(s->sender->objectName()),
4720 slotName.constData());
5510QMetaObject::Connection QObjectPrivate::connectImpl(
const QObject *sender,
int signal_index,
5511 const QObject *receiver,
void **slot,
5512 QtPrivate::QSlotObjectBase *slotObjRaw,
int type,
5513 const int *types,
const QMetaObject *senderMetaObject)
5515 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5517 if (!sender || !receiver || !slotObj || !senderMetaObject) {
5518 connectWarning(sender, senderMetaObject, receiver,
"invalid nullptr parameter");
5519 return QMetaObject::Connection();
5522 if (type & Qt::UniqueConnection && !slot) {
5523 connectWarning(sender, senderMetaObject, receiver,
"unique connections require a pointer to member function of a QObject subclass");
5524 return QMetaObject::Connection();
5527 QObject *s =
const_cast<QObject *>(sender);
5528 QObject *r =
const_cast<QObject *>(receiver);
5530 QOrderedMutexLocker locker(signalSlotLock(sender),
5531 signalSlotLock(receiver));
5533 if (type & Qt::UniqueConnection) {
5534 QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
5535 if (connections && connections->signalVectorCount() > signal_index) {
5536 const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
5539 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot))
5540 return QMetaObject::Connection();
5541 c2 = c2->nextConnectionList.loadRelaxed();
5545 type &= ~Qt::UniqueConnection;
5547 const bool isSingleShot = type & Qt::SingleShotConnection;
5548 type &= ~Qt::SingleShotConnection;
5550 Q_ASSERT(type >= 0);
5551 Q_ASSERT(type <= 3);
5553 std::unique_ptr<QObjectPrivate::Connection> c{
new QObjectPrivate::Connection};
5555 c->signal_index = signal_index;
5556 QThreadData *td = r->d_func()->threadData.loadAcquire();
5558 c->receiverThreadData.storeRelaxed(td);
5559 c->receiver.storeRelaxed(r);
5560 c->connectionType = type;
5561 c->isSlotObject =
true;
5562 c->slotObj = slotObj.release();
5564 c->argumentTypes.storeRelaxed(types);
5565 c->ownArgumentTypes =
false;
5567 c->isSingleShot = isSingleShot;
5569 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
5570 QMetaObject::Connection ret(c.release());
5573 QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
5574 Q_ASSERT(method.isValid());
5575 s->connectNotify(method);