📄 qdbusintegrator.cpp
字号:
}#if USE_OUTSIDE_DISPATCH dbus_connection_add_filter_outside(connection, qDBusSignalFilter, qDBusSignalFilterOutside, this, 0);#else dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0);#endif //qDebug("base service: %s", service); // schedule a dispatch: QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);}extern "C"{static void qDBusResultReceived(DBusPendingCall *pending, void *user_data){ QDBusConnectionPrivate::messageResultReceived(pending, user_data);}}void QDBusConnectionPrivate::messageResultReceived(DBusPendingCall *pending, void *user_data){ QDBusPendingCall *call = reinterpret_cast<QDBusPendingCall *>(user_data); QDBusConnectionPrivate *connection = const_cast<QDBusConnectionPrivate *>(call->connection); Q_ASSERT(call->pending == pending); if (!call->receiver.isNull() && call->methodIdx != -1) { DBusMessage *reply = dbus_pending_call_steal_reply(pending); // Deliver the return values of a remote function call. // // There is only one connection and it is specified by idx // The slot must have the same parameter types that the message does // The slot may have less parameters than the message // The slot may optionally have one final parameter that is QDBusMessage // The slot receives read-only copies of the message (i.e., pass by value or by const-ref) QDBusMessage msg = QDBusMessagePrivate::fromDBusMessage(reply); qDBusDebug() << "got message: " << msg; CallDeliveryEvent *e = prepareReply(call->receiver, call->methodIdx, call->metaTypes, msg); if (e) connection->postCallDeliveryEvent(e); else qDBusDebug() << "Deliver failed!"; } dbus_pending_call_unref(pending); delete call;}int QDBusConnectionPrivate::send(const QDBusMessage& message) const{ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message); if (!msg) { if (message.type() == QDBusMessage::MethodCallMessage) qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\"", qPrintable(message.service()), qPrintable(message.path()), qPrintable(message.interface()), qPrintable(message.member())); else if (message.type() == QDBusMessage::SignalMessage) qWarning("QDBusConnection: error: could not send signal path \"%s\" interface \"%s\" member \"%s\"", qPrintable(message.path()), qPrintable(message.interface()), qPrintable(message.member())); else qWarning("QDBusConnection: error: could not send %s message to service \"%s\"", message.type() == QDBusMessage::ReplyMessage ? "reply" : message.type() == QDBusMessage::ErrorMessage ? "error" : "invalid", qPrintable(message.service())); return 0; } dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything qDBusDebug() << "sending message:" << message; bool isOk = dbus_connection_send(connection, msg, 0); int serial = 0; if (isOk) serial = dbus_message_get_serial(msg); dbus_message_unref(msg); return serial;}QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message, int sendMode, int timeout){ // special case for synchronous local calls const bool localBlockingCall = ((sendMode == QDBus::BlockWithGui || sendMode == QDBus::Block) && isServiceRegisteredByThread(message.service())); if (!QCoreApplication::instance() || sendMode == QDBus::Block || localBlockingCall) { DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message); if (!msg) { qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\"", qPrintable(message.service()), qPrintable(message.path()), qPrintable(message.interface()), qPrintable(message.member())); return QDBusMessage(); } if (localBlockingCall) { QDBusMessage messageWithSignature = QDBusMessagePrivate::updateSignature(message, msg); QDBusMessagePrivate::setLocal(&messageWithSignature, true); bool handled = false; int type = dbus_message_get_type(msg); if (type == DBUS_MESSAGE_TYPE_SIGNAL) handled = handleSignal(messageWithSignature); else if (type == DBUS_MESSAGE_TYPE_METHOD_CALL) handled = handleObjectCall(messageWithSignature); if (!handled) handled = activateInternalFilters(&rootNode, message); if (handled) { return messageWithSignature; } else { return QDBusMessage::createError( QString::fromLocal8Bit("InternalError"), QString::fromLocal8Bit("the sender and receiver are in the same thread")); } } else { QDBusMessage amsg; qDBusDebug() << "sending message:" << message; DBusMessage *reply = dbus_connection_send_with_reply_and_block(connection, msg, timeout, &error); handleError(); dbus_message_unref(msg); if (lastError.isValid()) return QDBusMessagePrivate::fromError(lastError); amsg = QDBusMessagePrivate::fromDBusMessage(reply); dbus_message_unref(reply); qDBusDebug() << "got message:" << amsg; if (dbus_connection_get_dispatch_status(connection) == DBUS_DISPATCH_DATA_REMAINS) QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection); return amsg; } } else { // use the event loop QDBusReplyWaiter waiter; if (sendWithReplyAsync(message, &waiter, SLOT(reply(QDBusMessage)), timeout) > 0) { // enter the event loop and wait for a reply waiter.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents); lastError = waiter.replyMsg; // set or clear error return waiter.replyMsg; } return QDBusMessage(); }}int QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver, const char *method, int timeout){ if (!receiver || !method || !*method) { // would not be able to deliver a reply qWarning("QDBusConnection::sendWithReplyAsync: error: cannot deliver a reply to %s::%s (%s)", receiver ? receiver->metaObject()->className() : "(null)", method ? method + 1 : "(null)", receiver ? qPrintable(receiver->objectName()) : "no name"); return send(message); } int slotIdx = -1; QList<int> metaTypes; slotIdx = findSlot(receiver, method + 1, metaTypes); if (slotIdx == -1) { QByteArray normalizedName = QMetaObject::normalizedSignature(method + 1); slotIdx = findSlot(receiver, normalizedName, metaTypes); } if (slotIdx == -1) { // would not be able to deliver a reply qWarning("QDBusConnection::sendWithReplyAsync: error: cannot deliver a reply to %s::%s (%s)", receiver->metaObject()->className(), method + 1, qPrintable(receiver->objectName())); return send(message); } DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message); if (!msg) { qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\"", qPrintable(message.service()), qPrintable(message.path()), qPrintable(message.interface()), qPrintable(message.member())); return 0; } qDBusDebug() << "sending message:" << message; DBusPendingCall *pending = 0; if (dbus_connection_send_with_reply(connection, msg, &pending, timeout)) { int serial = dbus_message_get_serial(msg); dbus_message_unref(msg); QDBusPendingCall *pcall = new QDBusPendingCall; pcall->receiver = receiver; pcall->metaTypes = metaTypes; pcall->methodIdx = slotIdx; pcall->connection = this; pcall->pending = pending; dbus_pending_call_set_notify(pending, qDBusResultReceived, pcall, 0); return serial; } dbus_message_unref(msg); return 0;}void QDBusConnectionPrivate::connectSignal(const QString &key, const SignalHook &hook){ signalHooks.insertMulti(key, hook); connect(hook.obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)));}void QDBusConnectionPrivate::disconnectSignal(const QString &key, const SignalHook &hook){ hook.obj->disconnect(SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); signalHooks.remove(key);}void QDBusConnectionPrivate::registerObject(const ObjectTreeNode *node){ connect(node->obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*))); if (node->flags & (QDBusConnection::ExportAdaptors | QDBusConnection::ExportScriptableSignals | QDBusConnection::ExportNonScriptableSignals)) { QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(node->obj); if (node->flags & (QDBusConnection::ExportScriptableSignals | QDBusConnection::ExportNonScriptableSignals)) { connector->disconnectAllSignals(node->obj); connector->connectAllSignals(node->obj); } // disconnect and reconnect to avoid duplicates connector->disconnect(SIGNAL(relaySignal(QObject*,const QMetaObject*,int,QVariantList)), this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList))); connect(connector, SIGNAL(relaySignal(QObject*,const QMetaObject*,int,QVariantList)), this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList))); }}void QDBusConnectionPrivate::connectRelay(const QString &service, const QString &path, const QString &interface, QDBusAbstractInterface *receiver, const char *signal){ // this function is called by QDBusAbstractInterface when one of its signals is connected // we set up a relay from D-Bus into it SignalHook hook; QString key; QString owner = getNameOwner(service); if (!prepareHook(hook, key, service, owner, path, interface, QString(), receiver, signal, QDBusAbstractInterface::staticMetaObject.methodCount(), true)) return; // don't connect // add it to our list: QWriteLocker locker(&lock); SignalHookHash::ConstIterator it = signalHooks.find(key); SignalHookHash::ConstIterator end = signalHooks.constEnd(); for ( ; it != end && it.key() == key; ++it) { const SignalHook &entry = it.value(); if (entry.service == hook.service && entry.owner == hook.owner && entry.path == hook.path && entry.signature == hook.signature && entry.obj == hook.obj && entry.midx == hook.midx) return; // already there, no need to re-add } connectSignal(key, hook);}void QDBusConnectionPrivate::disconnectRelay(const QString &service, const QString &path, const QString &interface, QDBusAbstractInterface *receiver, const char *signal){ // this function is called by QDBusAbstractInterface when one of its signals is disconnected // we remove relay from D-Bus into it SignalHook hook; QString key; QString owner = getNameOwner(service); if (!prepareHook(hook, key, service, owner, path, interface, QString(), receiver, signal, QDBusAbstractInterface::staticMetaObject.methodCount(), true)) return; // don't connect // remove it from our list: QWriteLocker locker(&lock); SignalHookHash::Iterator it = signalHooks.find(key); SignalHookHash::Iterator end = signalHooks.end(); for ( ; it != end && it.key() == key; ++it) { const SignalHook &entry = it.value(); if (entry.service == hook.service && entry.owner == hook.owner && entry.path == hook.path && entry.signature == hook.signature && entry.obj == hook.obj && entry.midx == hook.midx) { // found it signalHooks.erase(it); return; } } qWarning("QDBusConnectionPrivate::disconnectRelay called for a signal that was not found");}QString QDBusConnectionPrivate::getNameOwner(const QString& serviceName){ if (QDBusUtil::isValidUniqueConnectionName(serviceName)) return serviceName; if (!connection || !QDBusUtil::isValidBusName(serviceName)) return QString(); QDBusMessage msg = QDBusMessage::createMethodCall(QLatin1String(DBUS_SERVICE_DBUS), QLatin1String(DBUS_PATH_DBUS), QLatin1String(DBUS_INTERFACE_DBUS), QLatin1String("GetNameOwner")); msg << serviceName; QDBusMessage reply = sendWithReply(msg, QDBus::Block); if (!lastError.isValid() && reply.type() == QDBusMessage::ReplyMessage) return reply.arguments().at(0).toString(); return QString();}struct qdbus_Introspect{ QString xml; inline void operator()(QDBusConnectionPrivate::ObjectTreeNode *node) { xml = qDBusIntrospectObject(node); }};QDBusMetaObject *QDBusConnectionPrivate::findMetaObject(const QString &service, const QString &path, const QString &interface){ // service must be a unique connection name if (!interface.isEmpty()) { QReadLocker locker(&lock); QDBusMetaObject *mo = cachedMetaObjects.value(interface, 0); if (mo) return mo; } if (service == QLatin1String(dbus_bus_get_unique_name(connection))) { // it's one of our own QWriteLocker locker(&lock); QDBusMetaObject *mo = 0; if (!interface.isEmpty()) mo = cachedMetaObjects.value(interface, 0); if (mo) // maybe it got created when we switched from read to write lock return mo; qdbus_Introspect apply; if (!applyForObject(&rootNode, path, apply)) { lastError = QDBusError(QDBusError::InvalidArgs, QString(QLatin1String("No object at %1")).arg(path)); return 0; // no object at path } // release the lock and return return QDBusMetaObject::createMetaObject(interface, apply.xml, cachedMetaObjects, lastError); } // not local: introspect the target object: QDBusMessage msg = QDBusMessage::createMethodCall(service, path, QLatin1String(DBUS_INTERFACE_INTROSPECTABLE), QLatin1String("Introspect")); QDBusMessage reply = sendWithReply(msg, QDBus::Block); // it doesn't exist yet, we have to create it QWriteLocker locker(&lock); QDBusMetaObject *mo = 0; if (!interface.isEmpty()) mo = cachedMetaObjects.value(interface, 0); if (mo) // maybe it got created when we switched from read to write lock return mo; QString xml; if (reply.type() == QDBusMessage::ReplyMessage) // fetch the XML description xml = reply.arguments().at(0).toString(); else { lastError = reply; if (reply.type() != QDBusMessage::ErrorMessage || lastError.type() != QDBusError::UnknownMethod) return 0; // error } // release the lock and return return QDBusMetaObject::createMetaObject(interface, xml, cachedMetaObjects, lastError);}void QDBusConnectionPrivate::registerService(const QString &serviceName){ qDBusServicesRegisteredByThread()->append(serviceName);}void QDBusConnectionPrivate::unregisterService(const QString &serviceName){ qDBusServicesRegisteredByThread()->removeAll(serviceName);}bool QDBusConnectionPrivate::isServiceRegisteredByThread(const QString &serviceName) const{ return (serviceName == baseService() || qDBusServicesRegisteredByThread()->contains(serviceName));}QString QDBusConnectionPrivate::baseService() const{ return connection ? QString::fromUtf8(dbus_bus_get_unique_name(connection)) : QString();}void QDBusReplyWaiter::reply(const QDBusMessage &msg){ replyMsg = msg; quit();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -