373 TaggedSignalVector c =
nullptr;
375 std::unique_lock<QBasicMutex> lock(*senderMutex, std::defer_lock_t{});
376 if (lockPolicy == NeedToLock)
378 if (ref.loadAcquire() > 1)
384 c = orphaned.exchange(
nullptr, std::memory_order_relaxed);
388 if (lockPolicy == AlreadyLockedAndTemporarilyReleasingLock) {
389 senderMutex->unlock();
398inline void QObjectPrivate::ConnectionData::deleteOrphaned(TaggedSignalVector o)
401 TaggedSignalVector next =
nullptr;
402 if (SignalVector *v =
static_cast<SignalVector *>(o)) {
403 next = v->nextInOrphanList;
406 QObjectPrivate::Connection *c =
static_cast<Connection *>(o);
407 next = c->nextInOrphanList;
408 Q_ASSERT(!c->receiver.loadRelaxed());
418
419
420
421
422
423bool QObjectPrivate::isSignalConnected(uint signalIndex,
bool checkDeclarative)
const
425 if (checkDeclarative && isDeclarativeSignalConnected(signalIndex))
428 ConnectionData *cd = connections.loadAcquire();
431 SignalVector *signalVector = cd->signalVector.loadRelaxed();
435 if (signalVector->at(-1).first.loadRelaxed())
438 if (signalIndex < uint(cd->signalVectorCount())) {
439 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadRelaxed();
441 if (c->receiver.loadRelaxed())
443 c = c->nextConnectionList.loadRelaxed();
449bool QObjectPrivate::maybeSignalConnected(uint signalIndex)
const
451 ConnectionData *cd = connections.loadAcquire();
454 SignalVector *signalVector = cd->signalVector.loadRelaxed();
458 if (signalVector->at(-1).first.loadAcquire())
461 if (signalIndex < uint(cd->signalVectorCount())) {
462 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadAcquire();
468void QObjectPrivate::reinitBindingStorageAfterThreadMove()
470 bindingStorage.reinitAfterThreadMove();
471 for (
int i = 0; i < children.size(); ++i)
472 children[i]->d_func()->reinitBindingStorageAfterThreadMove();
476
477
478QAbstractMetaCallEvent::~QAbstractMetaCallEvent()
487
488
489
490
491
492QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative,
493 QObjectPrivate::StaticMetaCallFunction callFunction,
494 const QObject *sender,
int signalId,
495 void **args, QLatch *latch)
496 : QAbstractMetaCallEvent(sender, signalId, latch),
497 d{
nullptr, args, callFunction, 0, method_offset, method_relative}
502
503
504
505
506
507QMetaCallEvent::QMetaCallEvent(QtPrivate::QSlotObjectBase *slotO,
508 const QObject *sender,
int signalId,
509 void **args, QLatch *latch)
510 : QAbstractMetaCallEvent(sender, signalId, latch),
511 d{QtPrivate::SlotObjUniquePtr{slotO}, args,
nullptr, 0, 0, ushort(-1)}
518
519
520
521
522
523QMetaCallEvent::QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotO,
524 const QObject *sender,
int signalId,
525 void **args, QLatch *latch)
526 : QAbstractMetaCallEvent(sender, signalId, latch),
527 d{std::move(slotO), args,
nullptr, 0, 0, ushort(-1)}
532
533
534QMetaCallEvent::QMetaCallEvent(
const QObject *sender,
int signalId, Data &&data)
535 : QAbstractMetaCallEvent(sender, signalId),
541
542
543void QMetaCallEvent::placeMetaCall(QObject *object)
546 d.slotObj_->call(object, d.args_);
547 }
else if (d.callFunction_ && d.method_offset_ <= object->metaObject()->methodOffset()) {
548 d.callFunction_(object, QMetaObject::InvokeMetaMethod, d.method_relative_, d.args_);
550 QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod,
551 d.method_offset_ + d.method_relative_, d.args_);
556
557
558
559
560QQueuedMetaCallEvent::QQueuedMetaCallEvent(ushort method_offset, ushort method_relative,
561 QObjectPrivate::StaticMetaCallFunction callFunction,
562 const QObject *sender,
int signalId,
int argCount,
563 const QtPrivate::QMetaTypeInterface *
const *argTypes,
564 const void *
const *argValues)
565 : QMetaCallEvent(sender, signalId, {
nullptr,
nullptr, callFunction, argCount,
566 method_offset, method_relative}),
569 copyArgValues(argCount, argTypes, argValues);
573
574
575
576
577QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
578 const QObject *sender,
int signalId,
int argCount,
579 const QtPrivate::QMetaTypeInterface *
const *argTypes,
580 const void *
const *argValues)
581 : QMetaCallEvent(sender, signalId, {QtPrivate::SlotObjUniquePtr(slotObj),
nullptr,
nullptr, argCount,
587 copyArgValues(argCount, argTypes, argValues);
591
592
593
594
595QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,
596 const QObject *sender,
int signalId,
int argCount,
597 const QtPrivate::QMetaTypeInterface *
const *argTypes,
598 const void *
const *argValues)
599 : QMetaCallEvent(sender, signalId, {std::move(slotObj),
nullptr,
nullptr, argCount,
603 copyArgValues(argCount, argTypes, argValues);
607
608
609QQueuedMetaCallEvent::~QQueuedMetaCallEvent()
611 const QMetaType *t =
reinterpret_cast<QMetaType *>(d.args_ + d.nargs_);
612 int inplaceIndex = 0;
613 for (
int i = 0; i < d.nargs_; ++i) {
614 if (t[i].isValid() && d.args_[i]) {
615 if (typeFitsInPlace(t[i]) && inplaceIndex < InplaceValuesCapacity) {
617 void *where = &valuesPrealloc_[inplaceIndex++].storage;
618 t[i].destruct(where);
621 t[i].destroy(d.args_[i]);
626 if (
static_cast<
void *>(d.args_) != prealloc_)
627 QtPrivate::sizedFree(d.args_, d.nargs_, PtrAndTypeSize);
632
633
634inline void QQueuedMetaCallEvent::allocArgs()
639 void *
const memory = d.nargs_ * PtrAndTypeSize >
sizeof(prealloc_) ?
640 calloc(d.nargs_, PtrAndTypeSize) : prealloc_;
643 d.args_ =
static_cast<
void **>(memory);
647
648
649inline void QQueuedMetaCallEvent::copyArgValues(
int argCount,
const QtPrivate::QMetaTypeInterface *
const *argTypes,
650 const void *
const *argValues)
653 void **args = d.args_;
654 QMetaType *types =
reinterpret_cast<QMetaType *>(d.args_ + d.nargs_);
655 int inplaceIndex = 0;
658 types[0] = QMetaType();
663 for (
int n = 1; n < argCount; ++n) {
664 types[n] = QMetaType(argTypes[n]);
665 if (typeFitsInPlace(types[n]) && inplaceIndex < InplaceValuesCapacity) {
667 void *where = &valuesPrealloc_[inplaceIndex++].storage;
668 types[n].construct(where, argValues[n]);
672 args[n] = types[n].create(argValues[n]);
678
679
680inline bool QQueuedMetaCallEvent::typeFitsInPlace(
const QMetaType type)
682 return (q20::cmp_less_equal(type.sizeOf(),
sizeof(ArgValueStorage)) &&
683 q20::cmp_less_equal(type.alignOf(),
alignof(ArgValueStorage)));
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
711
712
713
714
717
718
719
720
721
724
725
726
727
728
729
732
733
734
735
736
737
738
739
740
741
742
745
746
747
748
749
750
753
754
755
756
757
758
759
762
763
764
765
766
767
768
769
770
773
774
775
776
777
778
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
935
936
943 if (parent && parentThreadData != currentThreadData) {
944 QThread *parentThread = parentThreadData->thread.loadAcquire();
945 QThread *currentThread = currentThreadData->thread.loadAcquire();
946 qWarning(
"QObject: Cannot create children for a parent that is in a different thread.\n"
947 "(Parent is %s(%p), parent's thread is %s(%p), current thread is %s(%p)",
948 parent->metaObject()->className(),
950 parentThread ? parentThread->metaObject()->className() :
"QThread",
952 currentThread ? currentThread->metaObject()->className() :
"QThread",
960
961
962
963
964
965
966
967
968
969
970
971
972
974QObject::QObject(QObject *parent)
975 : QObject(*
new QObjectPrivate, parent)
980
981
982QObject::QObject(QObjectPrivate &dd, QObject *parent)
985 Q_ASSERT_X(
this != parent, Q_FUNC_INFO,
"Cannot parent a QObject to itself");
989 auto threadData = (parent && !parent->thread()) ? parent->d_func()->threadData.loadRelaxed() : QThreadData::current();
991 d->threadData.storeRelaxed(threadData);
994 if (!check_parent_thread(parent, parent ? parent->d_func()->threadData.loadRelaxed() :
nullptr, threadData))
996 if (d->willBeWidget) {
999 d->parent->d_func()->children.append(
this);
1006 threadData->deref();
1010 if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
1011 reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(
this);
1012 Q_TRACE(QObject_ctor,
this);
1047 d->wasDeleted =
true;
1050 if (!d->bindingStorage.isValid()) {
1053 if (QThread *ownThread = thread()) {
1054 auto *privThread =
static_cast<QThreadPrivate *>(
1055 QObjectPrivate::get(ownThread));
1056 privThread->removeObjectWithPendingBindingStatusChange(
this);
1062 d->clearBindingStorage();
1064 QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.loadRelaxed();
1065 if (sharedRefcount) {
1066 if (sharedRefcount->strongref.loadRelaxed() > 0) {
1067 qWarning(
"QObject: shared QObject was deleted directly. The program is malformed and may crash.");
1072 sharedRefcount->strongref.storeRelaxed(0);
1073 if (!sharedRefcount->weakref.deref())
1074 delete sharedRefcount;
1077 if (!d->wasWidget && d->isSignalConnected(0)) {
1078 emit destroyed(
this);
1081 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::destroyed)
1082 QAbstractDeclarativeData::destroyed(d->declarativeData,
this);
1084 QObjectPrivate::ConnectionData *cd = d->connections.loadAcquire();
1086 if (cd->currentSender) {
1087 cd->currentSender->receiverDeleted();
1088 cd->currentSender =
nullptr;
1091 QBasicMutex *signalSlotMutex = signalSlotLock(
this);
1092 QMutexLocker locker(signalSlotMutex);
1095 int receiverCount = cd->signalVectorCount();
1096 for (
int signal = -1; signal < receiverCount; ++signal) {
1097 QObjectPrivate::ConnectionList &connectionList = cd->connectionsForSignal(signal);
1099 while (QObjectPrivate::Connection *c = connectionList.first.loadRelaxed()) {
1100 Q_ASSERT(c->receiver.loadAcquire());
1102 QBasicMutex *m = signalSlotLock(c->receiver.loadRelaxed());
1103 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1104 if (c == connectionList.first.loadAcquire() && c->receiver.loadAcquire()) {
1105 cd->removeConnection(c);
1106 Q_ASSERT(connectionList.first.loadRelaxed() != c);
1114
1115 while (QObjectPrivate::Connection *node = cd->senders) {
1116 Q_ASSERT(node->receiver.loadAcquire());
1117 QObject *sender = node->sender;
1121 sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), node->signal_index));
1122 QBasicMutex *m = signalSlotLock(sender);
1123 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1125 if (node != cd->senders) {
1127 Q_ASSERT(needToUnlock);
1132 QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections.loadRelaxed();
1133 Q_ASSERT(senderData);
1135 QtPrivate::QSlotObjectBase *slotObj =
nullptr;
1136 if (node->isSlotObject) {
1137 slotObj = node->slotObj;
1138 node->isSlotObject =
false;
1141 senderData->removeConnection(node);
1143
1144
1145
1146
1147
1148
1149
1150 const bool locksAreTheSame = signalSlotMutex == m;
1151 if (!locksAreTheSame)
1153 senderData->cleanOrphanedConnections(
1155 QObjectPrivate::ConnectionData::AlreadyLockedAndTemporarilyReleasingLock
1160 if (locksAreTheSame)
1163 slotObj->destroyIfLastRef();
1169 cd->currentConnectionId.storeRelaxed(0);
1171 if (cd && !cd->ref.deref())
1173 d->connections.storeRelaxed(
nullptr);
1175 if (!d->children.isEmpty())
1176 d->deleteChildren();
1178 if (Q_UNLIKELY(qtHookData[QHooks::RemoveQObject]))
1179 reinterpret_cast<QHooks::RemoveQObjectCallback>(qtHookData[QHooks::RemoveQObject])(
this);
1181 Q_TRACE(QObject_dtor,
this);
1184 d->setParent_helper(
nullptr);
1450bool QObject::event(QEvent *e)
1452 switch (e->type()) {
1454 timerEvent((QTimerEvent *)e);
1457 case QEvent::ChildAdded:
1458 case QEvent::ChildPolished:
1459 case QEvent::ChildRemoved:
1460 childEvent((QChildEvent *)e);
1463 case QEvent::DeferredDelete:
1467 case QEvent::MetaCall:
1469 QAbstractMetaCallEvent *mce =
static_cast<QAbstractMetaCallEvent*>(e);
1471 QObjectPrivate::ConnectionData *connections = d_func()->connections.loadAcquire();
1473 QMutexLocker locker(signalSlotLock(
this));
1474 d_func()->ensureConnectionData();
1475 connections = d_func()->connections.loadRelaxed();
1477 QObjectPrivate::Sender sender(
this,
const_cast<QObject*>(mce->sender()), mce->signalId(), connections);
1479 mce->placeMetaCall(
this);
1483 case QEvent::ThreadChange: {
1485 QThreadData *threadData = d->threadData.loadRelaxed();
1486 QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
1487 if (eventDispatcher) {
1488 QList<QAbstractEventDispatcher::TimerInfoV2> timers = eventDispatcher->timersForObject(
this);
1489 if (!timers.isEmpty()) {
1490 const bool res = eventDispatcher->unregisterTimers(
this);
1492 Q_ASSERT_X(res, Q_FUNC_INFO,
1493 "QAbstractEventDispatcher::unregisterTimers() returned false,"
1494 " but there are timers associated with this object.");
1495 auto reRegisterTimers = [
this, timers = std::move(timers)]() {
1496 QAbstractEventDispatcher *eventDispatcher =
1497 d_func()->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
1498 for (
const auto &ti : timers)
1499 eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType,
this);
1501 QMetaObject::invokeMethod(
this, std::move(reRegisterTimers), Qt::QueuedConnection);
1508 if (e->type() >= QEvent::User) {
1705bool QObject::moveToThread(QThread *targetThread QT6_IMPL_NEW_OVERLOAD_TAIL)
1709 if (d->threadData.loadRelaxed()->thread.loadAcquire() == targetThread) {
1714 if (d->parent !=
nullptr) {
1715 qWarning(
"QObject::moveToThread: Cannot move objects with a parent");
1719 qWarning(
"QObject::moveToThread: Widgets cannot be moved to a new thread");
1722 if (!d->bindingStorage.isEmpty()) {
1723 qWarning(
"QObject::moveToThread: Can not move objects that contain bindings or are used in bindings to a new thread.");
1727 QThreadData *currentData = QThreadData::current();
1728 QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) :
nullptr;
1729 QThreadData *thisThreadData = d->threadData.loadAcquire();
1730 if (!thisThreadData->thread.loadRelaxed() && currentData == targetData) {
1732 currentData = thisThreadData;
1733 }
else if (thisThreadData != currentData) {
1734 qWarning(
"QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
1735 "Cannot move to target thread (%p)\n",
1736 currentData->thread.loadRelaxed(), thisThreadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() :
nullptr);
1739 qWarning(
"You might be loading two sets of Qt binaries into the same process. "
1740 "Check that all plugins are compiled against the right Qt binaries. Export "
1741 "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.");
1748 d->moveToThread_helper();
1751 targetData =
new QThreadData(0);
1754 QMutexLocker l(signalSlotLock(
this));
1756 QOrderedMutexLocker locker(¤tData->postEventList.mutex,
1757 &targetData->postEventList.mutex);
1763 auto threadPrivate = targetThread
1764 ?
static_cast<QThreadPrivate *>(QThreadPrivate::get(targetThread))
1766 QBindingStatus *bindingStatus = threadPrivate
1767 ? threadPrivate->bindingStatus()
1769 if (threadPrivate && !bindingStatus) {
1770 bindingStatus = threadPrivate->addObjectWithPendingBindingStatusChange(
this);
1772 d_func()->setThreadData_helper(currentData, targetData, bindingStatus);
1777 currentData->deref();
1793void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status)
1799 this->bindingStorage.bindingStatus = status;
1803 qsizetype eventsMoved = 0;
1804 for (qsizetype i = 0; i < currentData->postEventList.size(); ++i) {
1805 const QPostEvent &pe = currentData->postEventList.at(i);
1808 if (pe.receiver == q) {
1810 targetData->postEventList.addEvent(pe);
1811 const_cast<QPostEvent &>(pe).event =
nullptr;
1815 if (eventsMoved > 0 && targetData->hasEventDispatcher()) {
1816 targetData->canWait =
false;
1817 targetData->eventDispatcher.loadRelaxed()->wakeUp();
1821 ConnectionData *cd = connections.loadAcquire();
1823 if (cd->currentSender) {
1824 cd->currentSender->receiverDeleted();
1825 cd->currentSender =
nullptr;
1830 auto *c = cd->senders;
1832 QObject *r = c->receiver.loadRelaxed();
1836 QThreadData *old = c->receiverThreadData.loadRelaxed();
1839 c->receiverThreadData.storeRelaxed(targetData);
1849 threadData.loadRelaxed()->deref();
1852 threadData.storeRelease(targetData);
1854 for (
int i = 0; i < children.size(); ++i) {
1855 QObject *child = children.at(i);
1856 child->d_func()->setThreadData_helper(currentData, targetData, status);
2286void QObjectPrivate::setParent_helper(QObject *o)
2289 Q_ASSERT_X(q != o, Q_FUNC_INFO,
"Cannot parent a QObject to itself");
2291 const auto checkForParentChildLoops = qScopeGuard([&](){
2295 if (++depth == CheckForParentChildLoopsWarnDepth) {
2296 qWarning(
"QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
2297 "this is undefined behavior",
2298 q, q->metaObject()->className(), qPrintable(q->objectName()));
2309 QObjectPrivate *parentD = parent->d_func();
2310 if (parentD->isDeletingChildren && wasDeleted
2311 && parentD->currentChildBeingDeleted == q) {
2315 const qsizetype index = parentD->children.indexOf(q);
2318 }
else if (parentD->isDeletingChildren) {
2319 parentD->children[index] =
nullptr;
2321 parentD->children.removeAt(index);
2322 if (sendChildEvents && parentD->receiveChildEvents) {
2323 QChildEvent e(QEvent::ChildRemoved, q);
2324 QCoreApplication::sendEvent(parent, &e);
2330 if (receiveParentEvents) {
2331 Q_ASSERT(!isWidget);
2332 QEvent e(QEvent::ParentAboutToChange);
2333 QCoreApplication::sendEvent(q, &e);
2340 if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) {
2341 qWarning(
"QObject::setParent: Cannot set parent, new parent is in a different thread");
2345 parent->d_func()->children.append(q);
2346 if (sendChildEvents && parent->d_func()->receiveChildEvents) {
2348 QChildEvent e(QEvent::ChildAdded, q);
2349 QCoreApplication::sendEvent(parent, &e);
2354 if (receiveParentEvents) {
2355 Q_ASSERT(!isWidget);
2356 QEvent e(QEvent::ParentChange);
2357 QCoreApplication::sendEvent(q, &e);
3081QMetaObject::Connection QObject::connect(
const QObject *sender,
const char *signal,
3082 const QObject *receiver,
const char *method,
3083 Qt::ConnectionType type)
3085 if (sender ==
nullptr || receiver ==
nullptr || signal ==
nullptr || method ==
nullptr) {
3086 qCWarning(lcConnect,
"QObject::connect: Cannot connect %s::%s to %s::%s",
3087 sender ? sender->metaObject()->className() :
"(nullptr)",
3088 (signal && *signal) ? signal + 1 :
"(nullptr)",
3089 receiver ? receiver->metaObject()->className() :
"(nullptr)",
3090 (method && *method) ? method + 1 :
"(nullptr)");
3091 return QMetaObject::Connection(
nullptr);
3094 if (!check_signal_macro(sender, signal,
"connect",
"bind"))
3095 return QMetaObject::Connection(
nullptr);
3097 int membcode = extract_code(method);
3098 if (!check_method_code(membcode, receiver, method,
"connect"))
3099 return QMetaObject::Connection(
nullptr);
3101 QByteArray pinnedSignal;
3102 const QMetaObject *smeta = sender->metaObject();
3103 const char *signal_arg = signal;
3105 QByteArrayView signalView{signal};
3106 QArgumentTypeArray signalTypes;
3107 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3108 QByteArrayView signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3109 int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3110 if (signal_index < 0) {
3112 pinnedSignal = QMetaObjectPrivate::normalizedSignature(signalView);
3113 signalView = pinnedSignal;
3115 signalTypes.clear();
3116 signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3117 smeta = sender->metaObject();
3118 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3120 if (signal_index < 0) {
3121 err_method_notfound(sender, signal_arg,
"connect");
3122 err_info_about_objects(
"connect", sender, receiver);
3123 return QMetaObject::Connection(
nullptr);
3125 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3126 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3128 QByteArray pinnedMethod;
3129 const char *method_arg = method;
3131 QByteArrayView methodView{method};
3133 QArgumentTypeArray methodTypes;
3134 QByteArrayView methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3135 const QMetaObject *rmeta = receiver->metaObject();
3136 int method_index_relative = -1;
3137 Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
3140 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3141 &rmeta, methodName, methodTypes);
3144 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3145 &rmeta, methodName, methodTypes);
3149 if (method_index_relative < 0) {
3151 pinnedMethod = QMetaObjectPrivate::normalizedSignature(methodView);
3152 methodView = pinnedMethod;
3154 methodTypes.clear();
3155 methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3157 rmeta = receiver->metaObject();
3160 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3161 &rmeta, methodName, methodTypes);
3164 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3165 &rmeta, methodName, methodTypes);
3170 if (method_index_relative < 0) {
3171 err_method_notfound(receiver, method_arg,
"connect");
3172 err_info_about_objects(
"connect", sender, receiver);
3173 return QMetaObject::Connection(
nullptr);
3176 if (!QMetaObjectPrivate::checkConnectArgs(signalTypes, methodTypes)) {
3178 "QObject::connect: Incompatible sender/receiver arguments"
3179 "\n %s::%s --> %s::%s",
3180 sender->metaObject()->className(), signalView.constData(),
3181 receiver->metaObject()->className(), methodView.constData());
3182 return QMetaObject::Connection(
nullptr);
3187 int *types =
nullptr;
3188 if (type == Qt::QueuedConnection && !(types = queuedConnectionTypes(signalTypes))) {
3189 return QMetaObject::Connection(
nullptr);
3192 QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
3194 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3195 check_and_warn_compat(smeta, smethod, rmeta, rmethod);
3198#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
3199 check_and_warn_non_slot(
"connect", method, membcode, rmeta, rmethod);
3202 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3203 sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
3227QMetaObject::Connection QObject::connect(
const QObject *sender,
const QMetaMethod &signal,
3228 const QObject *receiver,
const QMetaMethod &method,
3229 Qt::ConnectionType type)
3231 if (sender ==
nullptr
3232 || receiver ==
nullptr
3233 || signal.methodType() != QMetaMethod::Signal
3234 || method.methodType() == QMetaMethod::Constructor) {
3235 qCWarning(lcConnect,
"QObject::connect: Cannot connect %s::%s to %s::%s",
3236 sender ? sender->metaObject()->className() :
"(nullptr)",
3237 signal.methodSignature().constData(),
3238 receiver ? receiver->metaObject()->className() :
"(nullptr)",
3239 method.methodSignature().constData());
3240 return QMetaObject::Connection(
nullptr);
3247 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3248 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3251 const QMetaObject *smeta = sender->metaObject();
3252 const QMetaObject *rmeta = receiver->metaObject();
3253 if (signal_index == -1) {
3254 qCWarning(lcConnect,
"QObject::connect: Can't find signal %s on instance of class %s",
3255 signal.methodSignature().constData(), smeta->className());
3256 return QMetaObject::Connection(
nullptr);
3258 if (method_index == -1) {
3259 qCWarning(lcConnect,
"QObject::connect: Can't find method %s on instance of class %s",
3260 method.methodSignature().constData(), rmeta->className());
3261 return QMetaObject::Connection(
nullptr);
3264 if (!QMetaObject::checkConnectArgs(signal.methodSignature().constData(),
3265 method.methodSignature().constData())) {
3267 "QObject::connect: Incompatible sender/receiver arguments"
3268 "\n %s::%s --> %s::%s",
3269 smeta->className(), signal.methodSignature().constData(), rmeta->className(),
3270 method.methodSignature().constData());
3271 return QMetaObject::Connection(
nullptr);
3274 int *types =
nullptr;
3275 if ((type == Qt::QueuedConnection) && !(types = queuedConnectionTypes(signal)))
3276 return QMetaObject::Connection(
nullptr);
3279 check_and_warn_compat(smeta, signal, rmeta, method);
3281 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3282 sender, signal_index, signal.enclosingMetaObject(), receiver, method_index,
nullptr, type, types));
3367bool QObject::disconnect(
const QObject *sender,
const char *signal,
3368 const QObject *receiver,
const char *method)
3370 if (sender ==
nullptr || (receiver ==
nullptr && method !=
nullptr)) {
3371 qCWarning(lcConnect,
"QObject::disconnect: Unexpected nullptr parameter");
3375 const char *signal_arg = signal;
3377 if (!check_signal_macro(sender, signal,
"disconnect",
"unbind"))
3382 const char *method_arg = method;
3385 membcode = extract_code(method);
3386 if (!check_method_code(membcode, receiver, method,
"disconnect"))
3391 QByteArray pinnedSignal;
3392 const QMetaObject *smeta = sender->metaObject();
3393 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3394 int signal_index = -1;
3395 QByteArrayView signalName;
3396 QArgumentTypeArray signalTypes;
3398 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3399 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3400 if (signal_index == -1) {
3401 pinnedSignal = QMetaObject::normalizedSignature(signal);
3402 signal = pinnedSignal.constData();
3403 signalTypes.clear();
3404 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3405 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3408 if (signal_index == -1) {
3409 err_method_notfound(sender, signal_arg,
"disconnect");
3410 err_info_about_objects(
"disconnect", sender, receiver);
3415 auto getMethodIndex = [](
int code,
const QMetaObject *mo, QByteArrayView name,
3416 const QArgumentTypeArray &types) {
3419 return QMetaObjectPrivate::indexOfSlot(mo, name, types);
3421 return QMetaObjectPrivate::indexOfSignal(mo, name, types);
3426 QByteArray pinnedMethod;
3427 const QMetaObject *rmeta = receiver ? receiver->metaObject() :
nullptr;
3428 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 7);
3429 int method_index = -1;
3430 QByteArrayView methodName;
3431 QArgumentTypeArray methodTypes;
3433 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3434 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3435 if (method_index == -1) {
3436 pinnedMethod = QMetaObject::normalizedSignature(method);
3437 method = pinnedMethod.constData();
3438 methodTypes.clear();
3439 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3440 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3442 if (method_index == -1) {
3443 err_method_notfound(receiver, method_arg,
"disconnect");
3444 err_info_about_objects(
"disconnect", sender, receiver);
3450
3451
3452
3457 if (smeta != sender->metaObject()) {
3458 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3461 if (signal_index < 0)
3463 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3464 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3468 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1,
nullptr);
3472 if (rmeta != receiver->metaObject())
3473 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3474 if (method_index >= 0) {
3475#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
3476 check_and_warn_non_slot(
"disconnect", method, membcode, rmeta,
3477 rmeta->method(method_index));
3479 while (method_index < rmeta->methodOffset())
3480 rmeta = rmeta->superClass();
3482 if (method_index < 0)
3484 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index,
nullptr);
3485 }
while ((rmeta = rmeta->superClass()));
3487 }
while (signal && (smeta = smeta->superClass()));
3491 const_cast<QObject *>(sender)->disconnectNotify(QMetaMethod());
3530bool QObject::disconnect(
const QObject *sender,
const QMetaMethod &signal,
3531 const QObject *receiver,
const QMetaMethod &method)
3533 if (sender ==
nullptr || (receiver ==
nullptr && method.mobj !=
nullptr)) {
3534 qCWarning(lcConnect,
"QObject::disconnect: Unexpected nullptr parameter");
3538 if (signal.methodType() != QMetaMethod::Signal) {
3539 qCWarning(lcConnect,
"QObject::%s: Attempt to %s non-signal %s::%s",
3540 "disconnect",
"unbind",
3541 sender->metaObject()->className(), signal.methodSignature().constData());
3546 if (method.methodType() == QMetaMethod::Constructor) {
3547 qCWarning(lcConnect,
"QObject::disconnect: cannot use constructor as argument %s::%s",
3548 receiver->metaObject()->className(), method.methodSignature().constData());
3557 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3558 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3562 if (signal.mobj && signal_index == -1) {
3563 qCWarning(lcConnect,
"QObject::disconnect: signal %s not found on class %s",
3564 signal.methodSignature().constData(), sender->metaObject()->className());
3568 if (receiver && method.mobj && method_index == -1) {
3569 qCWarning(lcConnect,
"QObject::disconnect: method %s not found on class %s",
3570 method.methodSignature().constData(), receiver->metaObject()->className());
3574 if (!QMetaObjectPrivate::disconnect(sender, signal_index, signal.mobj, receiver, method_index,
nullptr))
3577 if (!signal.isValid()) {
3582 const_cast<QObject *>(sender)->disconnectNotify(signal);
3739 int signal_index,
const QMetaObject *smeta,
3740 const QObject *receiver,
int method_index,
3741 const QMetaObject *rmeta,
int type,
int *types)
3743 QObject *s =
const_cast<QObject *>(sender);
3744 QObject *r =
const_cast<QObject *>(receiver);
3746 int method_offset = rmeta ? rmeta->methodOffset() : 0;
3748 QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall :
nullptr;
3750 QOrderedMutexLocker locker(signalSlotLock(sender),
3751 signalSlotLock(receiver));
3753 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3754 if (type & Qt::UniqueConnection && scd) {
3755 if (scd->signalVectorCount() > signal_index) {
3756 const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
3758 int method_index_absolute = method_index + method_offset;
3761 if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute)
3763 c2 = c2->nextConnectionList.loadRelaxed();
3767 type &= ~Qt::UniqueConnection;
3769 const bool isSingleShot = type & Qt::SingleShotConnection;
3770 type &= ~Qt::SingleShotConnection;
3772 Q_ASSERT(type >= 0);
3773 Q_ASSERT(type <= 3);
3775 std::unique_ptr<QObjectPrivate::Connection> c{
new QObjectPrivate::Connection};
3777 c->signal_index = signal_index;
3778 c->receiver.storeRelaxed(r);
3779 QThreadData *td = r->d_func()->threadData.loadAcquire();
3781 c->receiverThreadData.storeRelaxed(td);
3782 c->method_relative = method_index;
3783 c->method_offset = method_offset;
3784 c->connectionType = type;
3785 c->isSlotObject =
false;
3786 c->argumentTypes.storeRelaxed(types);
3787 c->callFunction = callFunction;
3788 c->isSingleShot = isSingleShot;
3790 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
3793 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3794 if (smethod.isValid())
3795 s->connectNotify(smethod);
3873bool QMetaObjectPrivate::disconnect(
const QObject *sender,
3874 int signal_index,
const QMetaObject *smeta,
3875 const QObject *receiver,
int method_index,
void **slot,
3876 DisconnectType disconnectType)
3881 QObject *s =
const_cast<QObject *>(sender);
3883 QBasicMutex *senderMutex = signalSlotLock(sender);
3884 QMutexLocker locker(senderMutex);
3886 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3890 bool success =
false;
3893 QObjectPrivate::ConnectionDataPointer connections(scd);
3895 if (signal_index < 0) {
3897 if (!receiver && method_index < 0 && sender->d_func()->isSignalConnected(0)) {
3898 qWarning(
"QObject::disconnect: wildcard call disconnects from destroyed signal of"
3899 " %s::%s", sender->metaObject()->className(),
3900 sender->objectName().isEmpty()
3902 : sender->objectName().toLocal8Bit().data());
3905 for (
int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
3906 if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
3909 }
else if (signal_index < scd->signalVectorCount()) {
3910 if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
3917 scd->cleanOrphanedConnections(s);
3919 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3920 if (smethod.isValid())
3921 s->disconnectNotify(smethod);
3977void QMetaObject::connectSlotsByName(QObject *o)
3981 const QMetaObject *mo = o->metaObject();
3983 const QObjectList list =
3984 o->findChildren<QObject *>()
3988 for (
int i = 0; i < mo->methodCount(); ++i) {
3989 const QByteArray slotSignature = mo->method(i).methodSignature();
3990 const char *slot = slotSignature.constData();
3994 if (slot[0] !=
'o' || slot[1] !=
'n' || slot[2] !=
'_')
3998 bool foundIt =
false;
3999 for (
int j = 0; j < list.size(); ++j) {
4000 const QObject *co = list.at(j);
4001 const QByteArray coName = co->objectName().toLatin1();
4004 if (coName.isEmpty() || qstrncmp(slot + 3, coName.constData(), coName.size()) || slot[coName.size()+3] !=
'_')
4007 const char *signal = slot + coName.size() + 4;
4010 const QMetaObject *smeta;
4011 int sigIndex = co->d_func()->signalIndex(signal, &smeta);
4017 QList<QByteArray> compatibleSignals;
4018 const QMetaObject *smo = co->metaObject();
4019 int sigLen =
int(qstrlen(signal)) - 1;
4020 for (
int k = QMetaObjectPrivate::absoluteSignalCount(smo)-1; k >= 0; --k) {
4021 const QMetaMethod method = QMetaObjectPrivate::signal(smo, k);
4022 if (!qstrncmp(method.methodSignature().constData(), signal, sigLen)) {
4023 smeta = method.enclosingMetaObject();
4025 compatibleSignals.prepend(method.methodSignature());
4028 if (compatibleSignals.size() > 1)
4029 qCWarning(lcConnectSlotsByName) <<
"QMetaObject::connectSlotsByName: Connecting slot" << slot
4030 <<
"with the first of the following compatible signals:" << compatibleSignals;
4037 if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) {
4039 qCDebug(lcConnectSlotsByName,
"%s",
4040 msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData());
4050 while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
4052 }
else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
4054 qsizetype iParen = slotSignature.indexOf(
'(');
4055 qsizetype iLastUnderscore = slotSignature.lastIndexOf(
'_', iParen - 1);
4056 if (iLastUnderscore > 3)
4058 "QMetaObject::connectSlotsByName: No matching signal for %s", slot);
4192static void queued_activate(QObject *sender,
int signal, QObjectPrivate::Connection *c,
void **argv)
4194 const int *argumentTypes = c->argumentTypes.loadRelaxed();
4195 if (!argumentTypes) {
4196 QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
4197 argumentTypes = queuedConnectionTypes(m);
4199 argumentTypes = &DIRECT_CONNECTION_ONLY;
4200 if (!c->argumentTypes.testAndSetOrdered(
nullptr, argumentTypes)) {
4201 if (argumentTypes != &DIRECT_CONNECTION_ONLY)
4202 delete[] argumentTypes;
4203 argumentTypes = c->argumentTypes.loadRelaxed();
4206 if (argumentTypes == &DIRECT_CONNECTION_ONLY)
4209 while (argumentTypes[nargs - 1])
4212 QMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
4213 QObject *receiver = c->receiver.loadRelaxed();
4219 SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj :
nullptr };
4222 QVarLengthArray<
const QtPrivate::QMetaTypeInterface *, 16> argTypes;
4223 argTypes.reserve(nargs);
4224 argTypes.emplace_back(
nullptr);
4225 for (
int n = 1; n < nargs; ++n) {
4226 argTypes.emplace_back(QMetaType(argumentTypes[n - 1]).iface());
4229 auto ev = c->isSlotObject ?
4230 std::make_unique<QQueuedMetaCallEvent>(c->slotObj,
4231 sender, signal, nargs, argTypes.data(), argv) :
4232 std::make_unique<QQueuedMetaCallEvent>(c->method_offset, c->method_relative, c->callFunction,
4233 sender, signal, nargs, argTypes.data(), argv);
4235 if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) {
4240 if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
4246 QCoreApplication::postEvent(receiver, ev.release());
4250void doActivate(QObject *sender,
int signal_index,
void **argv)
4252 QObjectPrivate *sp = QObjectPrivate::get(sender);
4257 Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
4259 if (sp->isDeclarativeSignalConnected(signal_index)
4260 && QAbstractDeclarativeData::signalEmitted) {
4261 Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
4262 QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
4263 signal_index, argv);
4266 const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() :
nullptr;
4268 void *empty_argv[] = {
nullptr };
4272 if (!sp->maybeSignalConnected(signal_index)) {
4274 if (callbacks_enabled && signal_spy_set->signal_begin_callback !=
nullptr)
4275 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4276 if (callbacks_enabled && signal_spy_set->signal_end_callback !=
nullptr)
4277 signal_spy_set->signal_end_callback(sender, signal_index);
4281 if (callbacks_enabled && signal_spy_set->signal_begin_callback !=
nullptr)
4282 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4284 bool senderDeleted =
false;
4286 Q_ASSERT(sp->connections.loadRelaxed());
4287 QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadAcquire());
4288 QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();
4290 const QObjectPrivate::ConnectionList *list;
4291 if (signal_index < signalVector->count())
4292 list = &signalVector->at(signal_index);
4294 list = &signalVector->at(-1);
4296 Qt::HANDLE currentThreadId = QThread::currentThreadId();
4297 bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
4301 uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
4303 QObjectPrivate::Connection *c = list->first.loadRelaxed();
4308 QObject *
const receiver = c->receiver.loadRelaxed();
4312 QThreadData *td = c->receiverThreadData.loadRelaxed();
4316 bool receiverInSameThread;
4317 if (inSenderThread) {
4318 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4321 QMutexLocker lock(signalSlotLock(receiver));
4322 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4328 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
4329 || (c->connectionType == Qt::QueuedConnection)) {
4330 queued_activate(sender, signal_index, c, argv);
4332#if QT_CONFIG(thread)
4333 }
else if (c->connectionType == Qt::BlockingQueuedConnection) {
4334 if (receiverInSameThread) {
4335 qWarning(
"Qt: Dead lock detected while activating a BlockingQueuedConnection: "
4336 "Sender is %s(%p), receiver is %s(%p)",
4337 sender->metaObject()->className(), sender,
4338 receiver->metaObject()->className(), receiver);
4341 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4346 QMutexLocker locker(signalSlotLock(receiver));
4347 if (!c->isSingleShot && !c->receiver.loadAcquire())
4349 QMetaCallEvent *ev = c->isSlotObject ?
4350 new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &latch) :
4351 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
4352 sender, signal_index, argv, &latch);
4353 QCoreApplication::postEvent(receiver, ev);
4360 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4363 QObjectPrivate::Sender senderData(
4364 receiverInSameThread ? receiver :
nullptr, sender, signal_index,
4365 receiverInSameThread ? QObjectPrivate::get(receiver)->connections.loadAcquire() :
nullptr);
4367 if (c->isSlotObject) {
4368 SlotObjectGuard obj{c->slotObj};
4371 Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
4372 obj->call(receiver, argv);
4374 }
else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
4376 const int method_relative = c->method_relative;
4377 const auto callFunction = c->callFunction;
4378 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
4379 if (callbacks_enabled && signal_spy_set->slot_begin_callback !=
nullptr)
4380 signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
4383 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
4384 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
4387 if (callbacks_enabled && signal_spy_set->slot_end_callback !=
nullptr)
4388 signal_spy_set->slot_end_callback(receiver, methodIndex);
4390 const int method = c->method_relative + c->method_offset;
4392 if (callbacks_enabled && signal_spy_set->slot_begin_callback !=
nullptr) {
4393 signal_spy_set->slot_begin_callback(receiver, method, argv);
4397 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
4398 QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
4401 if (callbacks_enabled && signal_spy_set->slot_end_callback !=
nullptr)
4402 signal_spy_set->slot_end_callback(receiver, method);
4404 }
while ((c = c->nextConnectionList.loadRelaxed()) !=
nullptr && c->id <= highestConnectionId);
4406 }
while (list != &signalVector->at(-1) &&
4408 ((list = &signalVector->at(-1)),
true));
4410 if (connections->currentConnectionId.loadRelaxed() == 0)
4411 senderDeleted =
true;
4413 if (!senderDeleted) {
4414 sp->connections.loadAcquire()->cleanOrphanedConnections(sender);
4416 if (callbacks_enabled && signal_spy_set->signal_end_callback !=
nullptr)
4417 signal_spy_set->signal_end_callback(sender, signal_index);
4655void QObject::dumpObjectInfo()
const
4657 qDebug(
"OBJECT %s::%s", metaObject()->className(),
4658 objectName().isEmpty() ?
"unnamed" : objectName().toLocal8Bit().data());
4661 QMutexLocker locker(signalSlotLock(
this));
4664 qDebug(
" SIGNALS OUT");
4666 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
4667 if (cd && cd->signalVectorCount() > 0) {
4668 QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
4669 for (
int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
4670 const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
4673 const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index);
4674 qDebug(
" signal: %s", signal.methodSignature().constData());
4678 if (!c->receiver.loadRelaxed()) {
4679 qDebug(
" <Disconnected receiver>");
4680 c = c->nextConnectionList.loadRelaxed();
4683 if (c->isSlotObject) {
4684 qDebug(
" <functor or function pointer>");
4685 c = c->nextConnectionList.loadRelaxed();
4688 const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
4689 const QMetaMethod method = receiverMetaObject->method(c->method());
4690 qDebug(
" --> %s::%s %s",
4691 receiverMetaObject->className(),
4692 c->receiver.loadRelaxed()->objectName().isEmpty() ?
"unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
4693 method.methodSignature().constData());
4694 c = c->nextConnectionList.loadRelaxed();
4698 qDebug(
" <None>" );
4702 qDebug(
" SIGNALS IN");
4704 if (cd && cd->senders) {
4705 for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
4706 QByteArray slotName = QByteArrayLiteral(
"<unknown>");
4707 if (!s->isSlotObject) {
4708 const QMetaMethod slot = metaObject()->method(s->method());
4709 slotName = slot.methodSignature();
4711 qDebug(
" <-- %s::%s %s",
4712 s->sender->metaObject()->className(),
4713 s->sender->objectName().isEmpty() ?
"unnamed" : qPrintable(s->sender->objectName()),
4714 slotName.constData());
5492QMetaObject::Connection QObjectPrivate::connectImpl(
const QObject *sender,
int signal_index,
5493 const QObject *receiver,
void **slot,
5494 QtPrivate::QSlotObjectBase *slotObjRaw,
int type,
5495 const int *types,
const QMetaObject *senderMetaObject)
5497 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5499 if (!sender || !receiver || !slotObj || !senderMetaObject) {
5500 connectWarning(sender, senderMetaObject, receiver,
"invalid nullptr parameter");
5501 return QMetaObject::Connection();
5504 if (type & Qt::UniqueConnection && !slot) {
5505 connectWarning(sender, senderMetaObject, receiver,
"unique connections require a pointer to member function of a QObject subclass");
5506 return QMetaObject::Connection();
5509 QObject *s =
const_cast<QObject *>(sender);
5510 QObject *r =
const_cast<QObject *>(receiver);
5512 QOrderedMutexLocker locker(signalSlotLock(sender),
5513 signalSlotLock(receiver));
5515 if (type & Qt::UniqueConnection) {
5516 QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
5517 if (connections && connections->signalVectorCount() > signal_index) {
5518 const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
5521 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot))
5522 return QMetaObject::Connection();
5523 c2 = c2->nextConnectionList.loadRelaxed();
5527 type &= ~Qt::UniqueConnection;
5529 const bool isSingleShot = type & Qt::SingleShotConnection;
5530 type &= ~Qt::SingleShotConnection;
5532 Q_ASSERT(type >= 0);
5533 Q_ASSERT(type <= 3);
5535 std::unique_ptr<QObjectPrivate::Connection> c{
new QObjectPrivate::Connection};
5537 c->signal_index = signal_index;
5538 QThreadData *td = r->d_func()->threadData.loadAcquire();
5540 c->receiverThreadData.storeRelaxed(td);
5541 c->receiver.storeRelaxed(r);
5542 c->connectionType = type;
5543 c->isSlotObject =
true;
5544 c->slotObj = slotObj.release();
5546 c->argumentTypes.storeRelaxed(types);
5547 c->ownArgumentTypes =
false;
5549 c->isSingleShot = isSingleShot;
5551 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
5552 QMetaObject::Connection ret(c.release());
5555 QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
5556 Q_ASSERT(method.isValid());
5557 s->connectNotify(method);