diff options
Diffstat (limited to 'src/corelib/kernel/qobject.cpp')
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 183 |
1 files changed, 111 insertions, 72 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index c6153cb..357cfd3 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -263,12 +263,6 @@ public: : QVector<QObjectPrivate::ConnectionList>(), orphaned(false), dirty(false), inUse(0) { } - const QObjectPrivate::ConnectionList &at(int at) const - { - if (at < 0) - return allsignals; - return QVector<QObjectPrivate::ConnectionList>::at(at); - } QObjectPrivate::ConnectionList &operator[](int at) { if (at < 0) @@ -496,10 +490,12 @@ void QObjectPrivate::clearGuards(QObject *object) /*! \internal */ -QMetaCallEvent::QMetaCallEvent(int id, const QObject *sender, int signalId, +QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction, + const QObject *sender, int signalId, int nargs, int *types, void **args, QSemaphore *semaphore) - : QEvent(MetaCall), id_(id), sender_(sender), signalId_(signalId), - nargs_(nargs), types_(types), args_(args), semaphore_(semaphore) + : QEvent(MetaCall), sender_(sender), signalId_(signalId), + nargs_(nargs), types_(types), args_(args), semaphore_(semaphore), + callFunction_(callFunction), method_offset_(method_offset), method_relative_(method_relative) { } /*! \internal @@ -522,9 +518,13 @@ QMetaCallEvent::~QMetaCallEvent() /*! \internal */ -int QMetaCallEvent::placeMetaCall(QObject *object) +void QMetaCallEvent::placeMetaCall(QObject *object) { - return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, id_, args_); + if (callFunction_) { + callFunction_(object, QMetaObject::InvokeMetaMethod, method_relative_, args_); + } else { + QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, method_offset_ + method_relative_, args_); + } } /*! @@ -2613,18 +2613,17 @@ bool QObject::connect(const QObject *sender, const char *signal, ++method; // skip code const QMetaObject *rmeta = receiver->metaObject(); - int method_index = -1; + int method_index_relative = -1; switch (membcode) { case QSLOT_CODE: - method_index = QMetaObjectPrivate::indexOfSlot(rmeta, method, false); + method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false); break; case QSIGNAL_CODE: - method_index = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false); - if (method_index >= 0) - method_index += rmeta->methodOffset(); + method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false); break; } - if (method_index < 0) { + + if (method_index_relative < 0) { // check for normalized methods tmp_method_name = QMetaObject::normalizedSignature(method); method = tmp_method_name.constData(); @@ -2633,19 +2632,24 @@ bool QObject::connect(const QObject *sender, const char *signal, rmeta = receiver->metaObject(); switch (membcode) { case QSLOT_CODE: - method_index = rmeta->indexOfSlot(method); + method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false); + if (method_index_relative < 0) + method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, true); break; case QSIGNAL_CODE: - method_index = rmeta->indexOfSignal(method); + method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false); + if (method_index_relative < 0) + method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, true); break; } } - if (method_index < 0) { + if (method_index_relative < 0) { err_method_notfound(receiver, method_arg, "connect"); err_info_about_objects("connect", sender, receiver); return false; } + if (!QMetaObject::checkConnectArgs(signal, method)) { qWarning("QObject::connect: Incompatible sender/receiver arguments" "\n %s::%s --> %s::%s", @@ -2660,14 +2664,13 @@ bool QObject::connect(const QObject *sender, const char *signal, return false; #ifndef QT_NO_DEBUG - { + if (warnCompat) { QMetaMethod smethod = smeta->method(signal_absolute_index); - QMetaMethod rmethod = rmeta->method(method_index); - if (warnCompat) - check_and_warn_compat(smeta, smethod, rmeta, rmethod); + QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset()); + check_and_warn_compat(smeta, smethod, rmeta, rmethod); } #endif - if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index, type, types)) + if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index_relative, rmeta ,type, types)) return false; const_cast<QObject*>(sender)->connectNotify(signal - 1); return true; @@ -2772,7 +2775,7 @@ bool QObject::connect(const QObject *sender, const QMetaMethod &signal, if (warnCompat) check_and_warn_compat(smeta, signal, rmeta, method); #endif - if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index, type, types)) + if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index, 0, type, types)) return false; const_cast<QObject*>(sender)->connectNotify(signalSignature.constData()); @@ -3163,18 +3166,28 @@ bool QMetaObject::connect(const QObject *sender, int signal_index, { signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index); return QMetaObjectPrivate::connect(sender, signal_index, - receiver, method_index, type, types); + receiver, method_index, + 0, //FIXME, we could speed this connection up by computing the relative index + type, types); } /*! \internal Same as the QMetaObject::connect, but \a signal_index must be the result of QObjectPrivate::signalIndex + + method_index is relative to the rmeta metaobject, if rmeta is null, then it is absolute index */ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index, - const QObject *receiver, int method_index, int type, int *types) + const QObject *receiver, int method_index, + const QMetaObject *rmeta, int type, int *types) { QObject *s = const_cast<QObject *>(sender); QObject *r = const_cast<QObject *>(receiver); + int method_offset = rmeta ? rmeta->methodOffset() : 0; + QObjectPrivate::StaticMetaCallFunction callFunction = + (rmeta && QMetaObjectPrivate::get(rmeta)->revision >= 6 && rmeta->d.extradata) + ? reinterpret_cast<const QMetaObjectExtraData *>(rmeta->d.extradata)->static_metacall : 0; + QOrderedMutexLocker locker(signalSlotLock(sender), signalSlotLock(receiver)); @@ -3184,8 +3197,10 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index, const QObjectPrivate::Connection *c2 = (*connectionLists)[signal_index].first; + int method_index_absolute = method_index + method_offset; + while (c2) { - if (c2->receiver == receiver && c2->method == method_index) + if (c2->receiver == receiver && c2->method() == method_index_absolute) return false; c2 = c2->nextConnectionList; } @@ -3196,10 +3211,12 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index, QObjectPrivate::Connection *c = new QObjectPrivate::Connection; c->sender = s; c->receiver = r; - c->method = method_index; + c->method_relative = method_index; + c->method_offset = method_offset; c->connectionType = type; c->argumentTypes = types; c->nextConnectionList = 0; + c->callFunction = callFunction; QT_TRY { QObjectPrivate::get(s)->addConnection(signal_index, c); @@ -3260,7 +3277,7 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, while (c) { if (c->receiver && (receiver == 0 || (c->receiver == receiver - && (method_index < 0 || c->method == method_index)))) { + && (method_index < 0 || c->method() == method_index)))) { bool needToUnlock = false; QMutex *receiverMutex = 0; if (!receiver) { @@ -3434,12 +3451,11 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect args[0] = 0; // return value for (int n = 1; n < nargs; ++n) args[n] = QMetaType::construct((types[n] = c->argumentTypes[n-1]), argv[n]); - QCoreApplication::postEvent(c->receiver, new QMetaCallEvent(c->method, - sender, - signal, - nargs, - types, - args)); + QCoreApplication::postEvent(c->receiver, new QMetaCallEvent(c->method_offset, + c->method_relative, + c->callFunction, + sender, signal, nargs, + types, args)); } @@ -3478,7 +3494,7 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign argv ? argv : empty_argv); } - QThreadData *currentThreadData = QThreadData::current(); + Qt::HANDLE currentThreadId = QThread::currentThreadId(); QMutexLocker locker(signalSlotLock(sender)); QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists; @@ -3489,24 +3505,27 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign return; } ++connectionLists->inUse; - if (signal_index >= connectionLists->count()) { - signal_index = -2; //for "all signals"; - } + + + const QObjectPrivate::ConnectionList *list; + if (signal_index < connectionLists->count()) + list = &connectionLists->at(signal_index); + else + list = &connectionLists->allsignals; do { - QObjectPrivate::Connection *c = connectionLists->at(signal_index).first; + QObjectPrivate::Connection *c = list->first; if (!c) continue; // We need to check against last here to ensure that signals added // during the signal emission are not emitted in this emission. - QObjectPrivate::Connection *last = connectionLists->at(signal_index).last; + QObjectPrivate::Connection *last = list->last; do { if (!c->receiver) continue; QObject * const receiver = c->receiver; - const int method = c->method; - const bool receiverInSameThread = currentThreadData == receiver->d_func()->threadData; + const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId; // determine if this connection should be sent immediately or // put into the event queue @@ -3524,7 +3543,8 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign receiver->metaObject()->className(), receiver); } QSemaphore semaphore; - QCoreApplication::postEvent(receiver, new QMetaCallEvent(method, + QCoreApplication::postEvent(receiver, new QMetaCallEvent(c->method_offset, c->method_relative, + c->callFunction, sender, signal_absolute_index, 0, 0, argv ? argv : empty_argv, @@ -3534,6 +3554,7 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign continue; #endif } + QObjectPrivate::Sender currentSender; QObjectPrivate::Sender *previousSender = 0; if (receiverInSameThread) { @@ -3542,36 +3563,52 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign currentSender.ref = 1; previousSender = QObjectPrivate::setCurrentSender(receiver, ¤tSender); } - locker.unlock(); + const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction; + const int method_relative = c->method_relative; + if (callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) { + //we compare the vtable to make sure we are not in the destructor of the object. + locker.unlock(); + if (qt_signal_spy_callback_set.slot_begin_callback != 0) + qt_signal_spy_callback_set.slot_begin_callback(receiver, c->method(), argv ? argv : empty_argv); - if (qt_signal_spy_callback_set.slot_begin_callback != 0) { - qt_signal_spy_callback_set.slot_begin_callback(receiver, - method, - argv ? argv : empty_argv); - } + callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv); -#if defined(QT_NO_EXCEPTIONS) - metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); -#else - QT_TRY { - metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); - } QT_CATCH(...) { + if (qt_signal_spy_callback_set.slot_end_callback != 0) + qt_signal_spy_callback_set.slot_end_callback(receiver, c->method()); locker.relock(); - if (receiverInSameThread) - QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender); + } else { + const int method = method_relative + c->method_offset; + locker.unlock(); - --connectionLists->inUse; - Q_ASSERT(connectionLists->inUse >= 0); - if (connectionLists->orphaned && !connectionLists->inUse) - delete connectionLists; - QT_RETHROW; - } + if (qt_signal_spy_callback_set.slot_begin_callback != 0) { + qt_signal_spy_callback_set.slot_begin_callback(receiver, + method, + argv ? argv : empty_argv); + } + +#if defined(QT_NO_EXCEPTIONS) + metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); +#else + QT_TRY { + metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); + } QT_CATCH(...) { + locker.relock(); + if (receiverInSameThread) + QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender); + + --connectionLists->inUse; + Q_ASSERT(connectionLists->inUse >= 0); + if (connectionLists->orphaned && !connectionLists->inUse) + delete connectionLists; + QT_RETHROW; + } #endif - if (qt_signal_spy_callback_set.slot_end_callback != 0) - qt_signal_spy_callback_set.slot_end_callback(receiver, method); + if (qt_signal_spy_callback_set.slot_end_callback != 0) + qt_signal_spy_callback_set.slot_end_callback(receiver, method); - locker.relock(); + locker.relock(); + } if (receiverInSameThread) QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender); @@ -3582,7 +3619,9 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign if (connectionLists->orphaned) break; - } while (signal_index >= 0 && (signal_index = -1)); //start over for -1 (all signal) + } while (list != &connectionLists->allsignals && + //start over for all signals; + ((list = &connectionLists->allsignals), true)); --connectionLists->inUse; Q_ASSERT(connectionLists->inUse >= 0); @@ -3870,7 +3909,7 @@ void QObject::dumpObjectInfo() continue; } const QMetaObject *receiverMetaObject = c->receiver->metaObject(); - const QMetaMethod method = receiverMetaObject->method(c->method); + const QMetaMethod method = receiverMetaObject->method(c->method()); qDebug(" --> %s::%s %s", receiverMetaObject->className(), c->receiver->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver->objectName()), @@ -3887,7 +3926,7 @@ void QObject::dumpObjectInfo() if (d->senders) { for (QObjectPrivate::Connection *s = d->senders; s; s = s->next) { - const QMetaMethod slot = metaObject()->method(s->method); + const QMetaMethod slot = metaObject()->method(s->method()); qDebug(" <-- %s::%s %s", s->sender->metaObject()->className(), s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()), |