📄 qdbusintegrator.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.**** This file is part of the tools applications of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://www.trolltech.com/products/qt/opensource.html**** If you are unsure which license is appropriate for your use, please** review the following information:** http://www.trolltech.com/products/qt/licensing.html or contact the** sales department at sales@trolltech.com.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include <qcoreapplication.h>#include <qcoreevent.h>#include <qdebug.h>#include <qmetaobject.h>#include <qobject.h>#include <qsocketnotifier.h>#include <qstringlist.h>#include <qtimer.h>#include "qdbusargument.h"#include "qdbusconnection_p.h"#include "qdbusinterface_p.h"#include "qdbusmessage.h"#include "qdbusmetatype.h"#include "qdbusmetatype_p.h"#include "qdbusabstractadaptor.h"#include "qdbusabstractadaptor_p.h"#include "qdbusutil_p.h"#include "qdbusmessage_p.h"static bool isDebugging;#define qDBusDebug if (!::isDebugging); else qDebug#ifndef USE_OUTSIDE_DISPATCH# define USE_OUTSIDE_DISPATCH 0#endiftypedef void (*QDBusSpyHook)(const QDBusMessage&);typedef QVarLengthArray<QDBusSpyHook, 4> QDBusSpyHookList;Q_GLOBAL_STATIC(QDBusSpyHookList, qDBusSpyHookList)Q_GLOBAL_STATIC(QStringList, qDBusServicesRegisteredByThread)struct QDBusPendingCall{ QPointer<QObject> receiver; QList<int> metaTypes; int methodIdx; DBusPendingCall *pending; const QDBusConnectionPrivate *connection;};class CallDeliveryEvent: public QEvent{public: CallDeliveryEvent() : QEvent(QEvent::User), object(0), flags(0), slotIdx(-1) { } const QDBusConnectionPrivate *conn; QPointer<QObject> object; QDBusMessage message; QList<int> metaTypes; int flags; int slotIdx;};static dbus_bool_t qDBusAddTimeout(DBusTimeout *timeout, void *data){ Q_ASSERT(timeout); Q_ASSERT(data); // qDebug("addTimeout %d", dbus_timeout_get_interval(timeout)); QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data); if (!dbus_timeout_get_enabled(timeout)) return true; if (!QCoreApplication::instance()) { d->pendingTimeouts.append(timeout); return true; } int timerId = d->startTimer(dbus_timeout_get_interval(timeout)); if (!timerId) return false; d->timeouts[timerId] = timeout; return true;}static void qDBusRemoveTimeout(DBusTimeout *timeout, void *data){ Q_ASSERT(timeout); Q_ASSERT(data); // qDebug("removeTimeout"); QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data); d->pendingTimeouts.removeAll(timeout); QDBusConnectionPrivate::TimeoutHash::iterator it = d->timeouts.begin(); while (it != d->timeouts.end()) { if (it.value() == timeout) { d->killTimer(it.key()); it = d->timeouts.erase(it); } else { ++it; } }}static void qDBusToggleTimeout(DBusTimeout *timeout, void *data){ Q_ASSERT(timeout); Q_ASSERT(data); //qDebug("ToggleTimeout"); qDBusRemoveTimeout(timeout, data); qDBusAddTimeout(timeout, data);}static dbus_bool_t qDBusAddWatch(DBusWatch *watch, void *data){ Q_ASSERT(watch); Q_ASSERT(data); QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data); int flags = dbus_watch_get_flags(watch); int fd = dbus_watch_get_fd(watch); QDBusConnectionPrivate::Watcher watcher; if (flags & DBUS_WATCH_READABLE) { //qDebug("addReadWatch %d", fd); watcher.watch = watch; if (QCoreApplication::instance()) { watcher.read = new QSocketNotifier(fd, QSocketNotifier::Read, d); watcher.read->setEnabled(dbus_watch_get_enabled(watch)); d->connect(watcher.read, SIGNAL(activated(int)), SLOT(socketRead(int))); } } if (flags & DBUS_WATCH_WRITABLE) { //qDebug("addWriteWatch %d", fd); watcher.watch = watch; if (QCoreApplication::instance()) { watcher.write = new QSocketNotifier(fd, QSocketNotifier::Write, d); watcher.write->setEnabled(dbus_watch_get_enabled(watch)); d->connect(watcher.write, SIGNAL(activated(int)), SLOT(socketWrite(int))); } } d->watchers.insertMulti(fd, watcher); return true;}static void qDBusRemoveWatch(DBusWatch *watch, void *data){ Q_ASSERT(watch); Q_ASSERT(data); //qDebug("remove watch"); QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data); int fd = dbus_watch_get_fd(watch); QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd); while (i != d->watchers.end() && i.key() == fd) { if (i.value().watch == watch) { delete i.value().read; delete i.value().write; d->watchers.erase(i); return; } ++i; }}static void qDBusToggleWatch(DBusWatch *watch, void *data){ Q_ASSERT(watch); Q_ASSERT(data); QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data); int fd = dbus_watch_get_fd(watch); QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd); while (i != d->watchers.end() && i.key() == fd) { if (i.value().watch == watch) { bool enabled = dbus_watch_get_enabled(watch); int flags = dbus_watch_get_flags(watch); //qDebug("toggle watch %d to %d (write: %d, read: %d)", dbus_watch_get_fd(watch), enabled, flags & DBUS_WATCH_WRITABLE, flags & DBUS_WATCH_READABLE); if (flags & DBUS_WATCH_READABLE && i.value().read) i.value().read->setEnabled(enabled); if (flags & DBUS_WATCH_WRITABLE && i.value().write) i.value().write->setEnabled(enabled); return; } ++i; }}static void qDBusNewConnection(DBusServer *server, DBusConnection *c, void *data){ Q_ASSERT(data); Q_ASSERT(server); Q_ASSERT(c); Q_UNUSED(data); Q_UNUSED(server); Q_UNUSED(c); qDebug("SERVER: GOT A NEW CONNECTION"); // TODO}extern QDBUS_EXPORT void qDBusAddSpyHook(QDBusSpyHook);void qDBusAddSpyHook(QDBusSpyHook hook){ qDBusSpyHookList()->append(hook);}#if USE_OUTSIDE_DISPATCH# define HANDLED DBUS_HANDLER_RESULT_HANDLED_OUTSIDE_DISPATCHstatic DBusHandlerResult qDBusSignalFilterOutside(DBusConnection *connection, DBusMessage *message, void *data){ Q_ASSERT(data); Q_UNUSED(connection); Q_UNUSED(message); QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data); if (d->mode == QDBusConnectionPrivate::InvalidMode) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; // internal error, actually CallDeliveryEvent *e = d->postedCallDeliveryEvent(); d->deliverCall(*e); delete e; return DBUS_HANDLER_RESULT_HANDLED;}#else# define HANDLED DBUS_HANDLER_RESULT_HANDLED#endifextern "C" {static DBusHandlerResultqDBusSignalFilter(DBusConnection *connection, DBusMessage *message, void *data){ return QDBusConnectionPrivate::messageFilter(connection, message, data);}}DBusHandlerResult QDBusConnectionPrivate::messageFilter(DBusConnection *connection, DBusMessage *message, void *data){ Q_ASSERT(data); Q_UNUSED(connection); QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data); if (d->mode == QDBusConnectionPrivate::InvalidMode) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(message); qDBusDebug() << "got message:" << amsg; const QDBusSpyHookList *list = qDBusSpyHookList(); for (int i = 0; i < list->size(); ++i) { qDBusDebug() << "calling the message spy hook"; (*(*list)[i])(amsg); } bool handled = false; int msgType = dbus_message_get_type(message); if (msgType == DBUS_MESSAGE_TYPE_SIGNAL) { handled = d->handleSignal(amsg); } else if (msgType == DBUS_MESSAGE_TYPE_METHOD_CALL) { handled = d->handleObjectCall(amsg); } return handled ? HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED;}static void huntAndDestroy(QObject *needle, QDBusConnectionPrivate::ObjectTreeNode *haystack){ QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it = haystack->children.constBegin(); QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator end = haystack->children.constEnd(); for ( ; it != end; ++it) huntAndDestroy(needle, it->node); if (needle == haystack->obj) { haystack->obj = 0; haystack->flags = 0; }}static void huntAndEmit(DBusConnection *connection, DBusMessage *msg, QObject *needle, QDBusConnectionPrivate::ObjectTreeNode *haystack, bool isScriptable, bool isAdaptor, const QString &path = QString()){ QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it = haystack->children.constBegin(); QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator end = haystack->children.constEnd(); for ( ; it != end; ++it) huntAndEmit(connection, msg, needle, it->node, isScriptable, isAdaptor, path + QLatin1String("/") + it->name); if (needle == haystack->obj) { // is this a signal we should relay? if (isAdaptor && (haystack->flags & QDBusConnection::ExportAdaptors) == 0) return; // no: it comes from an adaptor and we're not exporting adaptors else if (!isAdaptor) { int mask = isScriptable ? QDBusConnection::ExportScriptableSignals : QDBusConnection::ExportNonScriptableSignals; if ((haystack->flags & mask) == 0) return; // signal was not exported } QByteArray p = path.toLatin1(); if (p.isEmpty()) p = "/"; qDBusDebug() << "Emitting signal at " << p; DBusMessage *msg2 = dbus_message_copy(msg); dbus_message_set_path(msg2, p); dbus_connection_send(connection, msg2, 0); dbus_message_unref(msg2); }}static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags, const QString &signature_, QList<int>& metaTypes){ QByteArray msgSignature = signature_.toLatin1(); for (int idx = mo->methodCount() - 1 ; idx >= QObject::staticMetaObject.methodCount(); --idx) { QMetaMethod mm = mo->method(idx); // check access: if (mm.access() != QMetaMethod::Public) continue; // check type: // unnecessary, since signals are never public: //if (mm.methodType() != QMetaMethod::Slot) // continue; // check name: QByteArray slotname = mm.signature(); int paren = slotname.indexOf('('); if (paren != name.length() || !slotname.startsWith(name)) continue; int returnType = qDBusNameToTypeId(mm.typeName()); bool isAsync = qDBusCheckAsyncTag(mm.tag()); bool isScriptable = mm.attributes() & QMetaMethod::Scriptable; // consistency check: if (isAsync && returnType != QMetaType::Void) continue; int inputCount = qDBusParametersForMethod(mm, metaTypes); if (inputCount == -1) continue; // problem parsing metaTypes[0] = returnType; bool hasMessage = false; if (inputCount > 0 && metaTypes.at(inputCount) == QDBusMetaTypeId::message) { // "no input parameters" is allowed as long as the message meta type is there hasMessage = true; --inputCount; } // try to match the parameters int i; QByteArray reconstructedSignature; for (i = 1; i <= inputCount; ++i) { const char *typeSignature = QDBusMetaType::typeToSignature( metaTypes.at(i) ); if (!typeSignature) break; // invalid reconstructedSignature += typeSignature; if (!msgSignature.startsWith(reconstructedSignature)) break; } if (reconstructedSignature != msgSignature) continue; // we didn't match them all if (hasMessage) ++i; // make sure that the output parameters have signatures too if (returnType != 0 && QDBusMetaType::typeToSignature(returnType) == 0) continue; bool ok = true; for (int j = i; ok && j < metaTypes.count(); ++j) if (QDBusMetaType::typeToSignature(metaTypes.at(i)) == 0) ok = false; if (!ok) continue; // consistency check: if (isAsync && metaTypes.count() > i + 1) continue; if (isScriptable && (flags & QDBusConnection::ExportScriptableSlots) == 0) continue; // not exported if (!isScriptable && (flags & QDBusConnection::ExportNonScriptableSlots) == 0) continue; // not exported // if we got here, this slot matched return idx; } // no slot matched return -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -