qdbusintegrator.cpp

来自「奇趣公司比较新的qt/emd版本」· C++ 代码 · 共 1,726 行 · 第 1/5 页

CPP
1,726
字号
    Q_ASSERT_X(QThread::currentThread() == object->thread(),               "QDBusConnection: internal threading error",               "function called for an object that is in another thread!!");    QDBusSlotCache slotCache =        qvariant_cast<QDBusSlotCache>(object->property(cachePropertyName));    QString cacheKey = msg.member(), signature = msg.signature();    if (!signature.isEmpty()) {        cacheKey.reserve(cacheKey.length() + 1 + signature.length());        cacheKey += QLatin1Char('.');        cacheKey += signature;    }    QDBusSlotCache::Hash::ConstIterator cacheIt = slotCache.hash.constFind(cacheKey);    while (cacheIt != slotCache.hash.constEnd() && cacheIt->flags != flags &&           cacheIt.key() == cacheKey)        ++cacheIt;    if (cacheIt == slotCache.hash.constEnd() || cacheIt.key() != cacheKey)    {        // not cached, analyse the meta object        const QMetaObject *mo = object->metaObject();        QByteArray memberName = msg.member().toUtf8();        // find a slot that matches according to the rules above        QDBusSlotCache::Data slotData;        slotData.flags = flags;        slotData.slotIdx = ::findSlot(mo, memberName, flags, msg.signature(), slotData.metaTypes);        if (slotData.slotIdx == -1) {            // ### this is where we want to add the connection as an arg too            // try with no parameters, but with a QDBusMessage            slotData.slotIdx = ::findSlot(mo, memberName, flags, QString(), slotData.metaTypes);            if (slotData.metaTypes.count() != 2 ||                slotData.metaTypes.at(1) != QDBusMetaTypeId::message) {                // not found                // save the negative lookup                slotData.slotIdx = -1;                slotData.metaTypes.clear();                slotCache.hash.insert(cacheKey, slotData);                object->setProperty(cachePropertyName, qVariantFromValue(slotCache));                return false;            }        }        // save to the cache        slotCache.hash.insert(cacheKey, slotData);        object->setProperty(cachePropertyName, qVariantFromValue(slotCache));        // found the slot to be called        deliverCall(object, flags, msg, slotData.metaTypes, slotData.slotIdx);        return true;    } else if (cacheIt->slotIdx == -1) {        // negative cache        return false;    } else {        // use the cache        deliverCall(object, flags, msg, cacheIt->metaTypes, cacheIt->slotIdx);        return true;    }}void QDBusConnectionPrivate::deliverCall(QObject *object, int /*flags*/, const QDBusMessage &msg,                                         const QList<int> &metaTypes, int slotIdx){    Q_ASSERT_X(!object || QThread::currentThread() == object->thread(),               "QDBusConnection: internal threading error",               "function called for an object that is in another thread!!");    QVarLengthArray<void *, 10> params;    params.reserve(metaTypes.count());    QVariantList auxParameters;    // let's create the parameter list    // first one is the return type -- add it below    params.append(0);    // add the input parameters    int i;    int pCount = qMin(msg.arguments().count(), metaTypes.count() - 1);    for (i = 1; i <= pCount; ++i) {        int id = metaTypes[i];        if (id == QDBusMetaTypeId::message)            break;        const QVariant &arg = msg.arguments().at(i - 1);        if (arg.userType() == id)            // no conversion needed            params.append(const_cast<void *>(arg.constData()));        else if (arg.userType() == qMetaTypeId<QDBusArgument>()) {            // convert to what the function expects            void *null = 0;            auxParameters.append(QVariant(id, null));            const QDBusArgument &in =                *reinterpret_cast<const QDBusArgument *>(arg.constData());            QVariant &out = auxParameters[auxParameters.count() - 1];            if (!QDBusMetaType::demarshall(in, out.userType(), out.data()))                qFatal("Internal error: demarshalling function for type '%s' (%d) failed!",                       out.typeName(), out.userType());            params.append(const_cast<void *>(out.constData()));        } else {            qFatal("Internal error: got invalid meta type %d (%s) "                   "when trying to convert to meta type %d (%s)",                   arg.userType(), QMetaType::typeName(arg.userType()),                   id, QMetaType::typeName(id));        }    }    bool takesMessage = false;    if (metaTypes.count() > i && metaTypes[i] == QDBusMetaTypeId::message) {        params.append(const_cast<void*>(static_cast<const void*>(&msg)));        takesMessage = true;        ++i;    }    // output arguments    QVariantList outputArgs;    void *null = 0;    if (metaTypes[0] != QMetaType::Void) {        QVariant arg(metaTypes[0], null);        outputArgs.append( arg );        params[0] = const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData());    }    for ( ; i < metaTypes.count(); ++i) {        QVariant arg(metaTypes[i], null);        outputArgs.append( arg );        params.append(const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData()));    }    // make call:    bool fail;    if (!object) {        fail = true;    } else {        // FIXME: save the old sender!        QDBusContextPrivate context(QDBusConnection(this), msg);        QDBusContextPrivate *old = QDBusContextPrivate::set(object, &context);        QDBusConnectionPrivate::setSender(this);        QPointer<QObject> ptr = object;        fail = object->qt_metacall(QMetaObject::InvokeMetaMethod,                                   slotIdx, params.data()) >= 0;        QDBusConnectionPrivate::setSender(0);	// the object might be deleted in the slot	if (!ptr.isNull())	    QDBusContextPrivate::set(object, old);    }    // do we create a reply? Only if the caller is waiting for a reply and one hasn't been sent    // yet.    if (!msg.isReplyRequired() && !msg.isDelayedReply()) {        if (!fail) {            // normal reply            qDBusDebug() << QThread::currentThread() << "Automatically sending reply:" << outputArgs;            send(msg.createReply(outputArgs));        } else {            // generate internal error            qWarning("Internal error: Failed to deliver message");            send(msg.createErrorReply(QDBusError::InternalError,                                      QLatin1String("Failed to deliver message")));        }    }    return;}QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *p)    : QObject(p), ref(1), mode(InvalidMode), connection(0), server(0), busService(0),      rootNode(QString(QLatin1Char('/'))){    extern bool qDBusInitThreads();    static const bool threads = qDBusInitThreads();    static const bool debugging = !qgetenv("QDBUS_DEBUG").isEmpty();    Q_UNUSED(threads)    ::isDebugging = debugging;    QDBusMetaTypeId::init();    rootNode.flags = 0;    connect(this, SIGNAL(serviceOwnerChanged(QString,QString,QString)),            this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));}QDBusConnectionPrivate::~QDBusConnectionPrivate(){    if (thread() && thread() != QThread::currentThread())        qWarning("QDBusConnection(name=\"%s\")'s last reference in not in its creation thread! "                 "Timer and socket errors will follow and the program will probably crash",                 qPrintable(name));    closeConnection();    rootNode.children.clear();  // free resources    qDeleteAll(cachedMetaObjects);    if (server)        dbus_server_unref(server);    if (connection)        dbus_connection_unref(connection);    connection = 0;    server = 0;}void QDBusConnectionPrivate::deleteYourself(){    if (thread() && thread() != QThread::currentThread()) {        // last reference dropped while not in the correct thread        // ask the correct thread to delete        // note: since we're posting an event to another thread, we        // must consider deleteLater() to take effect immediately        deleteLater();    } else {        delete this;    }}void QDBusConnectionPrivate::closeConnection(){    QDBusWriteLocker locker(CloseConnectionAction, this);    ConnectionMode oldMode = mode;    mode = InvalidMode; // prevent reentrancy    baseService.clear();    if (oldMode == ServerMode) {        if (server) {            dbus_server_disconnect(server);        }    } else if (oldMode == ClientMode) {        if (connection) {            dbus_connection_close(connection);            // send the "close" message            while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS)                ;        }    }}void QDBusConnectionPrivate::checkThread(){    if (!thread()) {        if (QCoreApplication::instance())            moveToThread(QCoreApplication::instance()->thread());        else            qWarning("The thread that had QDBusConnection('%s') has died and there is no main thread",                     qPrintable(name));    }}bool QDBusConnectionPrivate::handleError(const QDBusErrorInternal &error){    if (!error)        return false;           // no error    //lock.lockForWrite();    lastError = error;    //lock.unlock();    return true;}void QDBusConnectionPrivate::timerEvent(QTimerEvent *e){    DBusTimeout *timeout = timeouts.value(e->timerId(), 0);    dbus_timeout_handle(timeout);}void QDBusConnectionPrivate::customEvent(QEvent *e){    Q_ASSERT(e->type() == QEvent::User);    QDBusConnectionCallbackEvent *ev = static_cast<QDBusConnectionCallbackEvent *>(e);    QDBusLockerBase::reportThreadAction(int(AddTimeoutAction) + int(ev->subtype),                                        QDBusLockerBase::BeforeDeliver, this);    switch (ev->subtype)    {    case QDBusConnectionCallbackEvent::AddTimeout:        qDBusRealAddTimeout(this, ev->timeout, ev->extra);        break;    case QDBusConnectionCallbackEvent::RemoveTimeout:        qDBusRealRemoveTimeout(this, ev->timeout);        break;    case QDBusConnectionCallbackEvent::AddWatch:        qDBusRealAddWatch(this, ev->watch, ev->extra, ev->fd);        break;    case QDBusConnectionCallbackEvent::RemoveWatch:        qDBusRealRemoveWatch(this, ev->watch, ev->fd);        break;    case QDBusConnectionCallbackEvent::ToggleWatch:        qDBusRealToggleWatch(this, ev->watch, ev->fd);        break;    }    QDBusLockerBase::reportThreadAction(int(AddTimeoutAction) + int(ev->subtype),                                        QDBusLockerBase::AfterDeliver, this);}void QDBusConnectionPrivate::doDispatch(){    QDBusDispatchLocker locker(DoDispatchAction, this);    if (mode == ClientMode)        while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS);}void QDBusConnectionPrivate::socketRead(int fd){    QHashIterator<int, QDBusConnectionPrivate::Watcher> it(watchers);    while (it.hasNext()) {        it.next();        if (it.key() == fd && it.value().read && it.value().read->isEnabled()) {            if (!dbus_watch_handle(it.value().watch, DBUS_WATCH_READABLE))                qDebug("OUT OF MEM");        }    }    doDispatch();}void QDBusConnectionPrivate::socketWrite(int fd){    QHashIterator<int, QDBusConnectionPrivate::Watcher> it(watchers);    while (it.hasNext()) {        it.next();        if (it.key() == fd && it.value().write && it.value().write->isEnabled()) {            if (!dbus_watch_handle(it.value().watch, DBUS_WATCH_WRITABLE))                qDebug("OUT OF MEM");        }    }}void QDBusConnectionPrivate::objectDestroyed(QObject *obj){    QDBusWriteLocker locker(ObjectDestroyedAction, this);    huntAndDestroy(obj, rootNode);    SignalHookHash::iterator sit = signalHooks.begin();    while (sit != signalHooks.end()) {        if (static_cast<QObject *>(sit.value().obj) == obj)            sit = disconnectSignal(sit);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?