381 QBasicMutex *senderMutex = signalSlotLock(sender);
382 TaggedSignalVector c =
nullptr;
384 std::unique_lock<QBasicMutex> lock(*senderMutex, std::defer_lock_t{});
385 if (lockPolicy == NeedToLock)
387 if (ref.loadAcquire() > 1)
393 c = orphaned.exchange(
nullptr, std::memory_order_relaxed);
397 if (lockPolicy == AlreadyLockedAndTemporarilyReleasingLock) {
398 senderMutex->unlock();
407inline void QObjectPrivate::ConnectionData::deleteOrphaned(TaggedSignalVector o)
410 TaggedSignalVector next =
nullptr;
411 if (SignalVector *v =
static_cast<SignalVector *>(o)) {
412 next = v->nextInOrphanList;
415 QObjectPrivate::Connection *c =
static_cast<Connection *>(o);
416 next = c->nextInOrphanList;
417 Q_ASSERT(!c->receiver.loadRelaxed());
427
428
429
430
431
432bool QObjectPrivate::isSignalConnected(uint signalIndex,
bool checkDeclarative)
const
434 if (checkDeclarative && isDeclarativeSignalConnected(signalIndex))
437 ConnectionData *cd = connections.loadAcquire();
440 SignalVector *signalVector = cd->signalVector.loadRelaxed();
444 if (signalVector->at(-1).first.loadRelaxed())
447 if (signalIndex < uint(cd->signalVectorCount())) {
448 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadRelaxed();
450 if (c->receiver.loadRelaxed())
452 c = c->nextConnectionList.loadRelaxed();
458bool QObjectPrivate::maybeSignalConnected(uint signalIndex)
const
460 ConnectionData *cd = connections.loadAcquire();
463 SignalVector *signalVector = cd->signalVector.loadAcquire();
467 if (signalVector->at(-1).first.loadAcquire())
470 if (signalIndex < uint(cd->signalVectorCount())) {
471 const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadAcquire();
477void QObjectPrivate::reinitBindingStorageAfterThreadMove()
479 bindingStorage.reinitAfterThreadMove();
480 for (
int i = 0; i < children.size(); ++i)
481 children[i]->d_func()->reinitBindingStorageAfterThreadMove();
485
486
487QAbstractMetaCallEvent::~QAbstractMetaCallEvent()
496
497
498
499
500
501QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative,
502 QObjectPrivate::StaticMetaCallFunction callFunction,
503 const QObject *sender,
int signalId,
504 void **args, QLatch *latch)
505 : QAbstractMetaCallEvent(sender, signalId, latch),
506 d{
nullptr, args, callFunction, 0, method_offset, method_relative}
511
512
513
514
515
516QMetaCallEvent::QMetaCallEvent(QtPrivate::QSlotObjectBase *slotO,
517 const QObject *sender,
int signalId,
518 void **args, QLatch *latch)
519 : QAbstractMetaCallEvent(sender, signalId, latch),
520 d{QtPrivate::SlotObjUniquePtr{slotO}, args,
nullptr, 0, 0, ushort(-1)}
527
528
529
530
531
532QMetaCallEvent::QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotO,
533 const QObject *sender,
int signalId,
534 void **args, QLatch *latch)
535 : QAbstractMetaCallEvent(sender, signalId, latch),
536 d{std::move(slotO), args,
nullptr, 0, 0, ushort(-1)}
541
542
543QMetaCallEvent::QMetaCallEvent(
const QObject *sender,
int signalId, Data &&data)
544 : QAbstractMetaCallEvent(sender, signalId),
550
551
552void QMetaCallEvent::placeMetaCall(QObject *object)
555 d.slotObj_->call(object, d.args_);
556 }
else if (d.callFunction_ && d.method_offset_ <= object->metaObject()->methodOffset()) {
557 d.callFunction_(object, QMetaObject::InvokeMetaMethod, d.method_relative_, d.args_);
559 QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod,
560 d.method_offset_ + d.method_relative_, d.args_);
565
566
567
568
569QQueuedMetaCallEvent::QQueuedMetaCallEvent(ushort method_offset, ushort method_relative,
570 QObjectPrivate::StaticMetaCallFunction callFunction,
571 const QObject *sender,
int signalId,
int argCount,
572 const QtPrivate::QMetaTypeInterface *
const *argTypes,
573 const void *
const *argValues)
574 : QMetaCallEvent(sender, signalId, {
nullptr,
nullptr, callFunction, argCount,
575 method_offset, method_relative}),
578 copyArgValues(argCount, argTypes, argValues);
582
583
584
585
586QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
587 const QObject *sender,
int signalId,
int argCount,
588 const QtPrivate::QMetaTypeInterface *
const *argTypes,
589 const void *
const *argValues)
590 : QMetaCallEvent(sender, signalId, {QtPrivate::SlotObjUniquePtr(slotObj),
nullptr,
nullptr, argCount,
596 copyArgValues(argCount, argTypes, argValues);
600
601
602
603
604QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,
605 const QObject *sender,
int signalId,
int argCount,
606 const QtPrivate::QMetaTypeInterface *
const *argTypes,
607 const void *
const *argValues)
608 : QMetaCallEvent(sender, signalId, {std::move(slotObj),
nullptr,
nullptr, argCount,
612 copyArgValues(argCount, argTypes, argValues);
616
617
618QQueuedMetaCallEvent::~QQueuedMetaCallEvent()
620 const QMetaType *t =
reinterpret_cast<QMetaType *>(d.args_ + d.nargs_);
621 int inplaceIndex = 0;
622 for (
int i = 0; i < d.nargs_; ++i) {
623 if (t[i].isValid() && d.args_[i]) {
624 if (typeFitsInPlace(t[i]) && inplaceIndex < InplaceValuesCapacity) {
626 void *where = &valuesPrealloc_[inplaceIndex++].storage;
627 t[i].destruct(where);
630 t[i].destroy(d.args_[i]);
635 if (
static_cast<
void *>(d.args_) != prealloc_)
636 QtPrivate::sizedFree(d.args_, d.nargs_, PtrAndTypeSize);
641
642
643inline void QQueuedMetaCallEvent::allocArgs()
648 void *
const memory = d.nargs_ * PtrAndTypeSize >
sizeof(prealloc_) ?
649 calloc(d.nargs_, PtrAndTypeSize) : prealloc_;
652 d.args_ =
static_cast<
void **>(memory);
656
657
658inline void QQueuedMetaCallEvent::copyArgValues(
int argCount,
const QtPrivate::QMetaTypeInterface *
const *argTypes,
659 const void *
const *argValues)
662 void **args = d.args_;
663 QMetaType *types =
reinterpret_cast<QMetaType *>(d.args_ + d.nargs_);
664 int inplaceIndex = 0;
667 types[0] = QMetaType();
672 for (
int n = 1; n < argCount; ++n) {
673 types[n] = QMetaType(argTypes[n]);
674 if (typeFitsInPlace(types[n]) && inplaceIndex < InplaceValuesCapacity) {
676 void *where = &valuesPrealloc_[inplaceIndex++].storage;
677 types[n].construct(where, argValues[n]);
681 args[n] = types[n].create(argValues[n]);
687
688
689inline bool QQueuedMetaCallEvent::typeFitsInPlace(
const QMetaType type)
691 return (q20::cmp_less_equal(type.sizeOf(),
sizeof(ArgValueStorage)) &&
692 q20::cmp_less_equal(type.alignOf(),
alignof(ArgValueStorage)));
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
720
721
722
723
726
727
728
729
730
733
734
735
736
737
738
741
742
743
744
745
746
747
748
749
750
751
754
755
756
757
758
759
762
763
764
765
766
767
768
771
772
773
774
775
776
777
778
779
782
783
784
785
786
787
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
944
945
952 if (parent && parentThreadData != currentThreadData) {
953 QThread *parentThread = parentThreadData->thread.loadAcquire();
954 QThread *currentThread = currentThreadData->thread.loadAcquire();
955 qWarning(
"QObject: Cannot create children for a parent that is in a different thread.\n"
956 "(Parent is %s(%p), parent's thread is %s(%p), current thread is %s(%p)",
957 parent->metaObject()->className(),
959 parentThread ? parentThread->metaObject()->className() :
"QThread",
961 currentThread ? currentThread->metaObject()->className() :
"QThread",
969
970
971
972
973
974
975
976
977
978
979
980
981
983QObject::QObject(QObject *parent)
984 : QObject(*
new QObjectPrivate, parent)
989
990
991QObject::QObject(QObjectPrivate &dd, QObject *parent)
994 Q_ASSERT_X(
this != parent, Q_FUNC_INFO,
"Cannot parent a QObject to itself");
998 QThreadData *parentThreadData = parent ? parent->d_func()->threadData.loadRelaxed() :
nullptr;
999 QThreadData *threadData;
1000 if (parent && !parentThreadData->thread.loadRelaxed()) {
1001 threadData = parentThreadData;
1003 threadData = QThreadData::current();
1004 if (!check_parent_thread(parent, parentThreadData, threadData))
1008 d->threadData.storeRelaxed(threadData);
1012 auto scopeDeref = qScopeGuard([threadData] { threadData->deref(); });
1013 if (d->willBeWidget) {
1015 d->parent->d_func()->children.append(
this);
1020 scopeDeref.dismiss();
1025 if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
1026 reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(
this);
1027 Q_TRACE(QObject_ctor,
this);
1062 d->wasDeleted =
true;
1065 if (!d->bindingStorage.isValid()) {
1068 if (QThread *ownThread = thread()) {
1069 auto *privThread =
static_cast<QThreadPrivate *>(
1070 QObjectPrivate::get(ownThread));
1071 privThread->removeObjectWithPendingBindingStatusChange(
this);
1077 d->clearBindingStorage();
1079 QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.loadRelaxed();
1080 if (sharedRefcount) {
1081 if (sharedRefcount->strongref.loadRelaxed() > 0) {
1082 qWarning(
"QObject: shared QObject was deleted directly. The program is malformed and may crash.");
1087 sharedRefcount->strongref.storeRelaxed(0);
1088 if (!sharedRefcount->weakref.deref())
1089 delete sharedRefcount;
1092 if (!d->wasWidget && d->isSignalConnected(0)) {
1093 emit destroyed(
this);
1096 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::destroyed)
1097 QAbstractDeclarativeData::destroyed(d->declarativeData,
this);
1099 QObjectPrivate::ConnectionData *cd = d->connections.loadAcquire();
1101 if (cd->currentSender) {
1102 cd->currentSender->receiverDeleted();
1103 cd->currentSender =
nullptr;
1106 QBasicMutex *signalSlotMutex = signalSlotLock(
this);
1107 QMutexLocker locker(signalSlotMutex);
1110 int receiverCount = cd->signalVectorCount();
1111 for (
int signal = -1; signal < receiverCount; ++signal) {
1112 QObjectPrivate::ConnectionList &connectionList = cd->connectionsForSignal(signal);
1114 while (QObjectPrivate::Connection *c = connectionList.first.loadRelaxed()) {
1115 Q_ASSERT(c->receiver.loadAcquire());
1117 QBasicMutex *m = signalSlotLock(c->receiver.loadRelaxed());
1118 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1119 if (c == connectionList.first.loadAcquire() && c->receiver.loadAcquire()) {
1120 cd->removeConnection(c);
1121 Q_ASSERT(connectionList.first.loadRelaxed() != c);
1129
1130 while (QObjectPrivate::Connection *node = cd->senders) {
1131 Q_ASSERT(node->receiver.loadAcquire());
1132 QObject *sender = node->sender;
1136 sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), node->signal_index));
1137 QBasicMutex *m = signalSlotLock(sender);
1138 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1140 if (node != cd->senders) {
1142 Q_ASSERT(needToUnlock);
1147 QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections.loadRelaxed();
1148 Q_ASSERT(senderData);
1150 QtPrivate::QSlotObjectBase *slotObj =
nullptr;
1151 if (node->isSlotObject) {
1152 slotObj = node->slotObj;
1153 node->isSlotObject =
false;
1156 senderData->removeConnection(node);
1158
1159
1160
1161
1162
1163
1164
1165 const bool locksAreTheSame = signalSlotMutex == m;
1166 if (!locksAreTheSame)
1168 senderData->cleanOrphanedConnections(
1170 QObjectPrivate::ConnectionData::AlreadyLockedAndTemporarilyReleasingLock
1175 if (locksAreTheSame)
1178 slotObj->destroyIfLastRef();
1184 cd->currentConnectionId.storeRelaxed(0);
1186 if (cd && !cd->ref.deref())
1188 d->connections.storeRelaxed(
nullptr);
1190 if (!d->children.isEmpty())
1191 d->deleteChildren();
1193 if (Q_UNLIKELY(qtHookData[QHooks::RemoveQObject]))
1194 reinterpret_cast<QHooks::RemoveQObjectCallback>(qtHookData[QHooks::RemoveQObject])(
this);
1196 Q_TRACE(QObject_dtor,
this);
1199 d->setParent_helper(
nullptr);
1464bool QObject::event(QEvent *e)
1466 switch (e->type()) {
1468 timerEvent((QTimerEvent *)e);
1471 case QEvent::ChildAdded:
1472 case QEvent::ChildPolished:
1473 case QEvent::ChildRemoved:
1474 childEvent((QChildEvent *)e);
1477 case QEvent::DeferredDelete:
1481 case QEvent::MetaCall:
1483 QAbstractMetaCallEvent *mce =
static_cast<QAbstractMetaCallEvent*>(e);
1485 QObjectPrivate::ConnectionData *connections = d_func()->connections.loadAcquire();
1487 QMutexLocker locker(signalSlotLock(
this));
1488 d_func()->ensureConnectionData();
1489 connections = d_func()->connections.loadRelaxed();
1491 QObjectPrivate::Sender sender(
this,
const_cast<QObject*>(mce->sender()), mce->signalId(), connections);
1493 mce->placeMetaCall(
this);
1497 case QEvent::ThreadChange: {
1499 QThreadData *threadData = d->threadData.loadRelaxed();
1500 QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
1501 if (eventDispatcher) {
1502 QList<QAbstractEventDispatcher::TimerInfoV2> timers = eventDispatcher->timersForObject(
this);
1503 if (!timers.isEmpty()) {
1504 const bool res = eventDispatcher->unregisterTimers(
this);
1506 Q_ASSERT_X(res, Q_FUNC_INFO,
1507 "QAbstractEventDispatcher::unregisterTimers() returned false,"
1508 " but there are timers associated with this object.");
1509 auto reRegisterTimers = [
this, timers = std::move(timers)]() {
1510 QAbstractEventDispatcher *eventDispatcher =
1511 d_func()->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
1512 for (
const auto &ti : timers)
1513 eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType,
this);
1515 QMetaObject::invokeMethod(
this, std::move(reRegisterTimers), Qt::QueuedConnection);
1522 if (e->type() >= QEvent::User) {
1719bool QObject::moveToThread(QThread *targetThread QT6_IMPL_NEW_OVERLOAD_TAIL)
1723 if (d->threadData.loadRelaxed()->thread.loadAcquire() == targetThread) {
1728 if (d->parent !=
nullptr) {
1729 qWarning(
"QObject::moveToThread: Cannot move objects with a parent");
1733 qWarning(
"QObject::moveToThread: Widgets cannot be moved to a new thread");
1736 if (!d->bindingStorage.isEmpty()) {
1737 qWarning(
"QObject::moveToThread: Can not move objects that contain bindings or are used in bindings to a new thread.");
1741 QThreadData *currentData = QThreadData::current();
1742 QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) :
nullptr;
1743 QThreadData *thisThreadData = d->threadData.loadAcquire();
1744 if (!thisThreadData->thread.loadRelaxed() && currentData == targetData) {
1746 currentData = thisThreadData;
1747 }
else if (thisThreadData != currentData) {
1748 qWarning(
"QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
1749 "Cannot move to target thread (%p)\n",
1750 currentData->thread.loadRelaxed(), thisThreadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() :
nullptr);
1753 qWarning(
"You might be loading two sets of Qt binaries into the same process. "
1754 "Check that all plugins are compiled against the right Qt binaries. Export "
1755 "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.");
1762 d->moveToThread_helper();
1765 targetData =
new QThreadData(0);
1768 QMutexLocker l(signalSlotLock(
this));
1770 QOrderedMutexLocker locker(¤tData->postEventList.mutex,
1771 &targetData->postEventList.mutex);
1777 auto threadPrivate = targetThread
1778 ?
static_cast<QThreadPrivate *>(QThreadPrivate::get(targetThread))
1780 QBindingStatus *bindingStatus = threadPrivate
1781 ? threadPrivate->bindingStatus()
1783 if (threadPrivate && !bindingStatus) {
1784 bindingStatus = threadPrivate->addObjectWithPendingBindingStatusChange(
this);
1786 d_func()->setThreadData_helper(currentData, targetData, bindingStatus);
1791 currentData->deref();
1807void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status)
1813 this->bindingStorage.bindingStatus = status;
1817 qsizetype eventsMoved = 0;
1818 for (qsizetype i = 0; i < currentData->postEventList.size(); ++i) {
1819 const QPostEvent &pe = currentData->postEventList.at(i);
1822 if (pe.receiver == q) {
1824 targetData->postEventList.addEvent(pe);
1825 const_cast<QPostEvent &>(pe).event =
nullptr;
1829 if (eventsMoved > 0 && targetData->hasEventDispatcher()) {
1830 targetData->canWait =
false;
1831 targetData->eventDispatcher.loadRelaxed()->wakeUp();
1835 ConnectionData *cd = connections.loadAcquire();
1837 if (cd->currentSender) {
1838 cd->currentSender->receiverDeleted();
1839 cd->currentSender =
nullptr;
1844 auto *c = cd->senders;
1846 QObject *r = c->receiver.loadRelaxed();
1850 QThreadData *old = c->receiverThreadData.loadRelaxed();
1853 c->receiverThreadData.storeRelaxed(targetData);
1863 threadData.loadRelaxed()->deref();
1866 threadData.storeRelease(targetData);
1868 for (
int i = 0; i < children.size(); ++i) {
1869 QObject *child = children.at(i);
1870 child->d_func()->setThreadData_helper(currentData, targetData, status);
2300void QObjectPrivate::setParent_helper(QObject *o)
2303 Q_ASSERT_X(q != o, Q_FUNC_INFO,
"Cannot parent a QObject to itself");
2305 const auto checkForParentChildLoops = qScopeGuard([&](){
2309 if (++depth == CheckForParentChildLoopsWarnDepth) {
2310 qWarning(
"QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
2311 "this is undefined behavior",
2312 q, q->metaObject()->className(), qPrintable(q->objectName()));
2323 QObjectPrivate *parentD = parent->d_func();
2324 if (parentD->isDeletingChildren && wasDeleted
2325 && parentD->currentChildBeingDeleted == q) {
2329 const qsizetype index = parentD->children.indexOf(q);
2332 }
else if (parentD->isDeletingChildren) {
2333 parentD->children[index] =
nullptr;
2335 parentD->children.removeAt(index);
2336 if (sendChildEvents && parentD->receiveChildEvents) {
2337 QChildEvent e(QEvent::ChildRemoved, q);
2338 QCoreApplication::sendEvent(parent, &e);
2344 if (receiveParentEvents) {
2345 Q_ASSERT(!isWidget);
2346 QEvent e(QEvent::ParentAboutToChange);
2347 QCoreApplication::sendEvent(q, &e);
2354 if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) {
2355 qWarning(
"QObject::setParent: Cannot set parent, new parent is in a different thread");
2359 parent->d_func()->children.append(q);
2360 if (sendChildEvents && parent->d_func()->receiveChildEvents) {
2362 QChildEvent e(QEvent::ChildAdded, q);
2363 QCoreApplication::sendEvent(parent, &e);
2368 if (receiveParentEvents) {
2369 Q_ASSERT(!isWidget);
2370 QEvent e(QEvent::ParentChange);
2371 QCoreApplication::sendEvent(q, &e);
3095QMetaObject::Connection QObject::connect(
const QObject *sender,
const char *signal,
3096 const QObject *receiver,
const char *method,
3097 Qt::ConnectionType type)
3099 if (sender ==
nullptr || receiver ==
nullptr || signal ==
nullptr || method ==
nullptr) {
3100 qCWarning(lcConnect,
"QObject::connect: Cannot connect %s::%s to %s::%s",
3101 sender ? sender->metaObject()->className() :
"(nullptr)",
3102 (signal && *signal) ? signal + 1 :
"(nullptr)",
3103 receiver ? receiver->metaObject()->className() :
"(nullptr)",
3104 (method && *method) ? method + 1 :
"(nullptr)");
3105 return QMetaObject::Connection(
nullptr);
3108 if (!check_signal_macro(sender, signal,
"connect",
"bind"))
3109 return QMetaObject::Connection(
nullptr);
3111 int membcode = extract_code(method);
3112 if (!check_method_code(membcode, receiver, method,
"connect"))
3113 return QMetaObject::Connection(
nullptr);
3115 QByteArray pinnedSignal;
3116 const QMetaObject *smeta = sender->metaObject();
3117 const char *signal_arg = signal;
3119 QByteArrayView signalView{signal};
3120 QArgumentTypeArray signalTypes;
3121 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3122 QByteArrayView signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3123 int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3124 if (signal_index < 0) {
3126 pinnedSignal = QMetaObjectPrivate::normalizedSignature(signalView);
3127 signalView = pinnedSignal;
3129 signalTypes.clear();
3130 signalName = QMetaObjectPrivate::decodeMethodSignature(signalView, signalTypes);
3131 smeta = sender->metaObject();
3132 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3134 if (signal_index < 0) {
3135 err_method_notfound(sender, signal_arg,
"connect");
3136 err_info_about_objects(
"connect", sender, receiver);
3137 return QMetaObject::Connection(
nullptr);
3139 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3140 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3142 QByteArray pinnedMethod;
3143 const char *method_arg = method;
3145 QByteArrayView methodView{method};
3147 QArgumentTypeArray methodTypes;
3148 QByteArrayView methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3149 const QMetaObject *rmeta = receiver->metaObject();
3150 int method_index_relative = -1;
3151 Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
3154 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3155 &rmeta, methodName, methodTypes);
3158 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3159 &rmeta, methodName, methodTypes);
3163 if (method_index_relative < 0) {
3165 pinnedMethod = QMetaObjectPrivate::normalizedSignature(methodView);
3166 methodView = pinnedMethod;
3168 methodTypes.clear();
3169 methodName = QMetaObjectPrivate::decodeMethodSignature(methodView, methodTypes);
3171 rmeta = receiver->metaObject();
3174 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3175 &rmeta, methodName, methodTypes);
3178 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3179 &rmeta, methodName, methodTypes);
3184 if (method_index_relative < 0) {
3185 err_method_notfound(receiver, method_arg,
"connect");
3186 err_info_about_objects(
"connect", sender, receiver);
3187 return QMetaObject::Connection(
nullptr);
3190 if (!QMetaObjectPrivate::checkConnectArgs(signalTypes, methodTypes)) {
3192 "QObject::connect: Incompatible sender/receiver arguments"
3193 "\n %s::%s --> %s::%s",
3194 sender->metaObject()->className(), signalView.constData(),
3195 receiver->metaObject()->className(), methodView.constData());
3196 return QMetaObject::Connection(
nullptr);
3201 int *types =
nullptr;
3202 if (type == Qt::QueuedConnection && !(types = queuedConnectionTypes(signalTypes))) {
3203 return QMetaObject::Connection(
nullptr);
3206 QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
3208 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3209 check_and_warn_compat(smeta, smethod, rmeta, rmethod);
3212#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
3213 check_and_warn_non_slot(
"connect", method, membcode, rmeta, rmethod);
3216 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3217 sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
3241QMetaObject::Connection QObject::connect(
const QObject *sender,
const QMetaMethod &signal,
3242 const QObject *receiver,
const QMetaMethod &method,
3243 Qt::ConnectionType type)
3245 if (sender ==
nullptr
3246 || receiver ==
nullptr
3247 || signal.methodType() != QMetaMethod::Signal
3248 || method.methodType() == QMetaMethod::Constructor) {
3249 qCWarning(lcConnect,
"QObject::connect: Cannot connect %s::%s to %s::%s",
3250 sender ? sender->metaObject()->className() :
"(nullptr)",
3251 signal.methodSignature().constData(),
3252 receiver ? receiver->metaObject()->className() :
"(nullptr)",
3253 method.methodSignature().constData());
3254 return QMetaObject::Connection(
nullptr);
3261 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3262 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3265 const QMetaObject *smeta = sender->metaObject();
3266 const QMetaObject *rmeta = receiver->metaObject();
3267 if (signal_index == -1) {
3268 qCWarning(lcConnect,
"QObject::connect: Can't find signal %s on instance of class %s",
3269 signal.methodSignature().constData(), smeta->className());
3270 return QMetaObject::Connection(
nullptr);
3272 if (method_index == -1) {
3273 qCWarning(lcConnect,
"QObject::connect: Can't find method %s on instance of class %s",
3274 method.methodSignature().constData(), rmeta->className());
3275 return QMetaObject::Connection(
nullptr);
3278 if (!QMetaObject::checkConnectArgs(signal.methodSignature().constData(),
3279 method.methodSignature().constData())) {
3281 "QObject::connect: Incompatible sender/receiver arguments"
3282 "\n %s::%s --> %s::%s",
3283 smeta->className(), signal.methodSignature().constData(), rmeta->className(),
3284 method.methodSignature().constData());
3285 return QMetaObject::Connection(
nullptr);
3288 int *types =
nullptr;
3289 if ((type == Qt::QueuedConnection) && !(types = queuedConnectionTypes(signal)))
3290 return QMetaObject::Connection(
nullptr);
3293 check_and_warn_compat(smeta, signal, rmeta, method);
3295 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3296 sender, signal_index, signal.enclosingMetaObject(), receiver, method_index,
nullptr, type, types));
3381bool QObject::disconnect(
const QObject *sender,
const char *signal,
3382 const QObject *receiver,
const char *method)
3384 if (sender ==
nullptr || (receiver ==
nullptr && method !=
nullptr)) {
3385 qCWarning(lcConnect,
"QObject::disconnect: Unexpected nullptr parameter");
3389 const char *signal_arg = signal;
3391 if (!check_signal_macro(sender, signal,
"disconnect",
"unbind"))
3396 const char *method_arg = method;
3399 membcode = extract_code(method);
3400 if (!check_method_code(membcode, receiver, method,
"disconnect"))
3405 QByteArray pinnedSignal;
3406 const QMetaObject *smeta = sender->metaObject();
3407 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3408 int signal_index = -1;
3409 QByteArrayView signalName;
3410 QArgumentTypeArray signalTypes;
3412 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3413 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName, signalTypes);
3414 if (signal_index == -1) {
3415 pinnedSignal = QMetaObject::normalizedSignature(signal);
3416 signal = pinnedSignal.constData();
3417 signalTypes.clear();
3418 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3419 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3422 if (signal_index == -1) {
3423 err_method_notfound(sender, signal_arg,
"disconnect");
3424 err_info_about_objects(
"disconnect", sender, receiver);
3429 auto getMethodIndex = [](
int code,
const QMetaObject *mo, QByteArrayView name,
3430 const QArgumentTypeArray &types) {
3433 return QMetaObjectPrivate::indexOfSlot(mo, name, types);
3435 return QMetaObjectPrivate::indexOfSignal(mo, name, types);
3440 QByteArray pinnedMethod;
3441 const QMetaObject *rmeta = receiver ? receiver->metaObject() :
nullptr;
3442 Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 7);
3443 int method_index = -1;
3444 QByteArrayView methodName;
3445 QArgumentTypeArray methodTypes;
3447 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3448 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3449 if (method_index == -1) {
3450 pinnedMethod = QMetaObject::normalizedSignature(method);
3451 method = pinnedMethod.constData();
3452 methodTypes.clear();
3453 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3454 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3456 if (method_index == -1) {
3457 err_method_notfound(receiver, method_arg,
"disconnect");
3458 err_info_about_objects(
"disconnect", sender, receiver);
3464
3465
3466
3471 if (smeta != sender->metaObject()) {
3472 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signalName,
3475 if (signal_index < 0)
3477 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3478 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3482 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1,
nullptr);
3486 if (rmeta != receiver->metaObject())
3487 method_index = getMethodIndex(membcode, rmeta, methodName, methodTypes);
3488 if (method_index >= 0) {
3489#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
3490 check_and_warn_non_slot(
"disconnect", method, membcode, rmeta,
3491 rmeta->method(method_index));
3493 while (method_index < rmeta->methodOffset())
3494 rmeta = rmeta->superClass();
3496 if (method_index < 0)
3498 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index,
nullptr);
3499 }
while ((rmeta = rmeta->superClass()));
3501 }
while (signal && (smeta = smeta->superClass()));
3505 const_cast<QObject *>(sender)->disconnectNotify(QMetaMethod());
3544bool QObject::disconnect(
const QObject *sender,
const QMetaMethod &signal,
3545 const QObject *receiver,
const QMetaMethod &method)
3547 if (sender ==
nullptr || (receiver ==
nullptr && method.mobj !=
nullptr)) {
3548 qCWarning(lcConnect,
"QObject::disconnect: Unexpected nullptr parameter");
3552 if (signal.methodType() != QMetaMethod::Signal) {
3553 qCWarning(lcConnect,
"QObject::%s: Attempt to %s non-signal %s::%s",
3554 "disconnect",
"unbind",
3555 sender->metaObject()->className(), signal.methodSignature().constData());
3560 if (method.methodType() == QMetaMethod::Constructor) {
3561 qCWarning(lcConnect,
"QObject::disconnect: cannot use constructor as argument %s::%s",
3562 receiver->metaObject()->className(), method.methodSignature().constData());
3571 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3572 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3576 if (signal.mobj && signal_index == -1) {
3577 qCWarning(lcConnect,
"QObject::disconnect: signal %s not found on class %s",
3578 signal.methodSignature().constData(), sender->metaObject()->className());
3582 if (receiver && method.mobj && method_index == -1) {
3583 qCWarning(lcConnect,
"QObject::disconnect: method %s not found on class %s",
3584 method.methodSignature().constData(), receiver->metaObject()->className());
3588 if (!QMetaObjectPrivate::disconnect(sender, signal_index, signal.mobj, receiver, method_index,
nullptr))
3591 if (!signal.isValid()) {
3596 const_cast<QObject *>(sender)->disconnectNotify(signal);
3753 int signal_index,
const QMetaObject *smeta,
3754 const QObject *receiver,
int method_index,
3755 const QMetaObject *rmeta,
int type,
int *types)
3757 QObject *s =
const_cast<QObject *>(sender);
3758 QObject *r =
const_cast<QObject *>(receiver);
3760 int method_offset = rmeta ? rmeta->methodOffset() : 0;
3762 QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall :
nullptr;
3764 QOrderedMutexLocker locker(signalSlotLock(sender),
3765 signalSlotLock(receiver));
3767 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3768 if (type & Qt::UniqueConnection && scd) {
3769 if (scd->signalVectorCount() > signal_index) {
3770 const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
3772 int method_index_absolute = method_index + method_offset;
3775 if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute)
3777 c2 = c2->nextConnectionList.loadRelaxed();
3781 type &= ~Qt::UniqueConnection;
3783 const bool isSingleShot = type & Qt::SingleShotConnection;
3784 type &= ~Qt::SingleShotConnection;
3786 Q_ASSERT(type >= 0);
3787 Q_ASSERT(type <= 3);
3789 std::unique_ptr<QObjectPrivate::Connection> c{
new QObjectPrivate::Connection};
3791 c->signal_index = signal_index;
3792 c->receiver.storeRelaxed(r);
3793 QThreadData *td = r->d_func()->threadData.loadAcquire();
3795 c->receiverThreadData.storeRelaxed(td);
3796 c->method_relative = method_index;
3797 c->method_offset = method_offset;
3798 c->connectionType = type;
3799 c->isSlotObject =
false;
3800 c->argumentTypes.storeRelaxed(types);
3801 c->callFunction = callFunction;
3802 c->isSingleShot = isSingleShot;
3804 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
3807 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3808 if (smethod.isValid())
3809 s->connectNotify(smethod);
3887bool QMetaObjectPrivate::disconnect(
const QObject *sender,
3888 int signal_index,
const QMetaObject *smeta,
3889 const QObject *receiver,
int method_index,
void **slot,
3890 DisconnectType disconnectType)
3895 QObject *s =
const_cast<QObject *>(sender);
3897 QBasicMutex *senderMutex = signalSlotLock(sender);
3898 QMutexLocker locker(senderMutex);
3900 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3907 struct WildcardDestroyedWarning
3909 QByteArray className;
3910 QByteArray objectName;
3912 std::optional<WildcardDestroyedWarning> wildcardDestroyedWarning;
3914 bool success =
false;
3917 QObjectPrivate::ConnectionDataPointer connections(scd);
3919 if (signal_index < 0) {
3921 if (!receiver && method_index < 0 && sender->d_func()->isSignalConnected(0)) {
3922 wildcardDestroyedWarning = WildcardDestroyedWarning{
3923 sender->metaObject()->className(),
3924 sender->objectName().toLocal8Bit()
3928 for (
int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
3929 if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
3932 }
else if (signal_index < scd->signalVectorCount()) {
3933 if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
3940 if (wildcardDestroyedWarning) {
3941 qWarning(
"QObject::disconnect: wildcard call disconnects from destroyed signal of %s::%s",
3942 wildcardDestroyedWarning->className.constData(),
3943 wildcardDestroyedWarning->objectName.isEmpty()
3945 : wildcardDestroyedWarning->objectName.constData());
3949 scd->cleanOrphanedConnections(s);
3951 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3952 if (smethod.isValid())
3953 s->disconnectNotify(smethod);
4009void QMetaObject::connectSlotsByName(QObject *o)
4013 const QMetaObject *mo = o->metaObject();
4015 const QObjectList list =
4016 o->findChildren<QObject *>()
4020 for (
int i = 0; i < mo->methodCount(); ++i) {
4021 const QByteArray slotSignature = mo->method(i).methodSignature();
4022 const char *slot = slotSignature.constData();
4026 if (slot[0] !=
'o' || slot[1] !=
'n' || slot[2] !=
'_')
4030 bool foundIt =
false;
4031 for (
int j = 0; j < list.size(); ++j) {
4032 const QObject *co = list.at(j);
4033 const QByteArray coName = co->objectName().toLatin1();
4036 if (coName.isEmpty() || qstrncmp(slot + 3, coName.constData(), coName.size()) || slot[coName.size()+3] !=
'_')
4039 const char *signal = slot + coName.size() + 4;
4042 const QMetaObject *smeta;
4043 int sigIndex = co->d_func()->signalIndex(signal, &smeta);
4049 QList<QByteArray> compatibleSignals;
4050 const QMetaObject *smo = co->metaObject();
4051 int sigLen =
int(qstrlen(signal)) - 1;
4052 for (
int k = QMetaObjectPrivate::absoluteSignalCount(smo)-1; k >= 0; --k) {
4053 const QMetaMethod method = QMetaObjectPrivate::signal(smo, k);
4054 if (!qstrncmp(method.methodSignature().constData(), signal, sigLen)) {
4055 smeta = method.enclosingMetaObject();
4057 compatibleSignals.prepend(method.methodSignature());
4060 if (compatibleSignals.size() > 1)
4061 qCWarning(lcConnectSlotsByName) <<
"QMetaObject::connectSlotsByName: Connecting slot" << slot
4062 <<
"with the first of the following compatible signals:" << compatibleSignals;
4069 if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) {
4071 qCDebug(lcConnectSlotsByName,
"%s",
4072 msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData());
4082 while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
4084 }
else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
4086 qsizetype iParen = slotSignature.indexOf(
'(');
4087 qsizetype iLastUnderscore = slotSignature.lastIndexOf(
'_', iParen - 1);
4088 if (iLastUnderscore > 3)
4090 "QMetaObject::connectSlotsByName: No matching signal for %s", slot);
4225static void queued_activate(QObject *sender,
int signal, QObjectPrivate::Connection *c,
void **argv)
4227 const int *argumentTypes = c->argumentTypes.loadRelaxed();
4228 if (!argumentTypes) {
4229 QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
4230 argumentTypes = queuedConnectionTypes(m);
4232 argumentTypes = &DIRECT_CONNECTION_ONLY;
4233 if (!c->argumentTypes.testAndSetOrdered(
nullptr, argumentTypes)) {
4234 if (argumentTypes != &DIRECT_CONNECTION_ONLY)
4235 delete[] argumentTypes;
4236 argumentTypes = c->argumentTypes.loadRelaxed();
4239 if (argumentTypes == &DIRECT_CONNECTION_ONLY)
4242 while (argumentTypes[nargs - 1])
4245 QMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
4246 QObject *receiver = c->receiver.loadRelaxed();
4252 SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj :
nullptr };
4255 QVarLengthArray<
const QtPrivate::QMetaTypeInterface *, 16> argTypes;
4256 argTypes.reserve(nargs);
4257 argTypes.emplace_back(
nullptr);
4258 for (
int n = 1; n < nargs; ++n) {
4259 argTypes.emplace_back(QMetaType(argumentTypes[n - 1]).iface());
4262 auto ev = c->isSlotObject ?
4263 std::make_unique<QQueuedMetaCallEvent>(c->slotObj,
4264 sender, signal, nargs, argTypes.data(), argv) :
4265 std::make_unique<QQueuedMetaCallEvent>(c->method_offset, c->method_relative, c->callFunction,
4266 sender, signal, nargs, argTypes.data(), argv);
4268 if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) {
4273 if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
4279 QCoreApplication::postEvent(receiver, ev.release());
4283void doActivate(QObject *sender,
int signal_index,
void **argv)
4285 QObjectPrivate *sp = QObjectPrivate::get(sender);
4290 Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
4292 if (sp->isDeclarativeSignalConnected(signal_index)
4293 && QAbstractDeclarativeData::signalEmitted) {
4294 Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
4295 QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
4296 signal_index, argv);
4299 const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() :
nullptr;
4301 void *empty_argv[] = {
nullptr };
4305 bool senderDeleted =
false;
4307 QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadAcquire());
4308 if (!connections || !sp->maybeSignalConnected(signal_index)) {
4310 if (callbacks_enabled && signal_spy_set->signal_begin_callback !=
nullptr)
4311 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4312 if (callbacks_enabled && signal_spy_set->signal_end_callback !=
nullptr)
4313 signal_spy_set->signal_end_callback(sender, signal_index);
4317 if (callbacks_enabled && signal_spy_set->signal_begin_callback !=
nullptr)
4318 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4322 QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadAcquire();
4324 const QObjectPrivate::ConnectionList *list;
4325 if (signal_index < signalVector->count())
4326 list = &signalVector->at(signal_index);
4328 list = &signalVector->at(-1);
4330 Qt::HANDLE currentThreadId = QThread::currentThreadId();
4331 bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
4335 uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
4337 QObjectPrivate::Connection *c = list->first.loadAcquire();
4342 QObject *
const receiver = c->receiver.loadRelaxed();
4346 QThreadData *td = c->receiverThreadData.loadRelaxed();
4350 bool receiverInSameThread;
4351 if (inSenderThread) {
4352 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4355 QMutexLocker lock(signalSlotLock(receiver));
4356 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4362 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
4363 || (c->connectionType == Qt::QueuedConnection)) {
4364 queued_activate(sender, signal_index, c, argv);
4366#if QT_CONFIG(thread)
4367 }
else if (c->connectionType == Qt::BlockingQueuedConnection) {
4368 if (receiverInSameThread) {
4369 qWarning(
"Qt: Dead lock detected while activating a BlockingQueuedConnection: "
4370 "Sender is %s(%p), receiver is %s(%p)",
4371 sender->metaObject()->className(), sender,
4372 receiver->metaObject()->className(), receiver);
4375 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4380 QMutexLocker locker(signalSlotLock(receiver));
4381 if (!c->isSingleShot && !c->receiver.loadAcquire())
4383 QMetaCallEvent *ev = c->isSlotObject ?
4384 new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &latch) :
4385 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
4386 sender, signal_index, argv, &latch);
4387 QCoreApplication::postEvent(receiver, ev);
4394 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4397 QObjectPrivate::Sender senderData(
4398 receiverInSameThread ? receiver :
nullptr, sender, signal_index,
4399 receiverInSameThread ? QObjectPrivate::get(receiver)->connections.loadAcquire() :
nullptr);
4401 if (c->isSlotObject) {
4402 SlotObjectGuard obj{c->slotObj};
4405 Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
4406 obj->call(receiver, argv);
4408 }
else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
4410 const int method_relative = c->method_relative;
4411 const auto callFunction = c->callFunction;
4412 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
4413 if (callbacks_enabled && signal_spy_set->slot_begin_callback !=
nullptr)
4414 signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
4417 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
4418 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
4421 if (callbacks_enabled && signal_spy_set->slot_end_callback !=
nullptr)
4422 signal_spy_set->slot_end_callback(receiver, methodIndex);
4424 const int method = c->method_relative + c->method_offset;
4426 if (callbacks_enabled && signal_spy_set->slot_begin_callback !=
nullptr) {
4427 signal_spy_set->slot_begin_callback(receiver, method, argv);
4431 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
4432 QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
4435 if (callbacks_enabled && signal_spy_set->slot_end_callback !=
nullptr)
4436 signal_spy_set->slot_end_callback(receiver, method);
4438 }
while ((c = c->nextConnectionList.loadAcquire()) !=
nullptr && c->id.loadAcquire() <= highestConnectionId);
4440 }
while (list != &signalVector->at(-1) &&
4442 ((list = &signalVector->at(-1)),
true));
4444 if (connections->currentConnectionId.loadRelaxed() == 0)
4445 senderDeleted =
true;
4448 if (!senderDeleted) {
4449 sp->connections.loadAcquire()->cleanOrphanedConnections(sender);
4451 if (callbacks_enabled && signal_spy_set->signal_end_callback !=
nullptr)
4452 signal_spy_set->signal_end_callback(sender, signal_index);
4690void QObject::dumpObjectInfo()
const
4692 qDebug(
"OBJECT %s::%s", metaObject()->className(),
4693 objectName().isEmpty() ?
"unnamed" : objectName().toLocal8Bit().data());
4696 QMutexLocker locker(signalSlotLock(
this));
4699 qDebug(
" SIGNALS OUT");
4701 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
4702 if (cd && cd->signalVectorCount() > 0) {
4703 QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
4704 for (
int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
4705 const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
4708 const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index);
4709 qDebug(
" signal: %s", signal.methodSignature().constData());
4713 if (!c->receiver.loadRelaxed()) {
4714 qDebug(
" <Disconnected receiver>");
4715 c = c->nextConnectionList.loadRelaxed();
4718 if (c->isSlotObject) {
4719 qDebug(
" <functor or function pointer>");
4720 c = c->nextConnectionList.loadRelaxed();
4723 const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
4724 const QMetaMethod method = receiverMetaObject->method(c->method());
4725 qDebug(
" --> %s::%s %s",
4726 receiverMetaObject->className(),
4727 c->receiver.loadRelaxed()->objectName().isEmpty() ?
"unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
4728 method.methodSignature().constData());
4729 c = c->nextConnectionList.loadRelaxed();
4733 qDebug(
" <None>" );
4737 qDebug(
" SIGNALS IN");
4739 if (cd && cd->senders) {
4740 for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
4741 QByteArray slotName = QByteArrayLiteral(
"<unknown>");
4742 if (!s->isSlotObject) {
4743 const QMetaMethod slot = metaObject()->method(s->method());
4744 slotName = slot.methodSignature();
4746 qDebug(
" <-- %s::%s %s",
4747 s->sender->metaObject()->className(),
4748 s->sender->objectName().isEmpty() ?
"unnamed" : qPrintable(s->sender->objectName()),
4749 slotName.constData());
5540QMetaObject::Connection QObjectPrivate::connectImpl(
const QObject *sender,
int signal_index,
5541 const QObject *receiver,
void **slot,
5542 QtPrivate::QSlotObjectBase *slotObjRaw,
int type,
5543 const int *types,
const QMetaObject *senderMetaObject)
5545 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5546 Q_ASSERT(senderMetaObject);
5549 if (!sender || !receiver) {
5550 connectWarning(sender, senderMetaObject, receiver,
"invalid nullptr parameter");
5551 return QMetaObject::Connection();
5554 if (type & Qt::UniqueConnection && !slot) {
5555 connectWarning(sender, senderMetaObject, receiver,
"unique connections require a pointer to member function of a QObject subclass");
5556 return QMetaObject::Connection();
5559 QObject *s =
const_cast<QObject *>(sender);
5560 QObject *r =
const_cast<QObject *>(receiver);
5562 QOrderedMutexLocker locker(signalSlotLock(sender),
5563 signalSlotLock(receiver));
5565 if (type & Qt::UniqueConnection) {
5566 QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
5567 if (connections && connections->signalVectorCount() > signal_index) {
5568 const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
5571 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot))
5572 return QMetaObject::Connection();
5573 c2 = c2->nextConnectionList.loadRelaxed();
5577 type &= ~Qt::UniqueConnection;
5579 const bool isSingleShot = type & Qt::SingleShotConnection;
5580 type &= ~Qt::SingleShotConnection;
5582 Q_ASSERT(type >= 0);
5583 Q_ASSERT(type <= 3);
5585 std::unique_ptr<QObjectPrivate::Connection> c{
new QObjectPrivate::Connection};
5587 c->signal_index = signal_index;
5588 QThreadData *td = r->d_func()->threadData.loadAcquire();
5590 c->receiverThreadData.storeRelaxed(td);
5591 c->receiver.storeRelaxed(r);
5592 c->connectionType = type;
5593 c->isSlotObject =
true;
5594 c->slotObj = slotObj.release();
5596 c->argumentTypes.storeRelaxed(types);
5597 c->ownArgumentTypes =
false;
5599 c->isSingleShot = isSingleShot;
5601 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
5602 QMetaObject::Connection ret(c.release());
5605 QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
5606 Q_ASSERT(method.isValid());
5607 s->connectNotify(method);