380 QBasicMutex *senderMutex = signalSlotLock(sender);
381 TaggedSignalVector c =
nullptr;
383 std::unique_lock<QBasicMutex> lock(*senderMutex, std::defer_lock_t{});
384 if (lockPolicy == NeedToLock)
386 if (ref.loadAcquire() > 1)
392 c = orphaned.exchange(
nullptr, std::memory_order_relaxed);
396 if (lockPolicy == AlreadyLockedAndTemporarilyReleasingLock) {
397 senderMutex->unlock();
406inline void QObjectPrivate::ConnectionData::deleteOrphaned(TaggedSignalVector o)
409 TaggedSignalVector next =
nullptr;
410 if (SignalVector *v =
static_cast<SignalVector *>(o)) {
411 next = v->nextInOrphanList;
414 QObjectPrivate::Connection *c =
static_cast<Connection *>(o);
415 next = c->nextInOrphanList;
416 Q_ASSERT(!c->receiver.loadRelaxed());
426
427
428
429
430
431bool QObjectPrivate::isSignalConnected(uint signalIndex,
bool checkDeclarative)
const
433 if (checkDeclarative && isDeclarativeSignalConnected(signalIndex))
436 ConnectionData *cd = connections.loadAcquire();
439 SignalVector *signalVector = cd->signalVector.loadRelaxed();
443 if (signalVector->at(-1).first.loadRelaxed())
446 if (signalIndex < uint(cd->signalVectorCount())) {
447 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadRelaxed();
449 if (c->receiver.loadRelaxed())
451 c = c->nextConnectionList.loadRelaxed();
457bool QObjectPrivate::maybeSignalConnected(uint signalIndex)
const
459 ConnectionData *cd = connections.loadAcquire();
462 SignalVector *signalVector = cd->signalVector.loadAcquire();
466 if (signalVector->at(-1).first.loadAcquire())
469 if (signalIndex < uint(cd->signalVectorCount())) {
470 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadAcquire();
476void QObjectPrivate::reinitBindingStorageAfterThreadMove()
478 bindingStorage.reinitAfterThreadMove();
479 for (
int i = 0; i < children.size(); ++i)
480 children[i]->d_func()->reinitBindingStorageAfterThreadMove();
484
485
486QAbstractMetaCallEvent::~QAbstractMetaCallEvent()
495
496
497
498
499
500QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative,
501 QObjectPrivate::StaticMetaCallFunction callFunction,
502 const QObject *sender,
int signalId,
503 void **args, QLatch *latch)
504 : QAbstractMetaCallEvent(sender, signalId, latch),
505 d{
nullptr, args, callFunction, 0, method_offset, method_relative}
510
511
512
513
514
515QMetaCallEvent::QMetaCallEvent(QtPrivate::QSlotObjectBase *slotO,
516 const QObject *sender,
int signalId,
517 void **args, QLatch *latch)
518 : QAbstractMetaCallEvent(sender, signalId, latch),
519 d{QtPrivate::SlotObjUniquePtr{slotO}, args,
nullptr, 0, 0, ushort(-1)}
526
527
528
529
530
531QMetaCallEvent::QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotO,
532 const QObject *sender,
int signalId,
533 void **args, QLatch *latch)
534 : QAbstractMetaCallEvent(sender, signalId, latch),
535 d{std::move(slotO), args,
nullptr, 0, 0, ushort(-1)}
540
541
542QMetaCallEvent::QMetaCallEvent(
const QObject *sender,
int signalId, Data &&data)
543 : QAbstractMetaCallEvent(sender, signalId),
549
550
551void QMetaCallEvent::placeMetaCall(QObject *object)
554 d.slotObj_->call(object, d.args_);
555 }
else if (d.callFunction_ && d.method_offset_ <= object->metaObject()->methodOffset()) {
556 d.callFunction_(object, QMetaObject::InvokeMetaMethod, d.method_relative_, d.args_);
558 QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod,
559 d.method_offset_ + d.method_relative_, d.args_);
564
565
566
567
568QQueuedMetaCallEvent::QQueuedMetaCallEvent(ushort method_offset, ushort method_relative,
569 QObjectPrivate::StaticMetaCallFunction callFunction,
570 const QObject *sender,
int signalId,
int argCount,
571 const QtPrivate::QMetaTypeInterface *
const *argTypes,
572 const void *
const *argValues)
573 : QMetaCallEvent(sender, signalId, {
nullptr,
nullptr, callFunction, argCount,
574 method_offset, method_relative}),
577 copyArgValues(argCount, argTypes, argValues);
581
582
583
584
585QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
586 const QObject *sender,
int signalId,
int argCount,
587 const QtPrivate::QMetaTypeInterface *
const *argTypes,
588 const void *
const *argValues)
589 : QMetaCallEvent(sender, signalId, {QtPrivate::SlotObjUniquePtr(slotObj),
nullptr,
nullptr, argCount,
595 copyArgValues(argCount, argTypes, argValues);
599
600
601
602
603QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,
604 const QObject *sender,
int signalId,
int argCount,
605 const QtPrivate::QMetaTypeInterface *
const *argTypes,
606 const void *
const *argValues)
607 : QMetaCallEvent(sender, signalId, {std::move(slotObj),
nullptr,
nullptr, argCount,
611 copyArgValues(argCount, argTypes, argValues);
615
616
617QQueuedMetaCallEvent::~QQueuedMetaCallEvent()
619 const QMetaType *t =
reinterpret_cast<QMetaType *>(d.args_ + d.nargs_);
620 int inplaceIndex = 0;
621 for (
int i = 0; i < d.nargs_; ++i) {
622 if (t[i].isValid() && d.args_[i]) {
623 if (typeFitsInPlace(t[i]) && inplaceIndex < InplaceValuesCapacity) {
625 void *where = &valuesPrealloc_[inplaceIndex++].storage;
626 t[i].destruct(where);
629 t[i].destroy(d.args_[i]);
634 if (
static_cast<
void *>(d.args_) != prealloc_)
635 QtPrivate::sizedFree(d.args_, d.nargs_, PtrAndTypeSize);
640
641
642inline void QQueuedMetaCallEvent::allocArgs()
647 void *
const memory = d.nargs_ * PtrAndTypeSize >
sizeof(prealloc_) ?
648 calloc(d.nargs_, PtrAndTypeSize) : prealloc_;
651 d.args_ =
static_cast<
void **>(memory);
655
656
657inline void QQueuedMetaCallEvent::copyArgValues(
int argCount,
const QtPrivate::QMetaTypeInterface *
const *argTypes,
658 const void *
const *argValues)
661 void **args = d.args_;
662 QMetaType *types =
reinterpret_cast<QMetaType *>(d.args_ + d.nargs_);
663 int inplaceIndex = 0;
666 types[0] = QMetaType();
671 for (
int n = 1; n < argCount; ++n) {
672 types[n] = QMetaType(argTypes[n]);
673 if (typeFitsInPlace(types[n]) && inplaceIndex < InplaceValuesCapacity) {
675 void *where = &valuesPrealloc_[inplaceIndex++].storage;
676 types[n].construct(where, argValues[n]);
680 args[n] = types[n].create(argValues[n]);
686
687
688inline bool QQueuedMetaCallEvent::typeFitsInPlace(
const QMetaType type)
690 return (q20::cmp_less_equal(type.sizeOf(),
sizeof(ArgValueStorage)) &&
691 q20::cmp_less_equal(type.alignOf(),
alignof(ArgValueStorage)));
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
719
720
721
722
725
726
727
728
729
732
733
734
735
736
737
740
741
742
743
744
745
746
747
748
749
750
753
754
755
756
757
758
761
762
763
764
765
766
767
770
771
772
773
774
775
776
777
778
781
782
783
784
785
786
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
938
939
940
943
944
951 if (parent && parentThreadData != currentThreadData) {
952 QThread *parentThread = parentThreadData->thread.loadAcquire();
953 QThread *currentThread = currentThreadData->thread.loadAcquire();
954 qWarning(
"QObject: Cannot create children for a parent that is in a different thread.\n"
955 "(Parent is %s(%p), parent's thread is %s(%p), current thread is %s(%p)",
956 parent->metaObject()->className(),
958 parentThread ? parentThread->metaObject()->className() :
"QThread",
960 currentThread ? currentThread->metaObject()->className() :
"QThread",
968
969
970
971
972
973
974
975
976
977
978
979
980
982QObject::QObject(QObject *parent)
983 : QObject(*
new QObjectPrivate, parent)
988
989
990QObject::QObject(QObjectPrivate &dd, QObject *parent)
993 Q_ASSERT_X(
this != parent, Q_FUNC_INFO,
"Cannot parent a QObject to itself");
997 QThreadData *parentThreadData = parent ? parent->d_func()->threadData.loadRelaxed() :
nullptr;
998 QThreadData *threadData;
999 if (parent && !parentThreadData->thread.loadRelaxed()) {
1000 threadData = parentThreadData;
1002 threadData = QThreadData::current();
1003 if (!check_parent_thread(parent, parentThreadData, threadData))
1007 d->threadData.storeRelaxed(threadData);
1011 auto scopeDeref = qScopeGuard([threadData] { threadData->deref(); });
1012 if (d->willBeWidget) {
1014 d->parent->d_func()->children.append(
this);
1019 scopeDeref.dismiss();
1024 if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
1025 reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(
this);
1026 Q_TRACE(QObject_ctor,
this);
1061 d->wasDeleted =
true;
1064 if (!d->bindingStorage.isValid()) {
1067 if (QThread *ownThread = thread()) {
1068 auto *privThread =
static_cast<QThreadPrivate *>(
1069 QObjectPrivate::get(ownThread));
1070 privThread->removeObjectWithPendingBindingStatusChange(
this);
1076 d->clearBindingStorage();
1078 QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.loadRelaxed();
1079 if (sharedRefcount) {
1080 if (sharedRefcount->strongref.loadRelaxed() > 0) {
1081 qWarning(
"QObject: shared QObject was deleted directly. The program is malformed and may crash.");
1086 sharedRefcount->strongref.storeRelaxed(0);
1087 if (!sharedRefcount->weakref.deref())
1088 delete sharedRefcount;
1091 if (!d->wasWidget && d->isSignalConnected(0)) {
1092 emit destroyed(
this);
1095 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::destroyed)
1096 QAbstractDeclarativeData::destroyed(d->declarativeData,
this);
1098 QObjectPrivate::ConnectionData *cd = d->connections.loadAcquire();
1100 if (cd->currentSender) {
1101 cd->currentSender->receiverDeleted();
1102 cd->currentSender =
nullptr;
1105 QBasicMutex *signalSlotMutex = signalSlotLock(
this);
1106 QMutexLocker locker(signalSlotMutex);
1109 int receiverCount = cd->signalVectorCount();
1110 for (
int signal = -1; signal < receiverCount; ++signal) {
1111 QObjectPrivate::ConnectionList &connectionList = cd->connectionsForSignal(signal);
1113 while (QObjectPrivate::Connection *c = connectionList.first.loadRelaxed()) {
1114 Q_ASSERT(c->receiver.loadAcquire());
1116 QBasicMutex *m = signalSlotLock(c->receiver.loadRelaxed());
1117 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1118 if (c == connectionList.first.loadAcquire() && c->receiver.loadAcquire()) {
1119 cd->removeConnection(c);
1120 Q_ASSERT(connectionList.first.loadRelaxed() != c);
1128
1129 while (QObjectPrivate::Connection *node = cd->senders) {
1130 Q_ASSERT(node->receiver.loadAcquire());
1131 QObject *sender = node->sender;
1135 sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), node->signal_index));
1136 QBasicMutex *m = signalSlotLock(sender);
1137 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1139 if (node != cd->senders) {
1141 Q_ASSERT(needToUnlock);
1146 QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections.loadRelaxed();
1147 Q_ASSERT(senderData);
1149 QtPrivate::QSlotObjectBase *slotObj =
nullptr;
1150 if (node->isSlotObject) {
1151 slotObj = node->slotObj;
1152 node->isSlotObject =
false;
1155 senderData->removeConnection(node);
1157
1158
1159
1160
1161
1162
1163
1164 const bool locksAreTheSame = signalSlotMutex == m;
1165 if (!locksAreTheSame)
1167 senderData->cleanOrphanedConnections(
1169 QObjectPrivate::ConnectionData::AlreadyLockedAndTemporarilyReleasingLock
1174 if (locksAreTheSame)
1177 slotObj->destroyIfLastRef();
1183 cd->currentConnectionId.storeRelaxed(0);
1185 if (cd && !cd->ref.deref())
1187 d->connections.storeRelaxed(
nullptr);
1189 if (!d->children.isEmpty())
1190 d->deleteChildren();
1192 if (Q_UNLIKELY(qtHookData[QHooks::RemoveQObject]))
1193 reinterpret_cast<QHooks::RemoveQObjectCallback>(qtHookData[QHooks::RemoveQObject])(
this);
1195 Q_TRACE(QObject_dtor,
this);
1198 d->setParent_helper(
nullptr);
1463bool QObject::event(QEvent *e)
1465 switch (e->type()) {
1467 timerEvent((QTimerEvent *)e);
1470 case QEvent::ChildAdded:
1471 case QEvent::ChildPolished:
1472 case QEvent::ChildRemoved:
1473 childEvent((QChildEvent *)e);
1476 case QEvent::DeferredDelete:
1480 case QEvent::MetaCall:
1482 QAbstractMetaCallEvent *mce =
static_cast<QAbstractMetaCallEvent*>(e);
1484 QObjectPrivate::ConnectionData *connections = d_func()->connections.loadAcquire();
1486 QMutexLocker locker(signalSlotLock(
this));
1487 d_func()->ensureConnectionData();
1488 connections = d_func()->connections.loadRelaxed();
1490 QObjectPrivate::Sender sender(
this,
const_cast<QObject*>(mce->sender()), mce->signalId(), connections);
1492 mce->placeMetaCall(
this);
1496 case QEvent::ThreadChange: {
1498 QThreadData *threadData = d->threadData.loadRelaxed();
1499 QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
1500 if (eventDispatcher) {
1501 QList<QAbstractEventDispatcher::TimerInfoV2> timers = eventDispatcher->timersForObject(
this);
1502 if (!timers.isEmpty()) {
1503 const bool res = eventDispatcher->unregisterTimers(
this);
1505 Q_ASSERT_X(res, Q_FUNC_INFO,
1506 "QAbstractEventDispatcher::unregisterTimers() returned false,"
1507 " but there are timers associated with this object.");
1508 auto reRegisterTimers = [
this, timers = std::move(timers)]() {
1509 QAbstractEventDispatcher *eventDispatcher =
1510 d_func()->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
1511 for (
const auto &ti : timers)
1512 eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType,
this);
1514 QMetaObject::invokeMethod(
this, std::move(reRegisterTimers), Qt::QueuedConnection);
1521 if (e->type() >= QEvent::User) {
1718bool QObject::moveToThread(QThread *targetThread QT6_IMPL_NEW_OVERLOAD_TAIL)
1722 if (d->threadData.loadRelaxed()->thread.loadAcquire() == targetThread) {
1727 if (d->parent !=
nullptr) {
1728 qWarning(
"QObject::moveToThread: Cannot move objects with a parent");
1732 qWarning(
"QObject::moveToThread: Widgets cannot be moved to a new thread");
1735 if (!d->bindingStorage.isEmpty()) {
1736 qWarning(
"QObject::moveToThread: Can not move objects that contain bindings or are used in bindings to a new thread.");
1740 QThreadData *currentData = QThreadData::current();
1741 QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) :
nullptr;
1742 QThreadData *thisThreadData = d->threadData.loadAcquire();
1743 if (!thisThreadData->thread.loadRelaxed() && currentData == targetData) {
1745 currentData = thisThreadData;
1746 }
else if (thisThreadData != currentData) {
1747 qWarning(
"QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
1748 "Cannot move to target thread (%p)\n",
1749 currentData->thread.loadRelaxed(), thisThreadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() :
nullptr);
1752 qWarning(
"You might be loading two sets of Qt binaries into the same process. "
1753 "Check that all plugins are compiled against the right Qt binaries. Export "
1754 "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.");
1761 d->moveToThread_helper();
1764 targetData =
new QThreadData(0);
1767 QMutexLocker l(signalSlotLock(
this));
1769 QOrderedMutexLocker locker(¤tData->postEventList.mutex,
1770 &targetData->postEventList.mutex);
1776 auto threadPrivate = targetThread
1777 ?
static_cast<QThreadPrivate *>(QThreadPrivate::get(targetThread))
1779 QBindingStatus *bindingStatus = threadPrivate
1780 ? threadPrivate->bindingStatus()
1782 if (threadPrivate && !bindingStatus) {
1783 bindingStatus = threadPrivate->addObjectWithPendingBindingStatusChange(
this);
1785 d_func()->setThreadData_helper(currentData, targetData, bindingStatus);
1790 currentData->deref();
1806void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status)
1812 this->bindingStorage.bindingStatus = status;
1816 qsizetype eventsMoved = 0;
1817 for (qsizetype i = 0; i < currentData->postEventList.size(); ++i) {
1818 const QPostEvent &pe = currentData->postEventList.at(i);
1821 if (pe.receiver == q) {
1823 targetData->postEventList.addEvent(pe);
1824 const_cast<QPostEvent &>(pe).event =
nullptr;
1828 if (eventsMoved > 0 && targetData->hasEventDispatcher()) {
1829 targetData->canWait =
false;
1830 targetData->eventDispatcher.loadRelaxed()->wakeUp();
1834 ConnectionData *cd = connections.loadAcquire();
1836 if (cd->currentSender) {
1837 cd->currentSender->receiverDeleted();
1838 cd->currentSender =
nullptr;
1843 auto *c = cd->senders;
1845 QObject *r = c->receiver.loadRelaxed();
1849 QThreadData *old = c->receiverThreadData.loadRelaxed();
1852 c->receiverThreadData.storeRelaxed(targetData);
1862 threadData.loadRelaxed()->deref();
1865 threadData.storeRelease(targetData);
1867 for (
int i = 0; i < children.size(); ++i) {
1868 QObject *child = children.at(i);
1869 child->d_func()->setThreadData_helper(currentData, targetData, status);
2299void QObjectPrivate::setParent_helper(QObject *o)
2302 Q_ASSERT_X(q != o, Q_FUNC_INFO,
"Cannot parent a QObject to itself");
2304 const auto checkForParentChildLoops = qScopeGuard([&](){
2308 if (++depth == CheckForParentChildLoopsWarnDepth) {
2309 qWarning(
"QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
2310 "this is undefined behavior",
2311 q, q->metaObject()->className(), qPrintable(q->objectName()));
2322 QObjectPrivate *parentD = parent->d_func();
2323 if (parentD->isDeletingChildren && wasDeleted
2324 && parentD->currentChildBeingDeleted == q) {
2328 const qsizetype index = parentD->children.indexOf(q);
2331 }
else if (parentD->isDeletingChildren) {
2332 parentD->children[index] =
nullptr;
2334 parentD->children.removeAt(index);
2335 if (sendChildEvents && parentD->receiveChildEvents) {
2336 QChildEvent e(QEvent::ChildRemoved, q);
2337 QCoreApplication::sendEvent(parent, &e);
2343 if (receiveParentEvents) {
2344 Q_ASSERT(!isWidget);
2345 QEvent e(QEvent::ParentAboutToChange);
2346 QCoreApplication::sendEvent(q, &e);
2353 if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) {
2354 qWarning(
"QObject::setParent: Cannot set parent, new parent is in a different thread");
2358 parent->d_func()->children.append(q);
2359 if (sendChildEvents && parent->d_func()->receiveChildEvents) {
2361 QChildEvent e(QEvent::ChildAdded, q);
2362 QCoreApplication::sendEvent(parent, &e);
2367 if (receiveParentEvents) {
2368 Q_ASSERT(!isWidget);
2369 QEvent e(QEvent::ParentChange);
2370 QCoreApplication::sendEvent(q, &e);
3094QMetaObject::Connection QObject::connect(
const QObject *sender,
const char *signal,
3095 const QObject *receiver,
const char *method,
3096 Qt::ConnectionType type)
3098 if (sender ==
nullptr || receiver ==
nullptr || signal ==
nullptr || method ==
nullptr) {
3099 qCWarning(lcConnect,
"QObject::connect: Cannot connect %s::%s to %s::%s",
3100 sender ? sender->metaObject()->className() :
"(nullptr)",
3101 (signal && *signal) ? signal + 1 :
"(nullptr)",
3102 receiver ? receiver->metaObject()->className() :
"(nullptr)",
3103 (method && *method) ? method + 1 :
"(nullptr)");
3104 return QMetaObject::Connection(
nullptr);
3107 if (!check_signal_macro(sender, signal,
"connect",
"bind"))
3108 return QMetaObject::Connection(
nullptr);
3110 int membcode = extract_code(method);
3111 if (!check_method_code(membcode, receiver, method,
"connect"))
3112 return QMetaObject::Connection(
nullptr);
3114 QByteArray pinnedSignal;
3115 const QMetaObject *smeta = sender->metaObject();
3116 const char *signal_arg = signal;
3118 QByteArrayView signalView{signal};
3119 QArgumentTypeArray signalTypes;
3120 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3121 QByteArrayView signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3122 int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3123 if (signal_index < 0) {
3125 pinnedSignal = QMetaObjectPrivate::normalizedSignature(signalView);
3126 signalView = pinnedSignal;
3128 signalTypes.clear();
3129 signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3130 smeta = sender->metaObject();
3131 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3133 if (signal_index < 0) {
3134 err_method_notfound(sender, signal_arg,
"connect");
3135 err_info_about_objects(
"connect", sender, receiver);
3136 return QMetaObject::Connection(
nullptr);
3138 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3139 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3141 QByteArray pinnedMethod;
3142 const char *method_arg = method;
3144 QByteArrayView methodView{method};
3146 QArgumentTypeArray methodTypes;
3147 QByteArrayView methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3148 const QMetaObject *rmeta = receiver->metaObject();
3149 int method_index_relative = -1;
3150 Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
3153 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3154 &rmeta, methodName, methodTypes);
3157 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3158 &rmeta, methodName, methodTypes);
3162 if (method_index_relative < 0) {
3164 pinnedMethod = QMetaObjectPrivate::normalizedSignature(methodView);
3165 methodView = pinnedMethod;
3167 methodTypes.clear();
3168 methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3170 rmeta = receiver->metaObject();
3173 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3174 &rmeta, methodName, methodTypes);
3177 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3178 &rmeta, methodName, methodTypes);
3183 if (method_index_relative < 0) {
3184 err_method_notfound(receiver, method_arg,
"connect");
3185 err_info_about_objects(
"connect", sender, receiver);
3186 return QMetaObject::Connection(
nullptr);
3189 if (!QMetaObjectPrivate::checkConnectArgs(signalTypes, methodTypes)) {
3191 "QObject::connect: Incompatible sender/receiver arguments"
3192 "\n %s::%s --> %s::%s",
3193 sender->metaObject()->className(), signalView.constData(),
3194 receiver->metaObject()->className(), methodView.constData());
3195 return QMetaObject::Connection(
nullptr);
3200 int *types =
nullptr;
3201 if (type == Qt::QueuedConnection && !(types = queuedConnectionTypes(signalTypes))) {
3202 return QMetaObject::Connection(
nullptr);
3205 QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
3207 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3208 check_and_warn_compat(smeta, smethod, rmeta, rmethod);
3211#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
3212 check_and_warn_non_slot(
"connect", method, membcode, rmeta, rmethod);
3215 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3216 sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
3240QMetaObject::Connection QObject::connect(
const QObject *sender,
const QMetaMethod &signal,
3241 const QObject *receiver,
const QMetaMethod &method,
3242 Qt::ConnectionType type)
3244 if (sender ==
nullptr
3245 || receiver ==
nullptr
3246 || signal.methodType() != QMetaMethod::Signal
3247 || method.methodType() == QMetaMethod::Constructor) {
3248 qCWarning(lcConnect,
"QObject::connect: Cannot connect %s::%s to %s::%s",
3249 sender ? sender->metaObject()->className() :
"(nullptr)",
3250 signal.methodSignature().constData(),
3251 receiver ? receiver->metaObject()->className() :
"(nullptr)",
3252 method.methodSignature().constData());
3253 return QMetaObject::Connection(
nullptr);
3260 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3261 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3264 const QMetaObject *smeta = sender->metaObject();
3265 const QMetaObject *rmeta = receiver->metaObject();
3266 if (signal_index == -1) {
3267 qCWarning(lcConnect,
"QObject::connect: Can't find signal %s on instance of class %s",
3268 signal.methodSignature().constData(), smeta->className());
3269 return QMetaObject::Connection(
nullptr);
3271 if (method_index == -1) {
3272 qCWarning(lcConnect,
"QObject::connect: Can't find method %s on instance of class %s",
3273 method.methodSignature().constData(), rmeta->className());
3274 return QMetaObject::Connection(
nullptr);
3277 if (!QMetaObject::checkConnectArgs(signal.methodSignature().constData(),
3278 method.methodSignature().constData())) {
3280 "QObject::connect: Incompatible sender/receiver arguments"
3281 "\n %s::%s --> %s::%s",
3282 smeta->className(), signal.methodSignature().constData(), rmeta->className(),
3283 method.methodSignature().constData());
3284 return QMetaObject::Connection(
nullptr);
3287 int *types =
nullptr;
3288 if ((type == Qt::QueuedConnection) && !(types = queuedConnectionTypes(signal)))
3289 return QMetaObject::Connection(
nullptr);
3292 check_and_warn_compat(smeta, signal, rmeta, method);
3294 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3295 sender, signal_index, signal.enclosingMetaObject(), receiver, method_index,
nullptr, type, types));
3380bool QObject::disconnect(
const QObject *sender,
const char *signal,
3381 const QObject *receiver,
const char *method)
3383 if (sender ==
nullptr || (receiver ==
nullptr && method !=
nullptr)) {
3384 qCWarning(lcConnect,
"QObject::disconnect: Unexpected nullptr parameter");
3388 const char *signal_arg = signal;
3390 if (!check_signal_macro(sender, signal,
"disconnect",
"unbind"))
3395 const char *method_arg = method;
3398 membcode = extract_code(method);
3399 if (!check_method_code(membcode, receiver, method,
"disconnect"))
3404 QByteArray pinnedSignal;
3405 const QMetaObject *smeta = sender->metaObject();
3406 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3407 int signal_index = -1;
3408 QByteArrayView signalName;
3409 QArgumentTypeArray signalTypes;
3411 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3412 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3413 if (signal_index == -1) {
3414 pinnedSignal = QMetaObject::normalizedSignature(signal);
3415 signal = pinnedSignal.constData();
3416 signalTypes.clear();
3417 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3418 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3421 if (signal_index == -1) {
3422 err_method_notfound(sender, signal_arg,
"disconnect");
3423 err_info_about_objects(
"disconnect", sender, receiver);
3428 auto getMethodIndex = [](
int code,
const QMetaObject *mo, QByteArrayView name,
3429 const QArgumentTypeArray &types) {
3432 return QMetaObjectPrivate::indexOfSlot(mo, name, types);
3434 return QMetaObjectPrivate::indexOfSignal(mo, name, types);
3439 QByteArray pinnedMethod;
3440 const QMetaObject *rmeta = receiver ? receiver->metaObject() :
nullptr;
3441 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 7);
3442 int method_index = -1;
3443 QByteArrayView methodName;
3444 QArgumentTypeArray methodTypes;
3446 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3447 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3448 if (method_index == -1) {
3449 pinnedMethod = QMetaObject::normalizedSignature(method);
3450 method = pinnedMethod.constData();
3451 methodTypes.clear();
3452 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3453 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3455 if (method_index == -1) {
3456 err_method_notfound(receiver, method_arg,
"disconnect");
3457 err_info_about_objects(
"disconnect", sender, receiver);
3463
3464
3465
3470 if (smeta != sender->metaObject()) {
3471 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3474 if (signal_index < 0)
3476 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3477 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3481 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1,
nullptr);
3485 if (rmeta != receiver->metaObject())
3486 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3487 if (method_index >= 0) {
3488#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
3489 check_and_warn_non_slot(
"disconnect", method, membcode, rmeta,
3490 rmeta->method(method_index));
3492 while (method_index < rmeta->methodOffset())
3493 rmeta = rmeta->superClass();
3495 if (method_index < 0)
3497 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index,
nullptr);
3498 }
while ((rmeta = rmeta->superClass()));
3500 }
while (signal && (smeta = smeta->superClass()));
3504 const_cast<QObject *>(sender)->disconnectNotify(QMetaMethod());
3543bool QObject::disconnect(
const QObject *sender,
const QMetaMethod &signal,
3544 const QObject *receiver,
const QMetaMethod &method)
3546 if (sender ==
nullptr || (receiver ==
nullptr && method.mobj !=
nullptr)) {
3547 qCWarning(lcConnect,
"QObject::disconnect: Unexpected nullptr parameter");
3551 if (signal.methodType() != QMetaMethod::Signal) {
3552 qCWarning(lcConnect,
"QObject::%s: Attempt to %s non-signal %s::%s",
3553 "disconnect",
"unbind",
3554 sender->metaObject()->className(), signal.methodSignature().constData());
3559 if (method.methodType() == QMetaMethod::Constructor) {
3560 qCWarning(lcConnect,
"QObject::disconnect: cannot use constructor as argument %s::%s",
3561 receiver->metaObject()->className(), method.methodSignature().constData());
3570 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3571 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3575 if (signal.mobj && signal_index == -1) {
3576 qCWarning(lcConnect,
"QObject::disconnect: signal %s not found on class %s",
3577 signal.methodSignature().constData(), sender->metaObject()->className());
3581 if (receiver && method.mobj && method_index == -1) {
3582 qCWarning(lcConnect,
"QObject::disconnect: method %s not found on class %s",
3583 method.methodSignature().constData(), receiver->metaObject()->className());
3587 if (!QMetaObjectPrivate::disconnect(sender, signal_index, signal.mobj, receiver, method_index,
nullptr))
3590 if (!signal.isValid()) {
3595 const_cast<QObject *>(sender)->disconnectNotify(signal);
3752 int signal_index,
const QMetaObject *smeta,
3753 const QObject *receiver,
int method_index,
3754 const QMetaObject *rmeta,
int type,
int *types)
3756 QObject *s =
const_cast<QObject *>(sender);
3757 QObject *r =
const_cast<QObject *>(receiver);
3759 int method_offset = rmeta ? rmeta->methodOffset() : 0;
3761 QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall :
nullptr;
3763 QOrderedMutexLocker locker(signalSlotLock(sender),
3764 signalSlotLock(receiver));
3766 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3767 if (type & Qt::UniqueConnection && scd) {
3768 if (scd->signalVectorCount() > signal_index) {
3769 const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
3771 int method_index_absolute = method_index + method_offset;
3774 if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute)
3776 c2 = c2->nextConnectionList.loadRelaxed();
3780 type &= ~Qt::UniqueConnection;
3782 const bool isSingleShot = type & Qt::SingleShotConnection;
3783 type &= ~Qt::SingleShotConnection;
3785 Q_ASSERT(type >= 0);
3786 Q_ASSERT(type <= 3);
3788 std::unique_ptr<QObjectPrivate::Connection> c{
new QObjectPrivate::Connection};
3790 c->signal_index = signal_index;
3791 c->receiver.storeRelaxed(r);
3792 QThreadData *td = r->d_func()->threadData.loadAcquire();
3794 c->receiverThreadData.storeRelaxed(td);
3795 c->method_relative = method_index;
3796 c->method_offset = method_offset;
3797 c->connectionType = type;
3798 c->isSlotObject =
false;
3799 c->argumentTypes.storeRelaxed(types);
3800 c->callFunction = callFunction;
3801 c->isSingleShot = isSingleShot;
3803 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
3806 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3807 if (smethod.isValid())
3808 s->connectNotify(smethod);
3886bool QMetaObjectPrivate::disconnect(
const QObject *sender,
3887 int signal_index,
const QMetaObject *smeta,
3888 const QObject *receiver,
int method_index,
void **slot,
3889 DisconnectType disconnectType)
3894 QObject *s =
const_cast<QObject *>(sender);
3896 QBasicMutex *senderMutex = signalSlotLock(sender);
3897 QMutexLocker locker(senderMutex);
3899 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3906 struct WildcardDestroyedWarning
3908 QByteArray className;
3909 QByteArray objectName;
3911 std::optional<WildcardDestroyedWarning> wildcardDestroyedWarning;
3913 bool success =
false;
3916 QObjectPrivate::ConnectionDataPointer connections(scd);
3918 if (signal_index < 0) {
3920 if (!receiver && method_index < 0 && sender->d_func()->isSignalConnected(0)) {
3921 wildcardDestroyedWarning = WildcardDestroyedWarning{
3922 sender->metaObject()->className(),
3923 sender->objectName().toLocal8Bit()
3927 for (
int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
3928 if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
3931 }
else if (signal_index < scd->signalVectorCount()) {
3932 if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
3939 if (wildcardDestroyedWarning) {
3940 qWarning(
"QObject::disconnect: wildcard call disconnects from destroyed signal of %s::%s",
3941 wildcardDestroyedWarning->className.constData(),
3942 wildcardDestroyedWarning->objectName.isEmpty()
3944 : wildcardDestroyedWarning->objectName.constData());
3948 scd->cleanOrphanedConnections(s);
3950 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3951 if (smethod.isValid())
3952 s->disconnectNotify(smethod);
4008void QMetaObject::connectSlotsByName(QObject *o)
4012 const QMetaObject *mo = o->metaObject();
4014 const QObjectList list =
4015 o->findChildren<QObject *>()
4019 for (
int i = 0; i < mo->methodCount(); ++i) {
4020 const QByteArray slotSignature = mo->method(i).methodSignature();
4021 const char *slot = slotSignature.constData();
4025 if (slot[0] !=
'o' || slot[1] !=
'n' || slot[2] !=
'_')
4029 bool foundIt =
false;
4030 for (
int j = 0; j < list.size(); ++j) {
4031 const QObject *co = list.at(j);
4032 const QByteArray coName = co->objectName().toLatin1();
4035 if (coName.isEmpty() || qstrncmp(slot + 3, coName.constData(), coName.size()) || slot[coName.size()+3] !=
'_')
4038 const char *signal = slot + coName.size() + 4;
4041 const QMetaObject *smeta;
4042 int sigIndex = co->d_func()->signalIndex(signal, &smeta);
4048 QList<QByteArray> compatibleSignals;
4049 const QMetaObject *smo = co->metaObject();
4050 int sigLen =
int(qstrlen(signal)) - 1;
4051 for (
int k = QMetaObjectPrivate::absoluteSignalCount(smo)-1; k >= 0; --k) {
4052 const QMetaMethod method = QMetaObjectPrivate::signal(smo, k);
4053 if (!qstrncmp(method.methodSignature().constData(), signal, sigLen)) {
4054 smeta = method.enclosingMetaObject();
4056 compatibleSignals.prepend(method.methodSignature());
4059 if (compatibleSignals.size() > 1)
4060 qCWarning(lcConnectSlotsByName) <<
"QMetaObject::connectSlotsByName: Connecting slot" << slot
4061 <<
"with the first of the following compatible signals:" << compatibleSignals;
4068 if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) {
4070 qCDebug(lcConnectSlotsByName,
"%s",
4071 msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData());
4081 while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
4083 }
else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
4085 qsizetype iParen = slotSignature.indexOf(
'(');
4086 qsizetype iLastUnderscore = slotSignature.lastIndexOf(
'_', iParen - 1);
4087 if (iLastUnderscore > 3)
4089 "QMetaObject::connectSlotsByName: No matching signal for %s", slot);
4224static void queued_activate(QObject *sender,
int signal, QObjectPrivate::Connection *c,
void **argv)
4226 const int *argumentTypes = c->argumentTypes.loadRelaxed();
4227 if (!argumentTypes) {
4228 QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
4229 argumentTypes = queuedConnectionTypes(m);
4231 argumentTypes = &DIRECT_CONNECTION_ONLY;
4232 if (!c->argumentTypes.testAndSetOrdered(
nullptr, argumentTypes)) {
4233 if (argumentTypes != &DIRECT_CONNECTION_ONLY)
4234 delete[] argumentTypes;
4235 argumentTypes = c->argumentTypes.loadRelaxed();
4238 if (argumentTypes == &DIRECT_CONNECTION_ONLY)
4241 while (argumentTypes[nargs - 1])
4244 QMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
4245 QObject *receiver = c->receiver.loadRelaxed();
4251 SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj :
nullptr };
4254 QVarLengthArray<
const QtPrivate::QMetaTypeInterface *, 16> argTypes;
4255 argTypes.reserve(nargs);
4256 argTypes.emplace_back(
nullptr);
4257 for (
int n = 1; n < nargs; ++n) {
4258 argTypes.emplace_back(QMetaType(argumentTypes[n - 1]).iface());
4261 auto ev = c->isSlotObject ?
4262 std::make_unique<QQueuedMetaCallEvent>(c->slotObj,
4263 sender, signal, nargs, argTypes.data(), argv) :
4264 std::make_unique<QQueuedMetaCallEvent>(c->method_offset, c->method_relative, c->callFunction,
4265 sender, signal, nargs, argTypes.data(), argv);
4267 if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) {
4272 if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
4278 QCoreApplication::postEvent(receiver, ev.release());
4282void doActivate(QObject *sender,
int signal_index,
void **argv)
4284 QObjectPrivate *sp = QObjectPrivate::get(sender);
4289 Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
4291 if (sp->isDeclarativeSignalConnected(signal_index)
4292 && QAbstractDeclarativeData::signalEmitted) {
4293 Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
4294 QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
4295 signal_index, argv);
4298 const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() :
nullptr;
4300 void *empty_argv[] = {
nullptr };
4304 bool senderDeleted =
false;
4306 QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadAcquire());
4307 if (!connections || !sp->maybeSignalConnected(signal_index)) {
4309 if (callbacks_enabled && signal_spy_set->signal_begin_callback !=
nullptr)
4310 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4311 if (callbacks_enabled && signal_spy_set->signal_end_callback !=
nullptr)
4312 signal_spy_set->signal_end_callback(sender, signal_index);
4316 if (callbacks_enabled && signal_spy_set->signal_begin_callback !=
nullptr)
4317 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4321 QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadAcquire();
4323 const QObjectPrivate::ConnectionList *list;
4324 if (signal_index < signalVector->count())
4325 list = &signalVector->at(signal_index);
4327 list = &signalVector->at(-1);
4329 Qt::HANDLE currentThreadId = QThread::currentThreadId();
4330 bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
4334 uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
4336 QObjectPrivate::Connection *c = list->first.loadAcquire();
4341 QObject *
const receiver = c->receiver.loadRelaxed();
4345 QThreadData *td = c->receiverThreadData.loadRelaxed();
4349 bool receiverInSameThread;
4350 if (inSenderThread) {
4351 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4354 QMutexLocker lock(signalSlotLock(receiver));
4355 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4361 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
4362 || (c->connectionType == Qt::QueuedConnection)) {
4363 queued_activate(sender, signal_index, c, argv);
4365#if QT_CONFIG(thread)
4366 }
else if (c->connectionType == Qt::BlockingQueuedConnection) {
4367 if (receiverInSameThread) {
4368 qWarning(
"Qt: Dead lock detected while activating a BlockingQueuedConnection: "
4369 "Sender is %s(%p), receiver is %s(%p)",
4370 sender->metaObject()->className(), sender,
4371 receiver->metaObject()->className(), receiver);
4374 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4379 QMutexLocker locker(signalSlotLock(receiver));
4380 if (!c->isSingleShot && !c->receiver.loadAcquire())
4382 QMetaCallEvent *ev = c->isSlotObject ?
4383 new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &latch) :
4384 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
4385 sender, signal_index, argv, &latch);
4386 QCoreApplication::postEvent(receiver, ev);
4393 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4396 QObjectPrivate::Sender senderData(
4397 receiverInSameThread ? receiver :
nullptr, sender, signal_index,
4398 receiverInSameThread ? QObjectPrivate::get(receiver)->connections.loadAcquire() :
nullptr);
4400 if (c->isSlotObject) {
4401 SlotObjectGuard obj{c->slotObj};
4404 Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
4405 obj->call(receiver, argv);
4407 }
else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
4409 const int method_relative = c->method_relative;
4410 const auto callFunction = c->callFunction;
4411 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
4412 if (callbacks_enabled && signal_spy_set->slot_begin_callback !=
nullptr)
4413 signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
4416 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
4417 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
4420 if (callbacks_enabled && signal_spy_set->slot_end_callback !=
nullptr)
4421 signal_spy_set->slot_end_callback(receiver, methodIndex);
4423 const int method = c->method_relative + c->method_offset;
4425 if (callbacks_enabled && signal_spy_set->slot_begin_callback !=
nullptr) {
4426 signal_spy_set->slot_begin_callback(receiver, method, argv);
4430 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
4431 QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
4434 if (callbacks_enabled && signal_spy_set->slot_end_callback !=
nullptr)
4435 signal_spy_set->slot_end_callback(receiver, method);
4437 }
while ((c = c->nextConnectionList.loadAcquire()) !=
nullptr && c->id.loadAcquire() <= highestConnectionId);
4439 }
while (list != &signalVector->at(-1) &&
4441 ((list = &signalVector->at(-1)),
true));
4443 if (connections->currentConnectionId.loadRelaxed() == 0)
4444 senderDeleted =
true;
4447 if (!senderDeleted) {
4448 sp->connections.loadAcquire()->cleanOrphanedConnections(sender);
4450 if (callbacks_enabled && signal_spy_set->signal_end_callback !=
nullptr)
4451 signal_spy_set->signal_end_callback(sender, signal_index);
4689void QObject::dumpObjectInfo()
const
4691 qDebug(
"OBJECT %s::%s", metaObject()->className(),
4692 objectName().isEmpty() ?
"unnamed" : objectName().toLocal8Bit().data());
4695 QMutexLocker locker(signalSlotLock(
this));
4698 qDebug(
" SIGNALS OUT");
4700 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
4701 if (cd && cd->signalVectorCount() > 0) {
4702 QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
4703 for (
int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
4704 const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
4707 const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index);
4708 qDebug(
" signal: %s", signal.methodSignature().constData());
4712 if (!c->receiver.loadRelaxed()) {
4713 qDebug(
" <Disconnected receiver>");
4714 c = c->nextConnectionList.loadRelaxed();
4717 if (c->isSlotObject) {
4718 qDebug(
" <functor or function pointer>");
4719 c = c->nextConnectionList.loadRelaxed();
4722 const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
4723 const QMetaMethod method = receiverMetaObject->method(c->method());
4724 qDebug(
" --> %s::%s %s",
4725 receiverMetaObject->className(),
4726 c->receiver.loadRelaxed()->objectName().isEmpty() ?
"unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
4727 method.methodSignature().constData());
4728 c = c->nextConnectionList.loadRelaxed();
4732 qDebug(
" <None>" );
4736 qDebug(
" SIGNALS IN");
4738 if (cd && cd->senders) {
4739 for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
4740 QByteArray slotName = QByteArrayLiteral(
"<unknown>");
4741 if (!s->isSlotObject) {
4742 const QMetaMethod slot = metaObject()->method(s->method());
4743 slotName = slot.methodSignature();
4745 qDebug(
" <-- %s::%s %s",
4746 s->sender->metaObject()->className(),
4747 s->sender->objectName().isEmpty() ?
"unnamed" : qPrintable(s->sender->objectName()),
4748 slotName.constData());
5539QMetaObject::Connection QObjectPrivate::connectImpl(
const QObject *sender,
int signal_index,
5540 const QObject *receiver,
void **slot,
5541 QtPrivate::QSlotObjectBase *slotObjRaw,
int type,
5542 const int *types,
const QMetaObject *senderMetaObject)
5544 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5545 Q_ASSERT(senderMetaObject);
5548 if (!sender || !receiver) {
5549 connectWarning(sender, senderMetaObject, receiver,
"invalid nullptr parameter");
5550 return QMetaObject::Connection();
5553 if (type & Qt::UniqueConnection && !slot) {
5554 connectWarning(sender, senderMetaObject, receiver,
"unique connections require a pointer to member function of a QObject subclass");
5555 return QMetaObject::Connection();
5558 QObject *s =
const_cast<QObject *>(sender);
5559 QObject *r =
const_cast<QObject *>(receiver);
5561 QOrderedMutexLocker locker(signalSlotLock(sender),
5562 signalSlotLock(receiver));
5564 if (type & Qt::UniqueConnection) {
5565 QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
5566 if (connections && connections->signalVectorCount() > signal_index) {
5567 const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
5570 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot))
5571 return QMetaObject::Connection();
5572 c2 = c2->nextConnectionList.loadRelaxed();
5576 type &= ~Qt::UniqueConnection;
5578 const bool isSingleShot = type & Qt::SingleShotConnection;
5579 type &= ~Qt::SingleShotConnection;
5581 Q_ASSERT(type >= 0);
5582 Q_ASSERT(type <= 3);
5584 std::unique_ptr<QObjectPrivate::Connection> c{
new QObjectPrivate::Connection};
5586 c->signal_index = signal_index;
5587 QThreadData *td = r->d_func()->threadData.loadAcquire();
5589 c->receiverThreadData.storeRelaxed(td);
5590 c->receiver.storeRelaxed(r);
5591 c->connectionType = type;
5592 c->isSlotObject =
true;
5593 c->slotObj = slotObj.release();
5595 c->argumentTypes.storeRelaxed(types);
5596 c->ownArgumentTypes =
false;
5598 c->isSingleShot = isSingleShot;
5600 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
5601 QMetaObject::Connection ret(c.release());
5604 QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
5605 Q_ASSERT(method.isValid());
5606 s->connectNotify(method);