diff options
Diffstat (limited to 'src/corelib/kernel/qobject.cpp')
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 335 |
1 files changed, 208 insertions, 127 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 5247290..040efc9 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -41,6 +41,7 @@ #include "qobject.h" #include "qobject_p.h" +#include "qmetaobject_p.h" #include "qabstracteventdispatcher.h" #include "qcoreapplication.h" @@ -222,12 +223,42 @@ void QObjectPrivate::removePendingChildInsertedEvents(QObject *child) #endif +/*!\internal + For a given metaobject, compute the signal offset, and the method offset (including signals) +*/ +static void computeOffsets(const QMetaObject *metaobject, int *signalOffset, int *methodOffset) +{ + *signalOffset = *methodOffset = 0; + const QMetaObject *m = metaobject->d.superdata; + while (m) { + const QMetaObjectPrivate *d = QMetaObjectPrivate::get(m); + *methodOffset += d->methodCount; + *signalOffset += (d->revision >= 4) ? d->signalCount : d->methodCount; + /*Before Qt 4.6 (revision 4), the signalCount information was not generated by moc. + so for compatibility we consider all the method as slot for old moc output*/ + m = m->d.superdata; + } +} + +/*! \internal + This vector contains the all connections from an object. + + Each object may have one vector containing the lists of connections for a given signal. + The index in the vector correspond to the signal index. + The signal index is the one returned by QObjectPrivate::signalIndex (not QMetaObject::indexOfSignal). + Negative index means connections to all signals. + + This vector is protected by the object mutex (signalSlotMutexes()) + + Each Connection is also part of a 'senders' linked list. The mutex of the receiver must be locked when touching + the pointers of this linked list. +*/ class QObjectConnectionListVector : public QVector<QObjectPrivate::ConnectionList> { public: - bool orphaned; - bool dirty; - int inUse; + bool orphaned; //the QObject owner of this vector has been destroyed while the vector was inUse + bool dirty; //some Connection have been disconnected (their receiver is 0) but not removed from the list yet + int inUse; //number of functions that are currently accessing this object or its connections QObjectPrivate::ConnectionList allsignals; QObjectConnectionListVector() @@ -252,7 +283,7 @@ public: bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const { Q_Q(const QObject); - int signal_index = q->metaObject()->indexOfSignal(signal); + int signal_index = signalIndex(signal); if (signal_index < 0) return false; QMutexLocker locker(signalSlotLock(q)); @@ -276,7 +307,7 @@ QObjectList QObjectPrivate::receiverList(const char *signal) const { Q_Q(const QObject); QObjectList returnValue; - int signal_index = q->metaObject()->indexOfSignal(signal); + int signal_index = signalIndex(signal); if (signal_index < 0) return returnValue; QMutexLocker locker(signalSlotLock(q)); @@ -2465,6 +2496,7 @@ QObject *QObject::sender() const int QObject::receivers(const char *signal) const { + Q_D(const QObject); int receivers = 0; if (signal) { QByteArray signal_name = QMetaObject::normalizedSignature(signal); @@ -2474,8 +2506,7 @@ int QObject::receivers(const char *signal) const return 0; #endif signal++; // skip code - const QMetaObject *smeta = this->metaObject(); - int signal_index = smeta->indexOfSignal(signal); + int signal_index = d->signalIndex(signal); if (signal_index < 0) { #ifndef QT_NO_DEBUG err_method_notfound(this, signal-1, "receivers"); @@ -2599,19 +2630,26 @@ bool QObject::connect(const QObject *sender, const char *signal, const QMetaObject *smeta = sender->metaObject(); const char *signal_arg = signal; ++signal; //skip code - int signal_index = smeta->indexOfSignal(signal); + int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal); if (signal_index < 0) { // check for normalized signatures tmp_signal_name = QMetaObject::normalizedSignature(signal - 1); signal = tmp_signal_name.constData() + 1; - signal_index = smeta->indexOfSignal(signal); + smeta = sender->metaObject(); + signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal); + if (signal_index < 0) { err_method_notfound(sender, signal_arg, "connect"); err_info_about_objects("connect", sender, receiver); return false; } } + signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index); + int signalOffset, methodOffset; + computeOffsets(smeta, &signalOffset, &methodOffset); + int signal_absolute_index = signal_index + methodOffset; + signal_index += signalOffset; QByteArray tmp_method_name; int membcode = extract_code(method); @@ -2660,12 +2698,12 @@ bool QObject::connect(const QObject *sender, const char *signal, int *types = 0; if ((type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection) - && !(types = queuedConnectionTypes(smeta->method(signal_index).parameterTypes()))) + && !(types = queuedConnectionTypes(smeta->method(signal_absolute_index).parameterTypes()))) return false; #ifndef QT_NO_DEBUG { - QMetaMethod smethod = smeta->method(signal_index); + QMetaMethod smethod = smeta->method(signal_absolute_index); QMetaMethod rmethod = rmeta->method(method_index); if (warnCompat) { if(smethod.attributes() & QMetaMethod::Compatibility) { @@ -2678,7 +2716,7 @@ bool QObject::connect(const QObject *sender, const char *signal, } } #endif - if (!QMetaObject::connect(sender, signal_index, receiver, method_index, type, types)) + if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index, type, types)) return false; const_cast<QObject*>(sender)->connectNotify(signal - 1); return true; @@ -2822,14 +2860,18 @@ bool QObject::disconnect(const QObject *sender, const char *signal, do { int signal_index = -1; if (signal) { - signal_index = smeta->indexOfSignal(signal); - if (signal_index < smeta->methodOffset()) - continue; + signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal); + if (signal_index < 0) + break; + signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index); + int signalOffset, methodOffset; + computeOffsets(smeta, &signalOffset, &methodOffset); + signal_index += signalOffset; signal_found = true; } if (!method) { - res |= QMetaObject::disconnect(sender, signal_index, receiver, -1); + res |= QMetaObjectPrivate::disconnect(sender, signal_index, receiver, -1); } else { const QMetaObject *rmeta = receiver->metaObject(); do { @@ -2839,7 +2881,7 @@ bool QObject::disconnect(const QObject *sender, const char *signal, rmeta = rmeta->superClass(); if (method_index < 0) break; - res |= QMetaObject::disconnect(sender, signal_index, receiver, method_index); + res |= QMetaObjectPrivate::disconnect(sender, signal_index, receiver, method_index); method_found = true; } while ((rmeta = rmeta->superClass())); } @@ -2930,16 +2972,31 @@ void QObject::disconnectNotify(const char *) } /*!\internal + \a types is a 0-terminated vector of meta types for queued + connections. - \a types is a 0-terminated vector of meta types for queued - connections. - - if \a signal_index is -1, then we effectively connect *all* signals - from the sender to the receiver's slot -*/ + if \a signal_index is -1, then we effectively connect *all* signals + from the sender to the receiver's slot + */ bool QMetaObject::connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type, int *types) { + const QMetaObject *mo = sender->metaObject(); + while (mo && mo->methodOffset() > signal_index) + mo = mo->superClass(); + int signalOffset, methodOffset; + computeOffsets(mo, &signalOffset, &methodOffset); + signal_index = QMetaObjectPrivate::originalClone(mo, signal_index - methodOffset) + signalOffset; + return QMetaObjectPrivate::connect(sender, signal_index, + receiver, method_index, type, types); +} + +/*! \internal + Same as the QMetaObject::connect, but \a signal_index must be the result of QObjectPrivate::signalIndex + */ +bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index, + const QObject *receiver, int method_index, int type, int *types) +{ QObject *s = const_cast<QObject *>(sender); QObject *r = const_cast<QObject *>(receiver); @@ -2947,7 +3004,7 @@ bool QMetaObject::connect(const QObject *sender, int signal_index, signalSlotLock(receiver)); if (type & Qt::UniqueConnection) { - QObjectConnectionListVector *connectionLists = s->d_func()->connectionLists; + QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists; if (connectionLists && connectionLists->count() > signal_index) { const QObjectPrivate::Connection *c2 = (*connectionLists)[signal_index].first; @@ -2970,29 +3027,29 @@ bool QMetaObject::connect(const QObject *sender, int signal_index, c->nextConnectionList = 0; QT_TRY { - s->d_func()->addConnection(signal_index, c); + QObjectPrivate::get(s)->addConnection(signal_index, c); } QT_CATCH(...) { delete c; QT_RETHROW; } - c->prev = &r->d_func()->senders; + c->prev = &(QObjectPrivate::get(r)->senders); c->next = *c->prev; *c->prev = c; if (c->next) c->next->prev = &c->next; + QObjectPrivate *const sender_d = QObjectPrivate::get(s); if (signal_index < 0) { - for (uint i = 0; i < (sizeof sender->d_func()->connectedSignals - / sizeof sender->d_func()->connectedSignals[0] ); ++i) - sender->d_func()->connectedSignals[i] = ~0u; - } else if (signal_index < (int)sizeof sender->d_func()->connectedSignals * 8) { - uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0])); - sender->d_func()->connectedSignals[n] |= (1 << (signal_index - n * 8 - * sizeof sender->d_func()->connectedSignals[0])); + for (uint i = 0; i < (sizeof sender_d->connectedSignals + / sizeof sender_d->connectedSignals[0] ); ++i) + sender_d->connectedSignals[i] = ~0u; + } else if (signal_index < (int)sizeof sender_d->connectedSignals * 8) { + uint n = (signal_index / (8 * sizeof sender_d->connectedSignals[0])); + sender_d->connectedSignals[n] |= (1 << (signal_index - n * 8 + * sizeof sender_d->connectedSignals[0])); } - return true; } @@ -3002,6 +3059,22 @@ bool QMetaObject::connect(const QObject *sender, int signal_index, bool QMetaObject::disconnect(const QObject *sender, int signal_index, const QObject *receiver, int method_index) { + const QMetaObject *mo = sender->metaObject(); + while (mo && mo->methodOffset() > signal_index) + mo = mo->superClass(); + int signalOffset, methodOffset; + computeOffsets(mo, &signalOffset, &methodOffset); + signal_index = QMetaObjectPrivate::originalClone(mo, signal_index - methodOffset) + signalOffset; + return QMetaObjectPrivate::disconnect(sender, signal_index, + receiver, method_index); +} + +/*! \internal + Same as the QMetaObject::disconnect, but \a signal_index must be the result of QObjectPrivate::signalIndex + */ +bool QMetaObjectPrivate::disconnect(const QObject *sender, int signal_index, + const QObject *receiver, int method_index) +{ if (!sender) return false; @@ -3012,7 +3085,7 @@ bool QMetaObject::disconnect(const QObject *sender, int signal_index, QMutex *receiverMutex = receiver ? signalSlotLock(receiver) : 0; QOrderedMutexLocker locker(senderMutex, receiverMutex); - QObjectConnectionListVector *connectionLists = s->d_func()->connectionLists; + QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists; if (!connectionLists) return false; @@ -3123,23 +3196,26 @@ void QMetaObject::connectSlotsByName(QObject *o) int len = objName.length(); if (!len || qstrncmp(slot + 3, objName.data(), len) || slot[len+3] != '_') continue; - const QMetaObject *smo = co->metaObject(); - int sigIndex = smo->indexOfMethod(slot + len + 4); + int sigIndex = co->d_func()->signalIndex(slot + len + 4); if (sigIndex < 0) { // search for compatible signals + const QMetaObject *smo = co->metaObject(); int slotlen = qstrlen(slot + len + 4) - 1; for (int k = 0; k < co->metaObject()->methodCount(); ++k) { - if (smo->method(k).methodType() != QMetaMethod::Signal) + QMetaMethod method = smo->method(k); + if (method.methodType() != QMetaMethod::Signal) continue; - if (!qstrncmp(smo->method(k).signature(), slot + len + 4, slotlen)) { - sigIndex = k; + if (!qstrncmp(method.signature(), slot + len + 4, slotlen)) { + int signalOffset, methodOffset; + computeOffsets(method.enclosingMetaObject(), &signalOffset, &methodOffset); + sigIndex = k + - methodOffset + signalOffset; break; } } } if (sigIndex < 0) continue; - if (QMetaObject::connect(co, sigIndex, o, i)) { + if (QMetaObjectPrivate::connect(co, sigIndex, o, i)) { foundIt = true; break; } @@ -3211,15 +3287,43 @@ static void blocking_activate(QObject *sender, int signal, QObjectPrivate::Conne } /*!\internal + \obsolete. + Used to be called from QMetaObject::activate(QObject *, QMetaObject *, int, int, void **) before Qt 4.6 */ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv) { + Q_UNUSED(to_signal_index); + activate(sender, from_signal_index, argv); +} + +/*!\internal + */ +void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index, + void **argv) +{ + int signalOffset; + int methodOffset; + computeOffsets(m, &signalOffset, &methodOffset); + + int signal_index = signalOffset + local_signal_index; + if (signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8 + && !qt_signal_spy_callback_set.signal_begin_callback + && !qt_signal_spy_callback_set.signal_end_callback) { + uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0])); + uint m = 1 << (signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]); + if ((sender->d_func()->connectedSignals[n] & m) == 0) + // nothing connected to these signals, and no spy + return; + } + if (sender->d_func()->blockSig) return; + int signal_absolute_index = methodOffset + local_signal_index; + void *empty_argv[] = { 0 }; if (qt_signal_spy_callback_set.signal_begin_callback != 0) { - qt_signal_spy_callback_set.signal_begin_callback(sender, from_signal_index, + qt_signal_spy_callback_set.signal_begin_callback(sender, signal_absolute_index, argv ? argv : empty_argv); } @@ -3229,26 +3333,20 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists; if (!connectionLists) { if (qt_signal_spy_callback_set.signal_end_callback != 0) - qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index); + qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index); return; } ++connectionLists->inUse; + if (signal_index >= connectionLists->count()) { + signal_index = -2; //for "all signals"; + } - // emit signals in the following order: from_signal_index <= signals <= to_signal_index, signal < 0 - for (int signal = from_signal_index; - (signal >= from_signal_index && signal <= to_signal_index) || (signal == -2); - (signal == to_signal_index ? signal = -2 : ++signal)) - { - if (signal >= connectionLists->count()) { - signal = to_signal_index; - continue; - } - - QObjectPrivate::Connection *c = connectionLists->at(signal).first; + do { + QObjectPrivate::Connection *c = connectionLists->at(signal_index).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).last; + QObjectPrivate::Connection *last = connectionLists->at(signal_index).last; do { if (!c->receiver) @@ -3262,17 +3360,17 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal && (currentThreadData != sender->d_func()->threadData || receiver->d_func()->threadData != sender->d_func()->threadData)) || (c->connectionType == Qt::QueuedConnection)) { - queued_activate(sender, signal, c, argv); + queued_activate(sender, signal_absolute_index, c, argv); continue; } else if (c->connectionType == Qt::BlockingQueuedConnection) { - blocking_activate(sender, signal, c, argv); + blocking_activate(sender, signal_absolute_index, c, argv); continue; } const int method = c->method; QObjectPrivate::Sender currentSender; currentSender.sender = sender; - currentSender.signal = signal < 0 ? from_signal_index : signal; + currentSender.signal = signal_absolute_index; currentSender.ref = 1; QObjectPrivate::Sender *previousSender = 0; if (currentThreadData == receiver->d_func()->threadData) @@ -3316,7 +3414,7 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal if (connectionLists->orphaned) break; - } + } while (signal_index >= 0 && (signal_index = -1)); //start over for -1 (all signal) --connectionLists->inUse; Q_ASSERT(connectionLists->inUse >= 0); @@ -3330,82 +3428,50 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal locker.unlock(); if (qt_signal_spy_callback_set.signal_end_callback != 0) - qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index); -} + qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index); +} /*!\internal - */ + Obsolete. (signal_index comes from indexOfMethod()) +*/ void QMetaObject::activate(QObject *sender, int signal_index, void **argv) { - if (signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8 - && !qt_signal_spy_callback_set.signal_begin_callback - && !qt_signal_spy_callback_set.signal_end_callback) { - uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0])); - uint m = 1 << (signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]); - if ((sender->d_func()->connectedSignals[n] & m) == 0) - // nothing connected to these signals, and no spy - return; - } - activate(sender, signal_index, signal_index, argv); -} - -/*!\internal - */ -void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index, - void **argv) -{ - int signal_index = m->methodOffset() + local_signal_index; - if (signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8 - && !qt_signal_spy_callback_set.signal_begin_callback - && !qt_signal_spy_callback_set.signal_end_callback) { - uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0])); - uint m = 1 << (signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]); - if ((sender->d_func()->connectedSignals[n] & m) == 0) - // nothing connected to these signals, and no spy - return; - } - activate(sender, signal_index, signal_index, argv); + const QMetaObject *mo = sender->metaObject(); + while (mo && mo->methodOffset() > signal_index) + mo = mo->superClass(); + activate(sender, mo, signal_index - mo->methodOffset(), argv); } /*!\internal + Obsolete, called by moc generated code before Qt 4.6 for cloned signals + But since Qt 4.6, all clones are connected to their original */ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int from_local_signal_index, int to_local_signal_index, void **argv) { - Q_ASSERT(from_local_signal_index <= to_local_signal_index); - int offset = m->methodOffset(); - int from_signal_index = offset + from_local_signal_index; - int to_signal_index = offset + to_local_signal_index; + Q_UNUSED(to_local_signal_index); + Q_ASSERT(from_local_signal_index == QMetaObjectPrivate::originalClone(m, to_local_signal_index)); + activate(sender, m, from_local_signal_index, argv); +} - if (to_signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8 - && !qt_signal_spy_callback_set.signal_begin_callback - && !qt_signal_spy_callback_set.signal_end_callback) { +/*! \internal + Returns the signal index used in the internal connectionLists vector. - uint n = (from_signal_index / (8 * sizeof sender->d_func()->connectedSignals[0])); - uint m = 1 << (from_signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]); - uint nt = (to_signal_index / (8 * sizeof sender->d_func()->connectedSignals[0])); - uint mt = 1 << (to_signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]); - bool connected = false; - quint32 *connectedSignals = sender->d_func()->connectedSignals; - for (uint i = 0; !connected && i < (sizeof sender->d_func()->connectedSignals - / sizeof sender->d_func()->connectedSignals[0]); ++i) { - uint mask = 0; - if (i > n) - mask = ~0u; - else if (i == n) - mask = ~(m -1); - if (i > nt) - mask = 0; - else if (i == nt) - mask &= (mt << 1) - 1; - connected = connectedSignals[i] & mask; - } - if (!connected) - // nothing connected to these signals, and no spy - return; - } - activate(sender, from_signal_index, to_signal_index, argv); + It is different from QMetaObject::indexOfSignal(): indexOfSignal is the same as indexOfMethod + while QObjectPrivate::signalIndex is smaller because it doesn't give index to slots. +*/ +int QObjectPrivate::signalIndex(const char *signalName) const +{ + Q_Q(const QObject); + const QMetaObject *base = q->metaObject(); + int relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName); + if (relative_index < 0) + return relative_index; + relative_index = QMetaObjectPrivate::originalClone(base, relative_index); + int signalOffset, methodOffset; + computeOffsets(base, &signalOffset, &methodOffset); + return relative_index + signalOffset; } /*! \internal @@ -3413,14 +3479,16 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, Returns true if the signal with index \a signal_index from object \a sender is connected. Signals with indices above a certain range are always considered connected (see connectedSignals in QObjectPrivate). If a signal spy is installed, all signals are considered connected. + + \a signal_index must be the index returned by QObjectPrivate::signalIndex; */ -bool QMetaObject::isConnected(QObject *sender, int signal_index) { - if (signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8 +bool QObjectPrivate::isSignalConnected(int signal_index) const { + if (signal_index < (int)sizeof(connectedSignals) * 8 && !qt_signal_spy_callback_set.signal_begin_callback && !qt_signal_spy_callback_set.signal_end_callback) { - uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0])); - uint m = 1 << (signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]); - if ((sender->d_func()->connectedSignals[n] & m) == 0) + uint n = (signal_index / (8 * sizeof connectedSignals[0])); + uint m = 1 << (signal_index - n * 8 * sizeof connectedSignals[0]); + if ((connectedSignals[n] & m) == 0) // nothing connected to these signals, and no spy return false; } @@ -3626,8 +3694,21 @@ void QObject::dumpObjectInfo() qDebug(" SIGNALS OUT"); if (d->connectionLists) { + int offset = 0; + int offsetToNextMetaObject = 0; for (int signal_index = 0; signal_index < d->connectionLists->count(); ++signal_index) { - const QMetaMethod signal = metaObject()->method(signal_index); + if (signal_index >= offsetToNextMetaObject) { + const QMetaObject *mo = metaObject(); + int signalOffset, methodOffset; + computeOffsets(mo, &signalOffset, &methodOffset); + while (mo && signalOffset > signal_index) { + mo = mo->superClass(); + offsetToNextMetaObject = signalOffset; + computeOffsets(mo, &signalOffset, &methodOffset); + } + offset = offset - signalOffset + methodOffset; + } + const QMetaMethod signal = metaObject()->method(signal_index + offset); qDebug(" signal: %s", signal.signature()); // receivers |