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 + -
显示快捷键?