1009 d->wasDeleted =
true;
1012 if (!d->bindingStorage.isValid()) {
1015 if (QThread *ownThread = thread()) {
1016 auto *privThread =
static_cast<QThreadPrivate *>(
1017 QObjectPrivate::get(ownThread));
1018 privThread->removeObjectWithPendingBindingStatusChange(
this);
1024 d->clearBindingStorage();
1026 QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.loadRelaxed();
1027 if (sharedRefcount) {
1028 if (sharedRefcount->strongref.loadRelaxed() > 0) {
1029 qWarning(
"QObject: shared QObject was deleted directly. The program is malformed and may crash.");
1034 sharedRefcount->strongref.storeRelaxed(0);
1035 if (!sharedRefcount->weakref.deref())
1036 delete sharedRefcount;
1039 if (!d->wasWidget && d->isSignalConnected(0)) {
1040 emit destroyed(
this);
1043 if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::destroyed)
1044 QAbstractDeclarativeData::destroyed(d->declarativeData,
this);
1046 QObjectPrivate::ConnectionData *cd = d->connections.loadAcquire();
1048 if (cd->currentSender) {
1049 cd->currentSender->receiverDeleted();
1050 cd->currentSender =
nullptr;
1053 QBasicMutex *signalSlotMutex = signalSlotLock(
this);
1054 QMutexLocker locker(signalSlotMutex);
1057 int receiverCount = cd->signalVectorCount();
1058 for (
int signal = -1; signal < receiverCount; ++signal) {
1059 QObjectPrivate::ConnectionList &connectionList = cd->connectionsForSignal(signal);
1061 while (QObjectPrivate::Connection *c = connectionList.first.loadRelaxed()) {
1062 Q_ASSERT(c->receiver.loadAcquire());
1064 QBasicMutex *m = signalSlotLock(c->receiver.loadRelaxed());
1065 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1066 if (c == connectionList.first.loadAcquire() && c->receiver.loadAcquire()) {
1067 cd->removeConnection(c);
1068 Q_ASSERT(connectionList.first.loadRelaxed() != c);
1076
1077 while (QObjectPrivate::Connection *node = cd->senders) {
1078 Q_ASSERT(node->receiver.loadAcquire());
1079 QObject *sender = node->sender;
1083 sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), node->signal_index));
1084 QBasicMutex *m = signalSlotLock(sender);
1085 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1087 if (node != cd->senders) {
1089 Q_ASSERT(needToUnlock);
1094 QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections.loadRelaxed();
1095 Q_ASSERT(senderData);
1097 QtPrivate::QSlotObjectBase *slotObj =
nullptr;
1098 if (node->isSlotObject) {
1099 slotObj = node->slotObj;
1100 node->isSlotObject =
false;
1103 senderData->removeConnection(node);
1105
1106
1107
1108
1109
1110
1111
1112 const bool locksAreTheSame = signalSlotMutex == m;
1113 if (!locksAreTheSame)
1115 senderData->cleanOrphanedConnections(
1117 QObjectPrivate::ConnectionData::AlreadyLockedAndTemporarilyReleasingLock
1122 if (locksAreTheSame)
1125 slotObj->destroyIfLastRef();
1131 cd->currentConnectionId.storeRelaxed(0);
1133 if (cd && !cd->ref.deref())
1135 d->connections.storeRelaxed(
nullptr);
1137 if (!d->children.isEmpty())
1138 d->deleteChildren();
1140 if (Q_UNLIKELY(qtHookData[QHooks::RemoveQObject]))
1141 reinterpret_cast<QHooks::RemoveQObjectCallback>(qtHookData[QHooks::RemoveQObject])(
this);
1143 Q_TRACE(QObject_dtor,
this);
1146 d->setParent_helper(
nullptr);
1400bool QObject::event(QEvent *e)
1402 switch (e->type()) {
1404 timerEvent((QTimerEvent *)e);
1407 case QEvent::ChildAdded:
1408 case QEvent::ChildPolished:
1409 case QEvent::ChildRemoved:
1410 childEvent((QChildEvent *)e);
1413 case QEvent::DeferredDelete:
1417 case QEvent::MetaCall:
1419 QAbstractMetaCallEvent *mce =
static_cast<QAbstractMetaCallEvent*>(e);
1421 QObjectPrivate::ConnectionData *connections = d_func()->connections.loadAcquire();
1423 QMutexLocker locker(signalSlotLock(
this));
1424 d_func()->ensureConnectionData();
1425 connections = d_func()->connections.loadRelaxed();
1427 QObjectPrivate::Sender sender(
this,
const_cast<QObject*>(mce->sender()), mce->signalId(), connections);
1429 mce->placeMetaCall(
this);
1433 case QEvent::ThreadChange: {
1435 QThreadData *threadData = d->threadData.loadRelaxed();
1436 QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
1437 if (eventDispatcher) {
1438 QList<QAbstractEventDispatcher::TimerInfoV2> timers = eventDispatcher->timersForObject(
this);
1439 if (!timers.isEmpty()) {
1440 const bool res = eventDispatcher->unregisterTimers(
this);
1442 Q_ASSERT_X(res, Q_FUNC_INFO,
1443 "QAbstractEventDispatcher::unregisterTimers() returned false,"
1444 " but there are timers associated with this object.");
1445 auto reRegisterTimers = [
this, timers = std::move(timers)]() {
1446 QAbstractEventDispatcher *eventDispatcher =
1447 d_func()->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
1448 for (
const auto &ti : timers)
1449 eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType,
this);
1451 QMetaObject::invokeMethod(
this, std::move(reRegisterTimers), Qt::QueuedConnection);
1458 if (e->type() >= QEvent::User) {
1653bool QObject::moveToThread(QThread *targetThread QT6_IMPL_NEW_OVERLOAD_TAIL)
1657 if (d->threadData.loadRelaxed()->thread.loadAcquire() == targetThread) {
1662 if (d->parent !=
nullptr) {
1663 qWarning(
"QObject::moveToThread: Cannot move objects with a parent");
1667 qWarning(
"QObject::moveToThread: Widgets cannot be moved to a new thread");
1670 if (!d->bindingStorage.isEmpty()) {
1671 qWarning(
"QObject::moveToThread: Can not move objects that contain bindings or are used in bindings to a new thread.");
1675 QThreadData *currentData = QThreadData::current();
1676 QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) :
nullptr;
1677 QThreadData *thisThreadData = d->threadData.loadAcquire();
1678 if (!thisThreadData->thread.loadRelaxed() && currentData == targetData) {
1680 currentData = thisThreadData;
1681 }
else if (thisThreadData != currentData) {
1682 qWarning(
"QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
1683 "Cannot move to target thread (%p)\n",
1684 currentData->thread.loadRelaxed(), thisThreadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() :
nullptr);
1687 qWarning(
"You might be loading two sets of Qt binaries into the same process. "
1688 "Check that all plugins are compiled against the right Qt binaries. Export "
1689 "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.");
1696 d->moveToThread_helper();
1699 targetData =
new QThreadData(0);
1702 QMutexLocker l(signalSlotLock(
this));
1704 QOrderedMutexLocker locker(¤tData->postEventList.mutex,
1705 &targetData->postEventList.mutex);
1711 auto threadPrivate = targetThread
1712 ?
static_cast<QThreadPrivate *>(QThreadPrivate::get(targetThread))
1714 QBindingStatus *bindingStatus = threadPrivate
1715 ? threadPrivate->bindingStatus()
1717 if (threadPrivate && !bindingStatus) {
1718 bindingStatus = threadPrivate->addObjectWithPendingBindingStatusChange(
this);
1720 d_func()->setThreadData_helper(currentData, targetData, bindingStatus);
1725 currentData->deref();
1741void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status)
1747 this->bindingStorage.bindingStatus = status;
1751 qsizetype eventsMoved = 0;
1752 for (qsizetype i = 0; i < currentData->postEventList.size(); ++i) {
1753 const QPostEvent &pe = currentData->postEventList.at(i);
1756 if (pe.receiver == q) {
1758 targetData->postEventList.addEvent(pe);
1759 const_cast<QPostEvent &>(pe).event =
nullptr;
1763 if (eventsMoved > 0 && targetData->hasEventDispatcher()) {
1764 targetData->canWait =
false;
1765 targetData->eventDispatcher.loadRelaxed()->wakeUp();
1769 ConnectionData *cd = connections.loadAcquire();
1771 if (cd->currentSender) {
1772 cd->currentSender->receiverDeleted();
1773 cd->currentSender =
nullptr;
1778 auto *c = cd->senders;
1780 QObject *r = c->receiver.loadRelaxed();
1784 QThreadData *old = c->receiverThreadData.loadRelaxed();
1787 c->receiverThreadData.storeRelaxed(targetData);
1797 threadData.loadRelaxed()->deref();
1800 threadData.storeRelease(targetData);
1802 for (
int i = 0; i < children.size(); ++i) {
1803 QObject *child = children.at(i);
1804 child->d_func()->setThreadData_helper(currentData, targetData, status);
2233void QObjectPrivate::setParent_helper(QObject *o)
2236 Q_ASSERT_X(q != o, Q_FUNC_INFO,
"Cannot parent a QObject to itself");
2238 const auto checkForParentChildLoops = qScopeGuard([&](){
2242 if (++depth == CheckForParentChildLoopsWarnDepth) {
2243 qWarning(
"QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
2244 "this is undefined behavior",
2245 q, q->metaObject()->className(), qPrintable(q->objectName()));
2256 QObjectPrivate *parentD = parent->d_func();
2257 if (parentD->isDeletingChildren && wasDeleted
2258 && parentD->currentChildBeingDeleted == q) {
2262 const int index = parentD->children.indexOf(q);
2265 }
else if (parentD->isDeletingChildren) {
2266 parentD->children[index] =
nullptr;
2268 parentD->children.removeAt(index);
2269 if (sendChildEvents && parentD->receiveChildEvents) {
2270 QChildEvent e(QEvent::ChildRemoved, q);
2271 QCoreApplication::sendEvent(parent, &e);
2277 if (receiveParentEvents) {
2278 Q_ASSERT(!isWidget);
2279 QEvent e(QEvent::ParentAboutToChange);
2280 QCoreApplication::sendEvent(q, &e);
2287 if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) {
2288 qWarning(
"QObject::setParent: Cannot set parent, new parent is in a different thread");
2292 parent->d_func()->children.append(q);
2293 if (sendChildEvents && parent->d_func()->receiveChildEvents) {
2295 QChildEvent e(QEvent::ChildAdded, q);
2296 QCoreApplication::sendEvent(parent, &e);
2301 if (receiveParentEvents) {
2302 Q_ASSERT(!isWidget);
2303 QEvent e(QEvent::ParentChange);
2304 QCoreApplication::sendEvent(q, &e);
2975QMetaObject::Connection QObject::connect(
const QObject *sender,
const char *signal,
2976 const QObject *receiver,
const char *method,
2977 Qt::ConnectionType type)
2979 if (sender ==
nullptr || receiver ==
nullptr || signal ==
nullptr || method ==
nullptr) {
2980 qCWarning(lcConnect,
"QObject::connect: Cannot connect %s::%s to %s::%s",
2981 sender ? sender->metaObject()->className() :
"(nullptr)",
2982 (signal && *signal) ? signal + 1 :
"(nullptr)",
2983 receiver ? receiver->metaObject()->className() :
"(nullptr)",
2984 (method && *method) ? method + 1 :
"(nullptr)");
2985 return QMetaObject::Connection(
nullptr);
2987 QByteArray tmp_signal_name;
2989 if (!check_signal_macro(sender, signal,
"connect",
"bind"))
2990 return QMetaObject::Connection(
nullptr);
2991 const QMetaObject *smeta = sender->metaObject();
2992 const char *signal_arg = signal;
2994 QArgumentTypeArray signalTypes;
2995 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
2996 QByteArray signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
2997 int signal_index = QMetaObjectPrivate::indexOfSignalRelative(
2998 &smeta, signalName, signalTypes.size(), signalTypes.constData());
2999 if (signal_index < 0) {
3001 tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
3002 signal = tmp_signal_name.constData() + 1;
3004 signalTypes.clear();
3005 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3006 smeta = sender->metaObject();
3007 signal_index = QMetaObjectPrivate::indexOfSignalRelative(
3008 &smeta, signalName, signalTypes.size(), signalTypes.constData());
3010 if (signal_index < 0) {
3011 err_method_notfound(sender, signal_arg,
"connect");
3012 err_info_about_objects(
"connect", sender, receiver);
3013 return QMetaObject::Connection(
nullptr);
3015 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3016 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3018 QByteArray tmp_method_name;
3019 int membcode = extract_code(method);
3021 if (!check_method_code(membcode, receiver, method,
"connect"))
3022 return QMetaObject::Connection(
nullptr);
3023 const char *method_arg = method;
3026 QArgumentTypeArray methodTypes;
3027 QByteArray methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3028 const QMetaObject *rmeta = receiver->metaObject();
3029 int method_index_relative = -1;
3030 Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
3033 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3034 &rmeta, methodName, methodTypes.size(), methodTypes.constData());
3037 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3038 &rmeta, methodName, methodTypes.size(), methodTypes.constData());
3041 if (method_index_relative < 0) {
3043 tmp_method_name = QMetaObject::normalizedSignature(method);
3044 method = tmp_method_name.constData();
3046 methodTypes.clear();
3047 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3049 rmeta = receiver->metaObject();
3052 method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
3053 &rmeta, methodName, methodTypes.size(), methodTypes.constData());
3056 method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
3057 &rmeta, methodName, methodTypes.size(), methodTypes.constData());
3062 if (method_index_relative < 0) {
3063 err_method_notfound(receiver, method_arg,
"connect");
3064 err_info_about_objects(
"connect", sender, receiver);
3065 return QMetaObject::Connection(
nullptr);
3068 if (!QMetaObjectPrivate::checkConnectArgs(signalTypes.size(), signalTypes.constData(),
3069 methodTypes.size(), methodTypes.constData())) {
3071 "QObject::connect: Incompatible sender/receiver arguments"
3072 "\n %s::%s --> %s::%s",
3073 sender->metaObject()->className(), signal, receiver->metaObject()->className(),
3075 return QMetaObject::Connection(
nullptr);
3080 int *types =
nullptr;
3081 if ((type == Qt::QueuedConnection)
3082 && !(types = queuedConnectionTypes(signalTypes.constData(), signalTypes.size()))) {
3083 return QMetaObject::Connection(
nullptr);
3087 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3088 QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
3089 check_and_warn_compat(smeta, smethod, rmeta, rmethod);
3091 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3092 sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
3116QMetaObject::Connection QObject::connect(
const QObject *sender,
const QMetaMethod &signal,
3117 const QObject *receiver,
const QMetaMethod &method,
3118 Qt::ConnectionType type)
3120 if (sender ==
nullptr
3121 || receiver ==
nullptr
3122 || signal.methodType() != QMetaMethod::Signal
3123 || method.methodType() == QMetaMethod::Constructor) {
3124 qCWarning(lcConnect,
"QObject::connect: Cannot connect %s::%s to %s::%s",
3125 sender ? sender->metaObject()->className() :
"(nullptr)",
3126 signal.methodSignature().constData(),
3127 receiver ? receiver->metaObject()->className() :
"(nullptr)",
3128 method.methodSignature().constData());
3129 return QMetaObject::Connection(
nullptr);
3136 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3137 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3140 const QMetaObject *smeta = sender->metaObject();
3141 const QMetaObject *rmeta = receiver->metaObject();
3142 if (signal_index == -1) {
3143 qCWarning(lcConnect,
"QObject::connect: Can't find signal %s on instance of class %s",
3144 signal.methodSignature().constData(), smeta->className());
3145 return QMetaObject::Connection(
nullptr);
3147 if (method_index == -1) {
3148 qCWarning(lcConnect,
"QObject::connect: Can't find method %s on instance of class %s",
3149 method.methodSignature().constData(), rmeta->className());
3150 return QMetaObject::Connection(
nullptr);
3153 if (!QMetaObject::checkConnectArgs(signal.methodSignature().constData(),
3154 method.methodSignature().constData())) {
3156 "QObject::connect: Incompatible sender/receiver arguments"
3157 "\n %s::%s --> %s::%s",
3158 smeta->className(), signal.methodSignature().constData(), rmeta->className(),
3159 method.methodSignature().constData());
3160 return QMetaObject::Connection(
nullptr);
3163 int *types =
nullptr;
3164 if ((type == Qt::QueuedConnection) && !(types = queuedConnectionTypes(signal)))
3165 return QMetaObject::Connection(
nullptr);
3168 check_and_warn_compat(smeta, signal, rmeta, method);
3170 QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
3171 sender, signal_index, signal.enclosingMetaObject(), receiver, method_index,
nullptr, type, types));
3256bool QObject::disconnect(
const QObject *sender,
const char *signal,
3257 const QObject *receiver,
const char *method)
3259 if (sender ==
nullptr || (receiver ==
nullptr && method !=
nullptr)) {
3260 qCWarning(lcConnect,
"QObject::disconnect: Unexpected nullptr parameter");
3264 const char *signal_arg = signal;
3265 QByteArray signal_name;
3266 bool signal_found =
false;
3269 signal_name = QMetaObject::normalizedSignature(signal);
3270 signal = signal_name.constData();
3271 } QT_CATCH (
const std::bad_alloc &) {
3273 if (sender->metaObject()->indexOfSignal(signal + 1) == -1)
3277 if (!check_signal_macro(sender, signal,
"disconnect",
"unbind"))
3282 QByteArray method_name;
3283 const char *method_arg = method;
3285 bool method_found =
false;
3288 method_name = QMetaObject::normalizedSignature(method);
3289 method = method_name.constData();
3290 } QT_CATCH(
const std::bad_alloc &) {
3292 if (receiver->metaObject()->indexOfMethod(method + 1) == -1)
3296 membcode = extract_code(method);
3297 if (!check_method_code(membcode, receiver, method,
"disconnect"))
3303
3304
3305
3307 const QMetaObject *smeta = sender->metaObject();
3308 QByteArray signalName;
3309 QArgumentTypeArray signalTypes;
3310 Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3312 signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3313 QByteArray methodName;
3314 QArgumentTypeArray methodTypes;
3315 Q_ASSERT(!receiver || QMetaObjectPrivate::get(receiver->metaObject())->revision >= 7);
3317 methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3319 int signal_index = -1;
3321 signal_index = QMetaObjectPrivate::indexOfSignalRelative(
3322 &smeta, signalName, signalTypes.size(), signalTypes.constData());
3323 if (signal_index < 0)
3325 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3326 signal_index += QMetaObjectPrivate::signalOffset(smeta);
3327 signal_found =
true;
3331 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1,
nullptr);
3333 const QMetaObject *rmeta = receiver->metaObject();
3335 int method_index = QMetaObjectPrivate::indexOfMethod(
3336 rmeta, methodName, methodTypes.size(), methodTypes.constData());
3337 if (method_index >= 0)
3338 while (method_index < rmeta->methodOffset())
3339 rmeta = rmeta->superClass();
3340 if (method_index < 0)
3342 res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index,
nullptr);
3343 method_found =
true;
3344 }
while ((rmeta = rmeta->superClass()));
3346 }
while (signal && (smeta = smeta->superClass()));
3348 if (signal && !signal_found) {
3349 err_method_notfound(sender, signal_arg,
"disconnect");
3350 err_info_about_objects(
"disconnect", sender, receiver);
3351 }
else if (method && !method_found) {
3352 err_method_notfound(receiver, method_arg,
"disconnect");
3353 err_info_about_objects(
"disconnect", sender, receiver);
3357 const_cast<QObject *>(sender)->disconnectNotify(QMetaMethod());
3396bool QObject::disconnect(
const QObject *sender,
const QMetaMethod &signal,
3397 const QObject *receiver,
const QMetaMethod &method)
3399 if (sender ==
nullptr || (receiver ==
nullptr && method.mobj !=
nullptr)) {
3400 qCWarning(lcConnect,
"QObject::disconnect: Unexpected nullptr parameter");
3404 if (signal.methodType() != QMetaMethod::Signal) {
3405 qCWarning(lcConnect,
"QObject::%s: Attempt to %s non-signal %s::%s",
3406 "disconnect",
"unbind",
3407 sender->metaObject()->className(), signal.methodSignature().constData());
3412 if (method.methodType() == QMetaMethod::Constructor) {
3413 qCWarning(lcConnect,
"QObject::disconnect: cannot use constructor as argument %s::%s",
3414 receiver->metaObject()->className(), method.methodSignature().constData());
3423 QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3424 QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3428 if (signal.mobj && signal_index == -1) {
3429 qCWarning(lcConnect,
"QObject::disconnect: signal %s not found on class %s",
3430 signal.methodSignature().constData(), sender->metaObject()->className());
3434 if (receiver && method.mobj && method_index == -1) {
3435 qCWarning(lcConnect,
"QObject::disconnect: method %s not found on class %s",
3436 method.methodSignature().constData(), receiver->metaObject()->className());
3440 if (!QMetaObjectPrivate::disconnect(sender, signal_index, signal.mobj, receiver, method_index,
nullptr))
3443 if (!signal.isValid()) {
3448 const_cast<QObject *>(sender)->disconnectNotify(signal);
3605 int signal_index,
const QMetaObject *smeta,
3606 const QObject *receiver,
int method_index,
3607 const QMetaObject *rmeta,
int type,
int *types)
3609 QObject *s =
const_cast<QObject *>(sender);
3610 QObject *r =
const_cast<QObject *>(receiver);
3612 int method_offset = rmeta ? rmeta->methodOffset() : 0;
3614 QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall :
nullptr;
3616 QOrderedMutexLocker locker(signalSlotLock(sender),
3617 signalSlotLock(receiver));
3619 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3620 if (type & Qt::UniqueConnection && scd) {
3621 if (scd->signalVectorCount() > signal_index) {
3622 const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
3624 int method_index_absolute = method_index + method_offset;
3627 if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute)
3629 c2 = c2->nextConnectionList.loadRelaxed();
3633 type &= ~Qt::UniqueConnection;
3635 const bool isSingleShot = type & Qt::SingleShotConnection;
3636 type &= ~Qt::SingleShotConnection;
3638 Q_ASSERT(type >= 0);
3639 Q_ASSERT(type <= 3);
3641 std::unique_ptr<QObjectPrivate::Connection> c{
new QObjectPrivate::Connection};
3643 c->signal_index = signal_index;
3644 c->receiver.storeRelaxed(r);
3645 QThreadData *td = r->d_func()->threadData.loadAcquire();
3647 c->receiverThreadData.storeRelaxed(td);
3648 c->method_relative = method_index;
3649 c->method_offset = method_offset;
3650 c->connectionType = type;
3651 c->isSlotObject =
false;
3652 c->argumentTypes.storeRelaxed(types);
3653 c->callFunction = callFunction;
3654 c->isSingleShot = isSingleShot;
3656 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
3659 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3660 if (smethod.isValid())
3661 s->connectNotify(smethod);
3739bool QMetaObjectPrivate::disconnect(
const QObject *sender,
3740 int signal_index,
const QMetaObject *smeta,
3741 const QObject *receiver,
int method_index,
void **slot,
3742 DisconnectType disconnectType)
3747 QObject *s =
const_cast<QObject *>(sender);
3749 QBasicMutex *senderMutex = signalSlotLock(sender);
3750 QMutexLocker locker(senderMutex);
3752 QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
3756 bool success =
false;
3759 QObjectPrivate::ConnectionDataPointer connections(scd);
3761 if (signal_index < 0) {
3763 for (
int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
3764 if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
3767 }
else if (signal_index < scd->signalVectorCount()) {
3768 if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
3775 scd->cleanOrphanedConnections(s);
3777 QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3778 if (smethod.isValid())
3779 s->disconnectNotify(smethod);
3835void QMetaObject::connectSlotsByName(QObject *o)
3839 const QMetaObject *mo = o->metaObject();
3841 const QObjectList list =
3842 o->findChildren<QObject *>()
3846 for (
int i = 0; i < mo->methodCount(); ++i) {
3847 const QByteArray slotSignature = mo->method(i).methodSignature();
3848 const char *slot = slotSignature.constData();
3852 if (slot[0] !=
'o' || slot[1] !=
'n' || slot[2] !=
'_')
3856 bool foundIt =
false;
3857 for (
int j = 0; j < list.size(); ++j) {
3858 const QObject *co = list.at(j);
3859 const QByteArray coName = co->objectName().toLatin1();
3862 if (coName.isEmpty() || qstrncmp(slot + 3, coName.constData(), coName.size()) || slot[coName.size()+3] !=
'_')
3865 const char *signal = slot + coName.size() + 4;
3868 const QMetaObject *smeta;
3869 int sigIndex = co->d_func()->signalIndex(signal, &smeta);
3875 QList<QByteArray> compatibleSignals;
3876 const QMetaObject *smo = co->metaObject();
3877 int sigLen =
int(qstrlen(signal)) - 1;
3878 for (
int k = QMetaObjectPrivate::absoluteSignalCount(smo)-1; k >= 0; --k) {
3879 const QMetaMethod method = QMetaObjectPrivate::signal(smo, k);
3880 if (!qstrncmp(method.methodSignature().constData(), signal, sigLen)) {
3881 smeta = method.enclosingMetaObject();
3883 compatibleSignals.prepend(method.methodSignature());
3886 if (compatibleSignals.size() > 1)
3887 qCWarning(lcConnectSlotsByName) <<
"QMetaObject::connectSlotsByName: Connecting slot" << slot
3888 <<
"with the first of the following compatible signals:" << compatibleSignals;
3895 if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) {
3897 qCDebug(lcConnectSlotsByName,
"%s",
3898 msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData());
3908 while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
3910 }
else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
3912 int iParen = slotSignature.indexOf(
'(');
3913 int iLastUnderscore = slotSignature.lastIndexOf(
'_', iParen - 1);
3914 if (iLastUnderscore > 3)
3916 "QMetaObject::connectSlotsByName: No matching signal for %s", slot);
4046static void queued_activate(QObject *sender,
int signal, QObjectPrivate::Connection *c,
void **argv)
4048 const int *argumentTypes = c->argumentTypes.loadRelaxed();
4049 if (!argumentTypes) {
4050 QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
4051 argumentTypes = queuedConnectionTypes(m);
4053 argumentTypes = &DIRECT_CONNECTION_ONLY;
4054 if (!c->argumentTypes.testAndSetOrdered(
nullptr, argumentTypes)) {
4055 if (argumentTypes != &DIRECT_CONNECTION_ONLY)
4056 delete[] argumentTypes;
4057 argumentTypes = c->argumentTypes.loadRelaxed();
4060 if (argumentTypes == &DIRECT_CONNECTION_ONLY)
4063 while (argumentTypes[nargs - 1])
4066 QMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
4067 QObject *receiver = c->receiver.loadRelaxed();
4073 SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj :
nullptr };
4076 QMetaCallEvent *ev = c->isSlotObject ?
4077 new QMetaCallEvent(c->slotObj, sender, signal, nargs) :
4078 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs);
4080 void **args = ev->args();
4081 QMetaType *types = ev->types();
4083 types[0] = QMetaType();
4087 for (
int n = 1; n < nargs; ++n)
4088 types[n] = QMetaType(argumentTypes[n - 1]);
4090 for (
int n = 1; n < nargs; ++n)
4091 args[n] = types[n].create(argv[n]);
4094 if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) {
4100 if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
4107 QCoreApplication::postEvent(receiver, ev);
4111void doActivate(QObject *sender,
int signal_index,
void **argv)
4113 QObjectPrivate *sp = QObjectPrivate::get(sender);
4118 Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
4120 if (sp->isDeclarativeSignalConnected(signal_index)
4121 && QAbstractDeclarativeData::signalEmitted) {
4122 Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
4123 QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
4124 signal_index, argv);
4127 const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() :
nullptr;
4129 void *empty_argv[] = {
nullptr };
4133 if (!sp->maybeSignalConnected(signal_index)) {
4135 if (callbacks_enabled && signal_spy_set->signal_begin_callback !=
nullptr)
4136 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4137 if (callbacks_enabled && signal_spy_set->signal_end_callback !=
nullptr)
4138 signal_spy_set->signal_end_callback(sender, signal_index);
4142 if (callbacks_enabled && signal_spy_set->signal_begin_callback !=
nullptr)
4143 signal_spy_set->signal_begin_callback(sender, signal_index, argv);
4145 bool senderDeleted =
false;
4147 Q_ASSERT(sp->connections.loadRelaxed());
4148 QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadAcquire());
4149 QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();
4151 const QObjectPrivate::ConnectionList *list;
4152 if (signal_index < signalVector->count())
4153 list = &signalVector->at(signal_index);
4155 list = &signalVector->at(-1);
4157 Qt::HANDLE currentThreadId = QThread::currentThreadId();
4158 bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
4162 uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
4164 QObjectPrivate::Connection *c = list->first.loadRelaxed();
4169 QObject *
const receiver = c->receiver.loadRelaxed();
4173 QThreadData *td = c->receiverThreadData.loadRelaxed();
4177 bool receiverInSameThread;
4178 if (inSenderThread) {
4179 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4182 QMutexLocker lock(signalSlotLock(receiver));
4183 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
4189 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
4190 || (c->connectionType == Qt::QueuedConnection)) {
4191 queued_activate(sender, signal_index, c, argv);
4193#if QT_CONFIG(thread)
4194 }
else if (c->connectionType == Qt::BlockingQueuedConnection) {
4195 if (receiverInSameThread) {
4196 qWarning(
"Qt: Dead lock detected while activating a BlockingQueuedConnection: "
4197 "Sender is %s(%p), receiver is %s(%p)",
4198 sender->metaObject()->className(), sender,
4199 receiver->metaObject()->className(), receiver);
4202 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4205 QSemaphore semaphore;
4207 QMutexLocker locker(signalSlotLock(receiver));
4208 if (!c->isSingleShot && !c->receiver.loadAcquire())
4210 QMetaCallEvent *ev = c->isSlotObject ?
4211 new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &semaphore) :
4212 new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
4213 sender, signal_index, argv, &semaphore);
4214 QCoreApplication::postEvent(receiver, ev);
4216 semaphore.acquire();
4221 if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
4224 QObjectPrivate::Sender senderData(
4225 receiverInSameThread ? receiver :
nullptr, sender, signal_index,
4226 receiverInSameThread ? QObjectPrivate::get(receiver)->connections.loadAcquire() :
nullptr);
4228 if (c->isSlotObject) {
4229 SlotObjectGuard obj{c->slotObj};
4232 Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
4233 obj->call(receiver, argv);
4235 }
else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
4237 const int method_relative = c->method_relative;
4238 const auto callFunction = c->callFunction;
4239 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
4240 if (callbacks_enabled && signal_spy_set->slot_begin_callback !=
nullptr)
4241 signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
4244 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
4245 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
4248 if (callbacks_enabled && signal_spy_set->slot_end_callback !=
nullptr)
4249 signal_spy_set->slot_end_callback(receiver, methodIndex);
4251 const int method = c->method_relative + c->method_offset;
4253 if (callbacks_enabled && signal_spy_set->slot_begin_callback !=
nullptr) {
4254 signal_spy_set->slot_begin_callback(receiver, method, argv);
4258 Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
4259 QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
4262 if (callbacks_enabled && signal_spy_set->slot_end_callback !=
nullptr)
4263 signal_spy_set->slot_end_callback(receiver, method);
4265 }
while ((c = c->nextConnectionList.loadRelaxed()) !=
nullptr && c->id <= highestConnectionId);
4267 }
while (list != &signalVector->at(-1) &&
4269 ((list = &signalVector->at(-1)),
true));
4271 if (connections->currentConnectionId.loadRelaxed() == 0)
4272 senderDeleted =
true;
4274 if (!senderDeleted) {
4275 sp->connections.loadAcquire()->cleanOrphanedConnections(sender);
4277 if (callbacks_enabled && signal_spy_set->signal_end_callback !=
nullptr)
4278 signal_spy_set->signal_end_callback(sender, signal_index);
4524void QObject::dumpObjectInfo()
const
4526 qDebug(
"OBJECT %s::%s", metaObject()->className(),
4527 objectName().isEmpty() ?
"unnamed" : objectName().toLocal8Bit().data());
4530 QMutexLocker locker(signalSlotLock(
this));
4533 qDebug(
" SIGNALS OUT");
4535 QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
4536 if (cd && cd->signalVectorCount() > 0) {
4537 QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
4538 for (
int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
4539 const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
4542 const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index);
4543 qDebug(
" signal: %s", signal.methodSignature().constData());
4547 if (!c->receiver.loadRelaxed()) {
4548 qDebug(
" <Disconnected receiver>");
4549 c = c->nextConnectionList.loadRelaxed();
4552 if (c->isSlotObject) {
4553 qDebug(
" <functor or function pointer>");
4554 c = c->nextConnectionList.loadRelaxed();
4557 const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
4558 const QMetaMethod method = receiverMetaObject->method(c->method());
4559 qDebug(
" --> %s::%s %s",
4560 receiverMetaObject->className(),
4561 c->receiver.loadRelaxed()->objectName().isEmpty() ?
"unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
4562 method.methodSignature().constData());
4563 c = c->nextConnectionList.loadRelaxed();
4567 qDebug(
" <None>" );
4571 qDebug(
" SIGNALS IN");
4573 if (cd && cd->senders) {
4574 for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
4575 QByteArray slotName = QByteArrayLiteral(
"<unknown>");
4576 if (!s->isSlotObject) {
4577 const QMetaMethod slot = metaObject()->method(s->method());
4578 slotName = slot.methodSignature();
4580 qDebug(
" <-- %s::%s %s",
4581 s->sender->metaObject()->className(),
4582 s->sender->objectName().isEmpty() ?
"unnamed" : qPrintable(s->sender->objectName()),
4583 slotName.constData());
5362QMetaObject::Connection QObjectPrivate::connectImpl(
const QObject *sender,
int signal_index,
5363 const QObject *receiver,
void **slot,
5364 QtPrivate::QSlotObjectBase *slotObjRaw,
int type,
5365 const int *types,
const QMetaObject *senderMetaObject)
5367 QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
5369 if (!sender || !receiver || !slotObj || !senderMetaObject) {
5370 connectWarning(sender, senderMetaObject, receiver,
"invalid nullptr parameter");
5371 return QMetaObject::Connection();
5374 if (type & Qt::UniqueConnection && !slot) {
5375 connectWarning(sender, senderMetaObject, receiver,
"unique connections require a pointer to member function of a QObject subclass");
5376 return QMetaObject::Connection();
5379 QObject *s =
const_cast<QObject *>(sender);
5380 QObject *r =
const_cast<QObject *>(receiver);
5382 QOrderedMutexLocker locker(signalSlotLock(sender),
5383 signalSlotLock(receiver));
5385 if (type & Qt::UniqueConnection && slot) {
5386 QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
5387 if (connections && connections->signalVectorCount() > signal_index) {
5388 const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
5391 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot))
5392 return QMetaObject::Connection();
5393 c2 = c2->nextConnectionList.loadRelaxed();
5397 type &= ~Qt::UniqueConnection;
5399 const bool isSingleShot = type & Qt::SingleShotConnection;
5400 type &= ~Qt::SingleShotConnection;
5402 Q_ASSERT(type >= 0);
5403 Q_ASSERT(type <= 3);
5405 std::unique_ptr<QObjectPrivate::Connection> c{
new QObjectPrivate::Connection};
5407 c->signal_index = signal_index;
5408 QThreadData *td = r->d_func()->threadData.loadAcquire();
5410 c->receiverThreadData.storeRelaxed(td);
5411 c->receiver.storeRelaxed(r);
5412 c->connectionType = type;
5413 c->isSlotObject =
true;
5414 c->slotObj = slotObj.release();
5416 c->argumentTypes.storeRelaxed(types);
5417 c->ownArgumentTypes =
false;
5419 c->isSingleShot = isSingleShot;
5421 QObjectPrivate::get(s)->addConnection(signal_index, c.get());
5422 QMetaObject::Connection ret(c.release());
5425 QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
5426 Q_ASSERT(method.isValid());
5427 s->connectNotify(method);