373 TaggedSignalVector c =
nullptr;
375 std::unique_lock<QBasicMutex> lock(*senderMutex, std::defer_lock_t{});
376 if (lockPolicy == NeedToLock)
378 if (ref.loadAcquire() > 1)
384 c = orphaned.exchange(
nullptr, std::memory_order_relaxed);
388 if (lockPolicy == AlreadyLockedAndTemporarilyReleasingLock) {
389 senderMutex->unlock();
398inline void QObjectPrivate::ConnectionData::deleteOrphaned(TaggedSignalVector o)
401 TaggedSignalVector next =
nullptr;
402 if (SignalVector *v =
static_cast<SignalVector *>(o)) {
403 next = v->nextInOrphanList;
406 QObjectPrivate::Connection *c =
static_cast<Connection *>(o);
407 next = c->nextInOrphanList;
408 Q_ASSERT(!c->receiver.loadRelaxed());
418
419
420
421
422
423bool QObjectPrivate::isSignalConnected(uint signalIndex,
bool checkDeclarative)
const
425 if (checkDeclarative && isDeclarativeSignalConnected(signalIndex))
428 ConnectionData *cd = connections.loadAcquire();
431 SignalVector *signalVector = cd->signalVector.loadRelaxed();
435 if (signalVector->at(-1).first.loadRelaxed())
438 if (signalIndex < uint(cd->signalVectorCount())) {
439 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadRelaxed();
441 if (c->receiver.loadRelaxed())
443 c = c->nextConnectionList.loadRelaxed();
449bool QObjectPrivate::maybeSignalConnected(uint signalIndex)
const
451 ConnectionData *cd = connections.loadAcquire();
454 SignalVector *signalVector = cd->signalVector.loadRelaxed();
458 if (signalVector->at(-1).first.loadAcquire())
461 if (signalIndex < uint(cd->signalVectorCount())) {
462 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadAcquire();
468void QObjectPrivate::reinitBindingStorageAfterThreadMove()
470 bindingStorage.reinitAfterThreadMove();
471 for (
int i = 0; i < children.size(); ++i)
472 children[i]->d_func()->reinitBindingStorageAfterThreadMove();
476
477
478QAbstractMetaCallEvent::~QAbstractMetaCallEvent()
487
488
489
490
491
492QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative,
493 QObjectPrivate::StaticMetaCallFunction callFunction,
494 const QObject *sender,
int signalId,
495 void **args, QLatch *latch)
496 : QAbstractMetaCallEvent(sender, signalId, latch),
497 d{
nullptr, args, callFunction, 0, method_offset, method_relative}
502
503
504
505
506
507QMetaCallEvent::QMetaCallEvent(QtPrivate::QSlotObjectBase *slotO,
508 const QObject *sender,
int signalId,
509 void **args, QLatch *latch)
510 : QAbstractMetaCallEvent(sender, signalId, latch),
511 d{QtPrivate::SlotObjUniquePtr{slotO}, args,
nullptr, 0, 0, ushort(-1)}
518
519
520
521
522
523QMetaCallEvent::QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotO,
524 const QObject *sender,
int signalId,
525 void **args, QLatch *latch)
526 : QAbstractMetaCallEvent(sender, signalId, latch),
527 d{std::move(slotO), args,
nullptr, 0, 0, ushort(-1)}
532
533
534QMetaCallEvent::QMetaCallEvent(
const QObject *sender,
int signalId, Data &&data)
535 : QAbstractMetaCallEvent(sender, signalId),
541
542
543void QMetaCallEvent::placeMetaCall(QObject *object)
546 d.slotObj_->call(object, d.args_);
547 }
else if (d.callFunction_ && d.method_offset_ <= object->metaObject()->methodOffset()) {
548 d.callFunction_(object, QMetaObject::InvokeMetaMethod, d.method_relative_, d.args_);
550 QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod,
551 d.method_offset_ + d.method_relative_, d.args_);
556
557
558
559
560QQueuedMetaCallEvent::QQueuedMetaCallEvent(ushort method_offset, ushort method_relative,
561 QObjectPrivate::StaticMetaCallFunction callFunction,
562 const QObject *sender,
int signalId,
int argCount,
563 const QtPrivate::QMetaTypeInterface *
const *argTypes,
564 const void *
const *argValues)
565 : QMetaCallEvent(sender, signalId, {
nullptr,
nullptr, callFunction, argCount,
566 method_offset, method_relative}),
569 copyArgValues(argCount, argTypes, argValues);
573
574
575
576
577QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
578 const QObject *sender,
int signalId,
int argCount,
579 const QtPrivate::QMetaTypeInterface *
const *argTypes,
580 const void *
const *argValues)
581 : QMetaCallEvent(sender, signalId, {QtPrivate::SlotObjUniquePtr(slotObj),
nullptr,
nullptr, argCount,
587 copyArgValues(argCount, argTypes, argValues);
591
592
593
594
595QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,
596 const QObject *sender,
int signalId,
int argCount,
597 const QtPrivate::QMetaTypeInterface *
const *argTypes,
598 const void *
const *argValues)
599 : QMetaCallEvent(sender, signalId, {std::move(slotObj),
nullptr,
nullptr, argCount,
603 copyArgValues(argCount, argTypes, argValues);
607
608
609QQueuedMetaCallEvent::~QQueuedMetaCallEvent()
611 const QMetaType *t =
reinterpret_cast<QMetaType *>(d.args_ + d.nargs_);
612 int inplaceIndex = 0;
613 for (
int i = 0; i < d.nargs_; ++i) {
614 if (t[i].isValid() && d.args_[i]) {
615 if (typeFitsInPlace(t[i]) && inplaceIndex < InplaceValuesCapacity) {
617 void *where = &valuesPrealloc_[inplaceIndex++].storage;
618 t[i].destruct(where);
621 t[i].destroy(d.args_[i]);
626 if (
static_cast<
void *>(d.args_) != prealloc_)
627 QtPrivate::sizedFree(d.args_, d.nargs_, PtrAndTypeSize);
632
633
634inline void QQueuedMetaCallEvent::allocArgs()
639 void *
const memory = d.nargs_ * PtrAndTypeSize >
sizeof(prealloc_) ?
640 calloc(d.nargs_, PtrAndTypeSize) : prealloc_;
643 d.args_ =
static_cast<
void **>(memory);
647
648
649inline void QQueuedMetaCallEvent::copyArgValues(
int argCount,
const QtPrivate::QMetaTypeInterface *
const *argTypes,
650 const void *
const *argValues)
653 void **args = d.args_;
654 QMetaType *types =
reinterpret_cast<QMetaType *>(d.args_ + d.nargs_);
655 int inplaceIndex = 0;
658 types[0] = QMetaType();
663 for (
int n = 1; n < argCount; ++n) {
664 types[n] = QMetaType(argTypes[n]);
665 if (typeFitsInPlace(types[n]) && inplaceIndex < InplaceValuesCapacity) {
667 void *where = &valuesPrealloc_[inplaceIndex++].storage;
668 types[n].construct(where, argValues[n]);
672 args[n] = types[n].create(argValues[n]);
678
679
680inline bool QQueuedMetaCallEvent::typeFitsInPlace(
const QMetaType type)
682 return (q20::cmp_less_equal(type.sizeOf(),
sizeof(ArgValueStorage)) &&
683 q20::cmp_less_equal(type.alignOf(),
alignof(ArgValueStorage)));
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
711
712
713
714
717
718
719
720
721
724
725
726
727
728
729
732
733
734
735
736
737
738
739
740
741
742
745
746
747
748
749
750
753
754
755
756
757
758
759
762
763
764
765
766
767
768
769
770
773
774
775
776
777
778
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
935
936
943 if (parent && parentThreadData != currentThreadData) {
944 QThread *parentThread = parentThreadData->thread.loadAcquire();
945 QThread *currentThread = currentThreadData->thread.loadAcquire();
946 qWarning(
"QObject: Cannot create children for a parent that is in a different thread.\n"
947 "(Parent is %s(%p), parent's thread is %s(%p), current thread is %s(%p)",
948 parent->metaObject()->className(),
950 parentThread ? parentThread->metaObject()->className() :
"QThread",
952 currentThread ? currentThread->metaObject()->className() :
"QThread",
960
961
962
963
964
965
966
967
968
969
970
971
972
974QObject::QObject(QObject *parent)
975 : QObject(*
new QObjectPrivate, parent)
980
981
982QObject::QObject(QObjectPrivate &dd, QObject *parent)
985 Q_ASSERT_X(
this != parent, Q_FUNC_INFO,
"Cannot parent a QObject to itself");
989 auto threadData = (parent && !parent->thread()) ? parent->d_func()->threadData.loadRelaxed() : QThreadData::current();
991 d->threadData.storeRelaxed(threadData);
994 if (!check_parent_thread(parent, parent ? parent->d_func()->threadData.loadRelaxed() :
nullptr, threadData))
996 if (d->willBeWidget) {
999 d->parent->d_func()->children.append(
this);
1006 threadData->deref();
1010 if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
1011 reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(
this);
1012 Q_TRACE(QObject_ctor,
this);
1047 d->wasDeleted =
true;
1050 if (!d->bindingStorage.isValid()) {
1053 if (QThread *ownThread = thread()) {
1054 auto *privThread =
static_cast<QThreadPrivate *>(
1055 QObjectPrivate::get(ownThread));
1056 privThread->removeObjectWithPendingBindingStatusChange(
this);
1062 d->clearBindingStorage();
1064 QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.loadRelaxed();
1065 if (sharedRefcount) {
1066 if (sharedRefcount->strongref.loadRelaxed() > 0) {
1067 qWarning(
"QObject: shared QObject was deleted directly. The program is malformed and may crash.");
1072 sharedRefcount->strongref.storeRelaxed(0);
1073 if (!sharedRefcount->weakref.deref())
1074 delete sharedRefcount;
1077 if (!d->wasWidget && d->isSignalConnected(0)) {
1078 emit destroyed(
this);
1081 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::destroyed)
1082 QAbstractDeclarativeData::destroyed(d->declarativeData,
this);
1084 QObjectPrivate::ConnectionData *cd = d->connections.loadAcquire();
1086 if (cd->currentSender) {
1087 cd->currentSender->receiverDeleted();
1088 cd->currentSender =
nullptr;
1091 QBasicMutex *signalSlotMutex = signalSlotLock(
this);
1092 QMutexLocker locker(signalSlotMutex);
1095 int receiverCount = cd->signalVectorCount();
1096 for (
int signal = -1; signal < receiverCount; ++signal) {
1097 QObjectPrivate::ConnectionList &connectionList = cd->connectionsForSignal(signal);
1099 while (QObjectPrivate::Connection *c = connectionList.first.loadRelaxed()) {
1100 Q_ASSERT(c->receiver.loadAcquire());
1102 QBasicMutex *m = signalSlotLock(c->receiver.loadRelaxed());
1103 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1104 if (c == connectionList.first.loadAcquire() && c->receiver.loadAcquire()) {
1105 cd->removeConnection(c);
1106 Q_ASSERT(connectionList.first.loadRelaxed() != c);
1114
1115 while (QObjectPrivate::Connection *node = cd->senders) {
1116 Q_ASSERT(node->receiver.loadAcquire());
1117 QObject *sender = node->sender;
1121 sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), node->signal_index));
1122 QBasicMutex *m = signalSlotLock(sender);
1123 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1125 if (node != cd->senders) {
1127 Q_ASSERT(needToUnlock);
1132 QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections.loadRelaxed();
1133 Q_ASSERT(senderData);
1135 QtPrivate::QSlotObjectBase *slotObj =
nullptr;
1136 if (node->isSlotObject) {
1137 slotObj = node->slotObj;
1138 node->isSlotObject =
false;
1141 senderData->removeConnection(node);
1143
1144
1145
1146
1147
1148
1149
1150 const bool locksAreTheSame = signalSlotMutex == m;
1151 if (!locksAreTheSame)
1153 senderData->cleanOrphanedConnections(
1155 QObjectPrivate::ConnectionData::AlreadyLockedAndTemporarilyReleasingLock
1160 if (locksAreTheSame)
1163 slotObj->destroyIfLastRef();
1169 cd->currentConnectionId.storeRelaxed(0);
1171 if (cd && !cd->ref.deref())
1173 d->connections.storeRelaxed(
nullptr);
1175 if (!d->children.isEmpty())
1176 d->deleteChildren();
1178 if (Q_UNLIKELY(qtHookData[QHooks::RemoveQObject]))
1179 reinterpret_cast<QHooks::RemoveQObjectCallback>(qtHookData[QHooks::RemoveQObject])(
this);
1181 Q_TRACE(QObject_dtor,
this);
1184 d->setParent_helper(
nullptr);
1450bool QObject::event(QEvent *e)
1452 switch (e->type()) {
1454 timerEvent((QTimerEvent *)e);
1457 case QEvent::ChildAdded:
1458 case QEvent::ChildPolished:
1459 case QEvent::ChildRemoved:
1460 childEvent((QChildEvent *)e);
1463 case QEvent::DeferredDelete:
1467 case QEvent::MetaCall:
1469 QAbstractMetaCallEvent *mce =
static_cast<QAbstractMetaCallEvent*>(e);
1471 QObjectPrivate::ConnectionData *connections = d_func()->connections.loadAcquire();
1473 QMutexLocker locker(signalSlotLock(
this));
1474 d_func()->ensureConnectionData();
1475 connections = d_func()->connections.loadRelaxed();
1477 QObjectPrivate::Sender sender(
this,
const_cast<QObject*>(mce->sender()), mce->signalId(), connections);
1479 mce->placeMetaCall(
this);
1483 case QEvent::ThreadChange: {
1485 QThreadData *threadData = d->threadData.loadRelaxed();
1486 QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
1487 if (eventDispatcher) {
1488 QList<QAbstractEventDispatcher::TimerInfoV2> timers = eventDispatcher->timersForObject(
this);
1489 if (!timers.isEmpty()) {
1490 const bool res = eventDispatcher->unregisterTimers(
this);
1492 Q_ASSERT_X(res, Q_FUNC_INFO,
1493 "QAbstractEventDispatcher::unregisterTimers() returned false,"
1494 " but there are timers associated with this object.");
1495 auto reRegisterTimers = [
this, timers = std::move(timers)]() {
1496 QAbstractEventDispatcher *eventDispatcher =
1497 d_func()->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
1498 for (
const auto &ti : timers)
1499 eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType,
this);
1501 QMetaObject::invokeMethod(
this, std::move(reRegisterTimers), Qt::QueuedConnection);
1508 if (e->type() >= QEvent::User) {
1705bool QObject::moveToThread(QThread *targetThread QT6_IMPL_NEW_OVERLOAD_TAIL)
1709 if (d->threadData.loadRelaxed()->thread.loadAcquire() == targetThread) {
1714 if (d->parent !=
nullptr) {
1715 qWarning(
"QObject::moveToThread: Cannot move objects with a parent");
1719 qWarning(
"QObject::moveToThread: Widgets cannot be moved to a new thread");
1722 if (!d->bindingStorage.isEmpty()) {
1723 qWarning(
"QObject::moveToThread: Can not move objects that contain bindings or are used in bindings to a new thread.");
1727 QThreadData *currentData = QThreadData::current();
1728 QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) :
nullptr;
1729 QThreadData *thisThreadData = d->threadData.loadAcquire();
1730 if (!thisThreadData->thread.loadRelaxed() && currentData == targetData) {
1732 currentData = thisThreadData;
1733 }
else if (thisThreadData != currentData) {
1734 qWarning(
"QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
1735 "Cannot move to target thread (%p)\n",
1736 currentData->thread.loadRelaxed(), thisThreadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() :
nullptr);
1739 qWarning(
"You might be loading two sets of Qt binaries into the same process. "
1740 "Check that all plugins are compiled against the right Qt binaries. Export "
1741 "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.");
1748 d->moveToThread_helper();
1751 targetData =
new QThreadData(0);
1754 QMutexLocker l(signalSlotLock(
this));
1756 QOrderedMutexLocker locker(¤tData->postEventList.mutex,
1757 &targetData->postEventList.mutex);
1763 auto threadPrivate = targetThread
1764 ?
static_cast<QThreadPrivate *>(QThreadPrivate::get(targetThread))
1766 QBindingStatus *bindingStatus = threadPrivate
1767 ? threadPrivate->bindingStatus()
1769 if (threadPrivate && !bindingStatus) {
1770 bindingStatus = threadPrivate->addObjectWithPendingBindingStatusChange(
this);
1772 d_func()->setThreadData_helper(currentData, targetData, bindingStatus);
1777 currentData->deref();
1793void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status)
1799 this->bindingStorage.bindingStatus = status;
1803 qsizetype eventsMoved = 0;
1804 for (qsizetype i = 0; i < currentData->postEventList.size(); ++i) {
1805 const QPostEvent &pe = currentData->postEventList.at(i);
1808 if (pe.receiver == q) {
1810 targetData->postEventList.addEvent(pe);
1811 const_cast<QPostEvent &>(pe).event =
nullptr;
1815 if (eventsMoved > 0 && targetData->hasEventDispatcher()) {
1816 targetData->canWait =
false;
1817 targetData->eventDispatcher.loadRelaxed()->wakeUp();
1821 ConnectionData *cd = connections.loadAcquire();
1823 if (cd->currentSender) {
1824 cd->currentSender->receiverDeleted();
1825 cd->currentSender =
nullptr;
1830 auto *c = cd->senders;
1832 QObject *r = c->receiver.loadRelaxed();
1836 QThreadData *old = c->receiverThreadData.loadRelaxed();
1839 c->receiverThreadData.storeRelaxed(targetData);
1849 threadData.loadRelaxed()->deref();
1852 threadData.storeRelease(targetData);
1854 for (
int i = 0; i < children.size(); ++i) {
1855 QObject *child = children.at(i);
1856 child->d_func()->setThreadData_helper(currentData, targetData, status);
2285void QObjectPrivate::setParent_helper(QObject *o)
2288 Q_ASSERT_X(q != o, Q_FUNC_INFO,
"Cannot parent a QObject to itself");
2290 const auto checkForParentChildLoops = qScopeGuard([&](){
2294 if (++depth == CheckForParentChildLoopsWarnDepth) {
2295 qWarning(
"QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
2296 "this is undefined behavior",
2297 q, q->metaObject()->className(), qPrintable(q->objectName()));
2308 QObjectPrivate *parentD = parent->d_func();
2309 if (parentD->isDeletingChildren && wasDeleted
2310 && parentD->currentChildBeingDeleted == q) {
2314 const qsizetype index = parentD->children.indexOf(q);
2317 }
else if (parentD->isDeletingChildren) {
2318 parentD->children[index] =
nullptr;
2320 parentD->children.removeAt(index);
2321 if (sendChildEvents && parentD->receiveChildEvents) {
2322 QChildEvent e(QEvent::ChildRemoved, q);
2323 QCoreApplication::sendEvent(parent, &e);
2329 if (receiveParentEvents) {
2330 Q_ASSERT(!isWidget);
2331 QEvent e(QEvent::ParentAboutToChange);
2332 QCoreApplication::sendEvent(q, &e);
2339 if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) {
2340 qWarning(
"QObject::setParent: Cannot set parent, new parent is in a different thread");
2344 parent->d_func()->children.append(q);
2345 if (sendChildEvents && parent->d_func()->receiveChildEvents) {
2347 QChildEvent e(QEvent::ChildAdded, q);
2348 QCoreApplication::sendEvent(parent, &e);
2353 if (receiveParentEvents) {
2354 Q_ASSERT(!isWidget);
2355 QEvent e(QEvent::ParentChange);
2356 QCoreApplication::sendEvent(q, &e);
3065QMetaObject::Connection QObject::connect(
const QObject *sender,
const char *signal,
3066 const QObject *receiver,
const char *method,
3067 Qt::ConnectionType type)
3069 if (sender ==
nullptr || receiver ==
nullptr || signal ==
nullptr || method ==
nullptr) {
3070 qCWarning(lcConnect,
"QObject::connect: Cannot connect %s::%s to %s::%s",
3071 sender ? sender->metaObject()->className() :
"(nullptr)",
3072 (signal && *signal) ? signal + 1 :
"(nullptr)",
3073 receiver ? receiver->metaObject()->className() :
"(nullptr)",
3074 (method && *method) ? method + 1 :
"(nullptr)");
3075 return QMetaObject::Connection(
nullptr);
3078 if (!check_signal_macro(sender, signal,
"connect",
"bind"))
3079 return QMetaObject::Connection(
nullptr);
3081 int membcode = extract_code(method);
3082 if (!check_method_code(membcode, receiver, method,
"connect"))
3083 return QMetaObject::Connection(
nullptr);
3085 QByteArray pinnedSignal;
3086 const QMetaObject *smeta = sender->metaObject();
3087 const char *signal_arg = signal;
3089 QByteArrayView signalView{signal};
3090 QArgumentTypeArray signalTypes;
3091 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3092 QByteArrayView signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3093 int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3094 if (signal_index < 0) {
3096 pinnedSignal = QMetaObjectPrivate::normalizedSignature(signalView);
3097 signalView = pinnedSignal;
3099 signalTypes.clear();
3100 signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3101 smeta = sender->metaObject();
3102 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3104 if (signal_index < 0) {
3105 err_method_notfound(sender, signal_arg,
"connect");
3106 err_info_about_objects(
"connect", sender, receiver);
3107 return QMetaObject::Connection(
nullptr);
3109 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3110 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3112 QByteArray pinnedMethod;
3113 const char *method_arg = method;
3115 QByteArrayView methodView{method};
3117 QArgumentTypeArray methodTypes;
3118 QByteArrayView methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3119 const QMetaObject *rmeta = receiver->metaObject();
3120 int method_index_relative = -1;
3121 Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
3124 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3125 &rmeta, methodName, methodTypes);
3128 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3129 &rmeta, methodName, methodTypes);
3133 if (method_index_relative < 0) {
3135 pinnedMethod = QMetaObjectPrivate::normalizedSignature(methodView);
3136 methodView = pinnedMethod;
3138 methodTypes.clear();
3139 methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3141 rmeta = receiver->metaObject();
3144 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3145 &rmeta, methodName, methodTypes);
3148 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3149 &rmeta, methodName, methodTypes);
3154 if (method_index_relative < 0) {
3155 err_method_notfound(receiver, method_arg,
"connect");
3156 err_info_about_objects(
"connect", sender, receiver);
3157 return QMetaObject::Connection(
nullptr);
3160 if (!QMetaObjectPrivate::checkConnectArgs(signalTypes, methodTypes)) {
3162 "QObject::connect: Incompatible sender/receiver arguments"
3163 "\n %s::%s --> %s::%s",
3164 sender->metaObject()->className(), signalView.constData(),
3165 receiver->metaObject()->className(), methodView.constData());
3166 return QMetaObject::Connection(
nullptr);
3171 int *types =
nullptr;
3172 if (type == Qt::QueuedConnection && !(types = queuedConnectionTypes(signalTypes))) {
3173 return QMetaObject::Connection(
nullptr);
3176 QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
3178 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3179 check_and_warn_compat(smeta, smethod, rmeta, rmethod);
3182#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
3183 check_and_warn_non_slot(
"connect", method, membcode, rmeta, rmethod);
3186 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3187 sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
3211QMetaObject::Connection QObject::connect(
const QObject *sender,
const QMetaMethod &signal,
3212 const QObject *receiver,
const QMetaMethod &method,
3213 Qt::ConnectionType type)
3215 if (sender ==
nullptr
3216 || receiver ==
nullptr
3217 || signal.methodType() != QMetaMethod::Signal
3218 || method.methodType() == QMetaMethod::Constructor) {
3219 qCWarning(lcConnect,
"QObject::connect: Cannot connect %s::%s to %s::%s",
3220 sender ? sender->metaObject()->className() :
"(nullptr)",
3221 signal.methodSignature().constData(),
3222 receiver ? receiver->metaObject()->className() :
"(nullptr)",
3223 method.methodSignature().constData());
3224 return QMetaObject::Connection(
nullptr);
3231 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3232 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3235 const QMetaObject *smeta = sender->metaObject();
3236 const QMetaObject *rmeta = receiver->metaObject();
3237 if (signal_index == -1) {
3238 qCWarning(lcConnect,
"QObject::connect: Can't find signal %s on instance of class %s",
3239 signal.methodSignature().constData(), smeta->className());
3240 return QMetaObject::Connection(
nullptr);
3242 if (method_index == -1) {
3243 qCWarning(lcConnect,
"QObject::connect: Can't find method %s on instance of class %s",
3244 method.methodSignature().constData(), rmeta->className());
3245 return QMetaObject::Connection(
nullptr);
3248 if (!QMetaObject::checkConnectArgs(signal.methodSignature().constData(),
3249 method.methodSignature().constData())) {
3251 "QObject::connect: Incompatible sender/receiver arguments"
3252 "\n %s::%s --> %s::%s",
3253 smeta->className(), signal.methodSignature().constData(), rmeta->className(),
3254 method.methodSignature().constData());
3255 return QMetaObject::Connection(
nullptr);
3258 int *types =
nullptr;
3259 if ((type == Qt::QueuedConnection) && !(types = queuedConnectionTypes(signal)))
3260 return QMetaObject::Connection(
nullptr);
3263 check_and_warn_compat(smeta, signal, rmeta, method);
3265 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3266 sender, signal_index, signal.enclosingMetaObject(), receiver, method_index,
nullptr, type, types));
3351bool QObject::disconnect(
const QObject *sender,
const char *signal,
3352 const QObject *receiver,
const char *method)
3354 if (sender ==
nullptr || (receiver ==
nullptr && method !=
nullptr)) {
3355 qCWarning(lcConnect,
"QObject::disconnect: Unexpected nullptr parameter");
3359 const char *signal_arg = signal;
3361 if (!check_signal_macro(sender, signal,
"disconnect",
"unbind"))
3366 const char *method_arg = method;
3369 membcode = extract_code(method);
3370 if (!check_method_code(membcode, receiver, method,
"disconnect"))
3375 QByteArray pinnedSignal;
3376 const QMetaObject *smeta = sender->metaObject();
3377 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3378 int signal_index = -1;
3379 QByteArrayView signalName;
3380 QArgumentTypeArray signalTypes;
3382 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3383 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3384 if (signal_index == -1) {
3385 pinnedSignal = QMetaObject::normalizedSignature(signal);
3386 signal = pinnedSignal.constData();
3387 signalTypes.clear();
3388 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3389 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3392 if (signal_index == -1) {
3393 err_method_notfound(sender, signal_arg,
"disconnect");
3394 err_info_about_objects(
"disconnect", sender, receiver);
3399 auto getMethodIndex = [](
int code,
const QMetaObject *mo, QByteArrayView name,
3400 const QArgumentTypeArray &types) {
3403 return QMetaObjectPrivate::indexOfSlot(mo, name, types);
3405 return QMetaObjectPrivate::indexOfSignal(mo, name, types);
3410 QByteArray pinnedMethod;
3411 const QMetaObject *rmeta = receiver ? receiver->metaObject() :
nullptr;
3412 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 7);
3413 int method_index = -1;
3414 QByteArrayView methodName;
3415 QArgumentTypeArray methodTypes;
3417 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3418 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3419 if (method_index == -1) {
3420 pinnedMethod = QMetaObject::normalizedSignature(method);
3421 method = pinnedMethod.constData();
3422 methodTypes.clear();
3423 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3424 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3426 if (method_index == -1) {
3427 err_method_notfound(receiver, method_arg,
"disconnect");
3428 err_info_about_objects(
"disconnect", sender, receiver);
3434
3435
3436
3441 if (smeta != sender->metaObject()) {
3442 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3445 if (signal_index < 0)
3447 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3448 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3452 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1,
nullptr);
3456 if (rmeta != receiver->metaObject())
3457 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3458 if (method_index >= 0) {
3459#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
3460 check_and_warn_non_slot(
"disconnect", method, membcode, rmeta,
3461 rmeta->method(method_index));
3463 while (method_index < rmeta->methodOffset())
3464 rmeta = rmeta->superClass();
3466 if (method_index < 0)
3468 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index,
nullptr);
3469 }
while ((rmeta = rmeta->superClass()));
3471 }
while (signal && (smeta = smeta->superClass()));
3475 const_cast<QObject *>(sender)->disconnectNotify(QMetaMethod());
3514bool QObject::disconnect(
const QObject *sender,
const QMetaMethod &signal,
3515 const QObject *receiver,
const QMetaMethod &method)
3517 if (sender ==
nullptr || (receiver ==
nullptr && method.mobj !=
nullptr)) {
3518 qCWarning(lcConnect,
"QObject::disconnect: Unexpected nullptr parameter");
3522 if (signal.methodType() != QMetaMethod::Signal) {
3523 qCWarning(lcConnect,
"QObject::%s: Attempt to %s non-signal %s::%s",
3524 "disconnect",
"unbind",
3525 sender->metaObject()->className(), signal.methodSignature().constData());
3530 if (method.methodType() == QMetaMethod::Constructor) {
3531 qCWarning(lcConnect,
"QObject::disconnect: cannot use constructor as argument %s::%s",
3532 receiver->metaObject()->className(), method.methodSignature().constData());
3541 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3542 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3546 if (signal.mobj && signal_index == -1) {
3547 qCWarning(lcConnect,
"QObject::disconnect: signal %s not found on class %s",
3548 signal.methodSignature().constData(), sender->metaObject()->className());
3552 if (receiver && method.mobj && method_index == -1) {
3553 qCWarning(lcConnect,
"QObject::disconnect: method %s not found on class %s",
3554 method.methodSignature().constData(), receiver->metaObject()->className());
3558 if (!QMetaObjectPrivate::disconnect(sender, signal_index, signal.mobj, receiver, method_index,
nullptr))
3561 if (!signal.isValid()) {
3566 const_cast<QObject *>(sender)->disconnectNotify(signal);
3723 int signal_index,
const QMetaObject *smeta,
3724 const QObject *receiver,
int method_index,
3725 const QMetaObject *rmeta,
int type,
int *types)
3727 QObject *s =
const_cast<QObject *>(sender);
3728 QObject *r =
const_cast<QObject *>(receiver);
3730 int method_offset = rmeta ? rmeta->methodOffset() : 0;
3732 QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall :
nullptr;
3734 QOrderedMutexLocker locker(signalSlotLock(sender),
3735 signalSlotLock(receiver));
3737 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3738 if (type & Qt::UniqueConnection && scd) {
3739 if (scd->signalVectorCount() > signal_index) {
3740 const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
3742 int method_index_absolute = method_index + method_offset;
3745 if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute)
3747 c2 = c2->nextConnectionList.loadRelaxed();
3751 type &= ~Qt::UniqueConnection;
3753 const bool isSingleShot = type & Qt::SingleShotConnection;
3754 type &= ~Qt::SingleShotConnection;
3756 Q_ASSERT(type >= 0);
3757 Q_ASSERT(type <= 3);
3759 std::unique_ptr<QObjectPrivate::Connection> c{
new QObjectPrivate::Connection};
3761 c->signal_index = signal_index;
3762 c->receiver.storeRelaxed(r);
3763 QThreadData *td = r->d_func()->threadData.loadAcquire();
3765 c->receiverThreadData.storeRelaxed(td);
3766 c->method_relative = method_index;
3767 c->method_offset = method_offset;
3768 c->connectionType = type;
3769 c->isSlotObject =
false;
3770 c->argumentTypes.storeRelaxed(types);
3771 c->callFunction = callFunction;
3772 c->isSingleShot = isSingleShot;
3774 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
3777 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3778 if (smethod.isValid())
3779 s->connectNotify(smethod);
3857bool QMetaObjectPrivate::disconnect(
const QObject *sender,
3858 int signal_index,
const QMetaObject *smeta,
3859 const QObject *receiver,
int method_index,
void **slot,
3860 DisconnectType disconnectType)
3865 QObject *s =
const_cast<QObject *>(sender);
3867 QBasicMutex *senderMutex = signalSlotLock(sender);
3868 QMutexLocker locker(senderMutex);
3870 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3874 bool success =
false;
3877 QObjectPrivate::ConnectionDataPointer connections(scd);
3879 if (signal_index < 0) {
3881 if (!receiver && method_index < 0 && sender->d_func()->isSignalConnected(0)) {
3882 qWarning(
"QObject::disconnect: wildcard call disconnects from destroyed signal of"
3883 " %s::%s", sender->metaObject()->className(),
3884 sender->objectName().isEmpty()
3886 : sender->objectName().toLocal8Bit().data());
3889 for (
int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
3890 if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
3893 }
else if (signal_index < scd->signalVectorCount()) {
3894 if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
3901 scd->cleanOrphanedConnections(s);
3903 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3904 if (smethod.isValid())
3905 s->disconnectNotify(smethod);
3961void QMetaObject::connectSlotsByName(QObject *o)
3965 const QMetaObject *mo = o->metaObject();
3967 const QObjectList list =
3968 o->findChildren<QObject *>()
3972 for (
int i = 0; i < mo->methodCount(); ++i) {
3973 const QByteArray slotSignature = mo->method(i).methodSignature();
3974 const char *slot = slotSignature.constData();
3978 if (slot[0] !=
'o' || slot[1] !=
'n' || slot[2] !=
'_')
3982 bool foundIt =
false;
3983 for (
int j = 0; j < list.size(); ++j) {
3984 const QObject *co = list.at(j);
3985 const QByteArray coName = co->objectName().toLatin1();
3988 if (coName.isEmpty() || qstrncmp(slot + 3, coName.constData(), coName.size()) || slot[coName.size()+3] !=
'_')
3991 const char *signal = slot + coName.size() + 4;
3994 const QMetaObject *smeta;
3995 int sigIndex = co->d_func()->signalIndex(signal, &smeta);
4001 QList<QByteArray> compatibleSignals;
4002 const QMetaObject *smo = co->metaObject();
4003 int sigLen =
int(qstrlen(signal)) - 1;
4004 for (
int k = QMetaObjectPrivate::absoluteSignalCount(smo)-1; k >= 0; --k) {
4005 const QMetaMethod method = QMetaObjectPrivate::signal(smo, k);
4006 if (!qstrncmp(method.methodSignature().constData(), signal, sigLen)) {
4007 smeta = method.enclosingMetaObject();
4009 compatibleSignals.prepend(method.methodSignature());
4012 if (compatibleSignals.size() > 1)
4013 qCWarning(lcConnectSlotsByName) <<
"QMetaObject::connectSlotsByName: Connecting slot" << slot
4014 <<
"with the first of the following compatible signals:" << compatibleSignals;
4021 if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) {
4023 qCDebug(lcConnectSlotsByName,
"%s",
4024 msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData());
4034 while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
4036 }
else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
4038 qsizetype iParen = slotSignature.indexOf(
'(');
4039 qsizetype iLastUnderscore = slotSignature.lastIndexOf(
'_', iParen - 1);
4040 if (iLastUnderscore > 3)
4042 "QMetaObject::connectSlotsByName: No matching signal for %s", slot);
4176static void queued_activate(QObject *sender,
int signal, QObjectPrivate::Connection *c,
void **argv)
4178 const int *argumentTypes = c->argumentTypes.loadRelaxed();
4179 if (!argumentTypes) {
4180 QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
4181 argumentTypes = queuedConnectionTypes(m);
4183 argumentTypes = &DIRECT_CONNECTION_ONLY;
4184 if (!c->argumentTypes.testAndSetOrdered(
nullptr, argumentTypes)) {
4185 if (argumentTypes != &DIRECT_CONNECTION_ONLY)
4186 delete[] argumentTypes;
4187 argumentTypes = c->argumentTypes.loadRelaxed();
4190 if (argumentTypes == &DIRECT_CONNECTION_ONLY)
4193 while (argumentTypes[nargs - 1])
4196 QMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
4197 QObject *receiver = c->receiver.loadRelaxed();
4203 SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj :
nullptr };
4206 QVarLengthArray<
const QtPrivate::QMetaTypeInterface *, 16> argTypes;
4207 argTypes.reserve(nargs);
4208 argTypes.emplace_back(
nullptr);
4209 for (
int n = 1; n < nargs; ++n) {
4210 argTypes.emplace_back(QMetaType(argumentTypes[n - 1]).iface());
4213 auto ev = c->isSlotObject ?
4214 std::make_unique<QQueuedMetaCallEvent>(c->slotObj,
4215 sender, signal, nargs, argTypes.data(), argv) :
4216 std::make_unique<QQueuedMetaCallEvent>(c->method_offset, c->method_relative, c->callFunction,
4217 sender, signal, nargs, argTypes.data(), argv);
4219 if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) {
4224 if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
4230 QCoreApplication::postEvent(receiver, ev.release());
4234void doActivate(QObject *sender,
int signal_index,
void **argv)
4236 QObjectPrivate *sp = QObjectPrivate::get(sender);
4241 Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
4243 if (sp->isDeclarativeSignalConnected(signal_index)
4244 && QAbstractDeclarativeData::signalEmitted) {
4245 Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
4246 QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
4247 signal_index, argv);
4250 const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() :
nullptr;
4252 void *empty_argv[] = {
nullptr };
4256 if (!sp->maybeSignalConnected(signal_index)) {
4258 if (callbacks_enabled && signal_spy_set->signal_begin_callback !=
nullptr)
4259 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4260 if (callbacks_enabled && signal_spy_set->signal_end_callback !=
nullptr)
4261 signal_spy_set->signal_end_callback(sender, signal_index);
4265 if (callbacks_enabled && signal_spy_set->signal_begin_callback !=
nullptr)
4266 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4268 bool senderDeleted =
false;
4270 Q_ASSERT(sp->connections.loadRelaxed());
4271 QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadAcquire());
4272 QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();
4274 const QObjectPrivate::ConnectionList *list;
4275 if (signal_index < signalVector->count())
4276 list = &signalVector->at(signal_index);
4278 list = &signalVector->at(-1);
4280 Qt::HANDLE currentThreadId = QThread::currentThreadId();
4281 bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
4285 uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
4287 QObjectPrivate::Connection *c = list->first.loadRelaxed();
4292 QObject *
const receiver = c->receiver.loadRelaxed();
4296 QThreadData *td = c->receiverThreadData.loadRelaxed();
4300 bool receiverInSameThread;
4301 if (inSenderThread) {
4302 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4305 QMutexLocker lock(signalSlotLock(receiver));
4306 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4312 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
4313 || (c->connectionType == Qt::QueuedConnection)) {
4314 queued_activate(sender, signal_index, c, argv);
4316#if QT_CONFIG(thread)
4317 }
else if (c->connectionType == Qt::BlockingQueuedConnection) {
4318 if (receiverInSameThread) {
4319 qWarning(
"Qt: Dead lock detected while activating a BlockingQueuedConnection: "
4320 "Sender is %s(%p), receiver is %s(%p)",
4321 sender->metaObject()->className(), sender,
4322 receiver->metaObject()->className(), receiver);
4325 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4330 QMutexLocker locker(signalSlotLock(receiver));
4331 if (!c->isSingleShot && !c->receiver.loadAcquire())
4333 QMetaCallEvent *ev = c->isSlotObject ?
4334 new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &latch) :
4335 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
4336 sender, signal_index, argv, &latch);
4337 QCoreApplication::postEvent(receiver, ev);
4344 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4347 QObjectPrivate::Sender senderData(
4348 receiverInSameThread ? receiver :
nullptr, sender, signal_index,
4349 receiverInSameThread ? QObjectPrivate::get(receiver)->connections.loadAcquire() :
nullptr);
4351 if (c->isSlotObject) {
4352 SlotObjectGuard obj{c->slotObj};
4355 Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
4356 obj->call(receiver, argv);
4358 }
else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
4360 const int method_relative = c->method_relative;
4361 const auto callFunction = c->callFunction;
4362 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
4363 if (callbacks_enabled && signal_spy_set->slot_begin_callback !=
nullptr)
4364 signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
4367 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
4368 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
4371 if (callbacks_enabled && signal_spy_set->slot_end_callback !=
nullptr)
4372 signal_spy_set->slot_end_callback(receiver, methodIndex);
4374 const int method = c->method_relative + c->method_offset;
4376 if (callbacks_enabled && signal_spy_set->slot_begin_callback !=
nullptr) {
4377 signal_spy_set->slot_begin_callback(receiver, method, argv);
4381 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
4382 QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
4385 if (callbacks_enabled && signal_spy_set->slot_end_callback !=
nullptr)
4386 signal_spy_set->slot_end_callback(receiver, method);
4388 }
while ((c = c->nextConnectionList.loadRelaxed()) !=
nullptr && c->id <= highestConnectionId);
4390 }
while (list != &signalVector->at(-1) &&
4392 ((list = &signalVector->at(-1)),
true));
4394 if (connections->currentConnectionId.loadRelaxed() == 0)
4395 senderDeleted =
true;
4397 if (!senderDeleted) {
4398 sp->connections.loadAcquire()->cleanOrphanedConnections(sender);
4400 if (callbacks_enabled && signal_spy_set->signal_end_callback !=
nullptr)
4401 signal_spy_set->signal_end_callback(sender, signal_index);
4639void QObject::dumpObjectInfo()
const
4641 qDebug(
"OBJECT %s::%s", metaObject()->className(),
4642 objectName().isEmpty() ?
"unnamed" : objectName().toLocal8Bit().data());
4645 QMutexLocker locker(signalSlotLock(
this));
4648 qDebug(
" SIGNALS OUT");
4650 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
4651 if (cd && cd->signalVectorCount() > 0) {
4652 QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
4653 for (
int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
4654 const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
4657 const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index);
4658 qDebug(
" signal: %s", signal.methodSignature().constData());
4662 if (!c->receiver.loadRelaxed()) {
4663 qDebug(
" <Disconnected receiver>");
4664 c = c->nextConnectionList.loadRelaxed();
4667 if (c->isSlotObject) {
4668 qDebug(
" <functor or function pointer>");
4669 c = c->nextConnectionList.loadRelaxed();
4672 const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
4673 const QMetaMethod method = receiverMetaObject->method(c->method());
4674 qDebug(
" --> %s::%s %s",
4675 receiverMetaObject->className(),
4676 c->receiver.loadRelaxed()->objectName().isEmpty() ?
"unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
4677 method.methodSignature().constData());
4678 c = c->nextConnectionList.loadRelaxed();
4682 qDebug(
" <None>" );
4686 qDebug(
" SIGNALS IN");
4688 if (cd && cd->senders) {
4689 for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
4690 QByteArray slotName = QByteArrayLiteral(
"<unknown>");
4691 if (!s->isSlotObject) {
4692 const QMetaMethod slot = metaObject()->method(s->method());
4693 slotName = slot.methodSignature();
4695 qDebug(
" <-- %s::%s %s",
4696 s->sender->metaObject()->className(),
4697 s->sender->objectName().isEmpty() ?
"unnamed" : qPrintable(s->sender->objectName()),
4698 slotName.constData());
5476QMetaObject::Connection QObjectPrivate::connectImpl(
const QObject *sender,
int signal_index,
5477 const QObject *receiver,
void **slot,
5478 QtPrivate::QSlotObjectBase *slotObjRaw,
int type,
5479 const int *types,
const QMetaObject *senderMetaObject)
5481 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5483 if (!sender || !receiver || !slotObj || !senderMetaObject) {
5484 connectWarning(sender, senderMetaObject, receiver,
"invalid nullptr parameter");
5485 return QMetaObject::Connection();
5488 if (type & Qt::UniqueConnection && !slot) {
5489 connectWarning(sender, senderMetaObject, receiver,
"unique connections require a pointer to member function of a QObject subclass");
5490 return QMetaObject::Connection();
5493 QObject *s =
const_cast<QObject *>(sender);
5494 QObject *r =
const_cast<QObject *>(receiver);
5496 QOrderedMutexLocker locker(signalSlotLock(sender),
5497 signalSlotLock(receiver));
5499 if (type & Qt::UniqueConnection) {
5500 QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
5501 if (connections && connections->signalVectorCount() > signal_index) {
5502 const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
5505 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot))
5506 return QMetaObject::Connection();
5507 c2 = c2->nextConnectionList.loadRelaxed();
5511 type &= ~Qt::UniqueConnection;
5513 const bool isSingleShot = type & Qt::SingleShotConnection;
5514 type &= ~Qt::SingleShotConnection;
5516 Q_ASSERT(type >= 0);
5517 Q_ASSERT(type <= 3);
5519 std::unique_ptr<QObjectPrivate::Connection> c{
new QObjectPrivate::Connection};
5521 c->signal_index = signal_index;
5522 QThreadData *td = r->d_func()->threadData.loadAcquire();
5524 c->receiverThreadData.storeRelaxed(td);
5525 c->receiver.storeRelaxed(r);
5526 c->connectionType = type;
5527 c->isSlotObject =
true;
5528 c->slotObj = slotObj.release();
5530 c->argumentTypes.storeRelaxed(types);
5531 c->ownArgumentTypes =
false;
5533 c->isSingleShot = isSingleShot;
5535 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
5536 QMetaObject::Connection ret(c.release());
5539 QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
5540 Q_ASSERT(method.isValid());
5541 s->connectNotify(method);