summaryrefslogtreecommitdiffstats
path: root/qt/qdbusintegrator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qt/qdbusintegrator.cpp')
-rw-r--r--qt/qdbusintegrator.cpp507
1 files changed, 341 insertions, 166 deletions
diff --git a/qt/qdbusintegrator.cpp b/qt/qdbusintegrator.cpp
index f108fc43..38f71a11 100644
--- a/qt/qdbusintegrator.cpp
+++ b/qt/qdbusintegrator.cpp
@@ -28,15 +28,17 @@
#include <qmetaobject.h>
#include <qobject.h>
#include <qsocketnotifier.h>
+#include <qstringlist.h>
#include <qtimer.h>
-#include "qdbusvariant.h"
#include "qdbusconnection_p.h"
#include "qdbusinterface_p.h"
-#include "qdbusobject_p.h"
#include "qdbusmessage.h"
#include "qdbusabstractadaptor.h"
#include "qdbusabstractadaptor_p.h"
+#include "qdbustypehelper_p.h"
+#include "qdbusutil.h"
+#include "qdbustype_p.h"
#ifndef USE_OUTSIDE_DISPATCH
# define USE_OUTSIDE_DISPATCH 0
@@ -44,9 +46,6 @@
int QDBusConnectionPrivate::messageMetaType = 0;
-/*!
- \internal
-*/
struct QDBusPendingCall
{
QPointer<QObject> receiver;
@@ -56,9 +55,6 @@ struct QDBusPendingCall
const QDBusConnectionPrivate *connection;
};
-/*!
- \internal
-*/
class CallDeliveryEvent: public QEvent
{
public:
@@ -75,18 +71,6 @@ public:
int slotIdx;
};
-#if __BYTE_ORDER != __LITTLE_ENDIAN
-/*!
- \internal
-*/
-union integer
-{
- short s;
- unsigned short us;
- unsigned char uc;
-};
-#endif
-
static dbus_bool_t qDBusAddTimeout(DBusTimeout *timeout, void *data)
{
Q_ASSERT(timeout);
@@ -137,7 +121,7 @@ static void qDBusToggleTimeout(DBusTimeout *timeout, void *data)
Q_ASSERT(timeout);
Q_ASSERT(data);
- qDebug("ToggleTimeout");
+ //qDebug("ToggleTimeout");
qDBusRemoveTimeout(timeout, data);
qDBusAddTimeout(timeout, data);
@@ -155,7 +139,7 @@ static dbus_bool_t qDBusAddWatch(DBusWatch *watch, void *data)
QDBusConnectionPrivate::Watcher watcher;
if (flags & DBUS_WATCH_READABLE) {
- qDebug("addReadWatch %d", fd);
+ //qDebug("addReadWatch %d", fd);
watcher.watch = watch;
if (QCoreApplication::instance()) {
watcher.read = new QSocketNotifier(fd, QSocketNotifier::Read, d);
@@ -164,7 +148,7 @@ static dbus_bool_t qDBusAddWatch(DBusWatch *watch, void *data)
}
}
if (flags & DBUS_WATCH_WRITABLE) {
- qDebug("addWriteWatch %d", fd);
+ //qDebug("addWriteWatch %d", fd);
watcher.watch = watch;
if (QCoreApplication::instance()) {
watcher.write = new QSocketNotifier(fd, QSocketNotifier::Write, d);
@@ -182,7 +166,7 @@ static void qDBusRemoveWatch(DBusWatch *watch, void *data)
Q_ASSERT(watch);
Q_ASSERT(data);
- qDebug("remove watch");
+ //qDebug("remove watch");
QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
int fd = dbus_watch_get_fd(watch);
@@ -213,7 +197,7 @@ static void qDBusToggleWatch(DBusWatch *watch, void *data)
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);
+ //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);
@@ -228,6 +212,7 @@ static void qDBusToggleWatch(DBusWatch *watch, void *data)
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
}
@@ -256,8 +241,16 @@ static DBusHandlerResult qDBusSignalFilterOutside(DBusConnection *connection,
# define HANDLED DBUS_HANDLER_RESULT_HANDLED
#endif
-static DBusHandlerResult qDBusSignalFilter(DBusConnection *connection,
- DBusMessage *message, void *data)
+extern "C" {
+static DBusHandlerResult
+qDBusSignalFilter(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);
@@ -303,7 +296,7 @@ static void huntAndEmit(DBusConnection *connection, DBusMessage *msg,
QByteArray p = path.toLatin1();
if (p.isEmpty())
p = "/";
- qDebug() << p;
+ //qDebug() << p;
DBusMessage *msg2 = dbus_message_copy(msg);
dbus_message_set_path(msg2, p);
dbus_connection_send(connection, msg2, 0);
@@ -319,39 +312,21 @@ bool qDBusCheckAsyncTag(const char *tag)
const char *p = strstr(tag, "async");
if (p != NULL &&
(p == tag || *(p-1) == ' ') &&
- (p[6] == '\0' || p[6] == ' '))
+ (p[5] == '\0' || p[5] == ' '))
return true;
p = strstr(tag, "Q_ASYNC");
if (p != NULL &&
(p == tag || *(p-1) == ' ') &&
- (p[8] == '\0' || p[8] == ' '))
+ (p[7] == '\0' || p[7] == ' '))
return true;
return false;
}
-static QList<QByteArray> splitParameters(const char *p)
-{
- QList<QByteArray> retval;
- ++p;
- const char *e = p;
- while (*e != ')') {
- while (*e != ')' && *e != ',')
- ++e;
-
- // found the end of this parameter
- retval += QByteArray(p, e - p);
-
- if (*e != ')')
- p = ++e;
- }
- return retval;
-}
-
-static bool typesMatch(int metaId, QVariant::Type variantType)
+static bool typesMatch(int metaId, int variantType)
{
- if (metaId == (int)variantType)
+ if (metaId == int(variantType))
return true;
if (variantType == QVariant::Int && metaId == QMetaType::Short)
@@ -361,6 +336,18 @@ static bool typesMatch(int metaId, QVariant::Type variantType)
metaId == QMetaType::UChar))
return true;
+ if (variantType == QVariant::List) {
+ if (metaId == QDBusTypeHelper<bool>::listId() ||
+ metaId == QDBusTypeHelper<short>::listId() ||
+ metaId == QDBusTypeHelper<ushort>::listId() ||
+ metaId == QDBusTypeHelper<int>::listId() ||
+ metaId == QDBusTypeHelper<uint>::listId() ||
+ metaId == QDBusTypeHelper<qlonglong>::listId() ||
+ metaId == QDBusTypeHelper<qulonglong>::listId() ||
+ metaId == QDBusTypeHelper<double>::listId())
+ return true;
+ }
+
return false; // no match
}
@@ -392,7 +379,15 @@ int qDBusNameToTypeId(const char *name)
return id;
default:
- if (id == qMetaTypeId<QDBusVariant>() || id == QDBusConnectionPrivate::messageMetaType)
+ if (id == QDBusConnectionPrivate::messageMetaType ||
+ id == QDBusTypeHelper<QVariant>::id() ||
+ id == QDBusTypeHelper<bool>::listId() ||
+ id == QDBusTypeHelper<short>::listId() ||
+ id == QDBusTypeHelper<ushort>::listId() ||
+ id == QDBusTypeHelper<int>::listId() ||
+ id == QDBusTypeHelper<qlonglong>::listId() ||
+ id == QDBusTypeHelper<qulonglong>::listId() ||
+ id == QDBusTypeHelper<double>::listId())
return id;
return 0; // invalid
@@ -411,16 +406,9 @@ int qDBusNameToTypeId(const char *name)
// metaTypes.count() >= retval + 1 in all cases
//
// sig must be the normalised signature for the method
-int qDBusParametersForMethod(const QByteArray &sig, QList<int>& metaTypes)
+int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes)
{
- if (sig.indexOf('<') != -1) {
- qWarning("Could not parse the method '%s'", sig.constData());
- // there's no type with templates that we can handle
- return -1;
- }
-
- int paren = sig.indexOf('(');
- QList<QByteArray> parameterTypes = splitParameters(sig.data() + paren);
+ QList<QByteArray> parameterTypes = mm.parameterTypes();
metaTypes.clear();
metaTypes.append(0); // return type
@@ -428,7 +416,7 @@ int qDBusParametersForMethod(const QByteArray &sig, QList<int>& metaTypes)
bool seenMessage = false;
foreach (QByteArray type, parameterTypes) {
if (type.endsWith('*')) {
- qWarning("Could not parse the method '%s'", sig.constData());
+ qWarning("Could not parse the method '%s'", mm.signature());
// pointer?
return -1;
}
@@ -437,7 +425,7 @@ int qDBusParametersForMethod(const QByteArray &sig, QList<int>& metaTypes)
type.truncate(type.length() - 1);
int id = qDBusNameToTypeId(type);
if (id == 0) {
- qWarning("Could not parse the method '%s'", sig.constData());
+ qWarning("Could not parse the method '%s'", mm.signature());
// invalid type in method parameter list
return -1;
}
@@ -448,14 +436,14 @@ int qDBusParametersForMethod(const QByteArray &sig, QList<int>& metaTypes)
}
if (seenMessage) { // && !type.endsWith('&')
- qWarning("Could not parse the method '%s'", sig.constData());
+ qWarning("Could not parse the method '%s'", mm.signature());
// non-output parameters after message or after output params
return -1; // not allowed
}
int id = qDBusNameToTypeId(type);
if (id == 0) {
- qWarning("Could not parse the method '%s'", sig.constData());
+ qWarning("Could not parse the method '%s'", mm.signature());
// invalid type in method parameter list
return -1;
}
@@ -478,7 +466,7 @@ static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags,
super != &QDBusAbstractAdaptor::staticMetaObject)
super = super->superClass();
- int attributeMask = (flags & QDBusConnection::ExportNonScriptableSlots) ?
+ int attributeMask = (flags & QDBusConnection::ExportAllSlots) ?
0 : QMetaMethod::Scriptable;
for (int idx = super->methodCount() ; idx <= mo->methodCount(); ++idx) {
@@ -506,7 +494,7 @@ static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags,
if (isAsync && returnType != QMetaType::Void)
continue;
- int inputCount = qDBusParametersForMethod(sig, metaTypes);
+ int inputCount = qDBusParametersForMethod(mm, metaTypes);
if (inputCount == -1)
continue; // problem parsing
@@ -630,12 +618,13 @@ bool QDBusConnectionPrivate::activateCall(QObject* object, int flags,
{
const QMetaObject *mo = object->metaObject();
QDBusTypeList typeList(msg.signature().toUtf8());
+ QByteArray name = msg.name().toUtf8();
// find a slot that matches according to the rules above
- idx = ::findSlot(mo, msg.name().toUtf8(), flags, typeList, metaTypes);
+ idx = ::findSlot(mo, name, flags, typeList, metaTypes);
if (idx == -1) {
// try with no parameters, but with a QDBusMessage
- idx = ::findSlot(mo, msg.name().toUtf8(), flags, QDBusTypeList(), metaTypes);
+ idx = ::findSlot(mo, name, flags, QDBusTypeList(), metaTypes);
if (metaTypes.count() != 2 || metaTypes.at(1) != messageMetaType)
return false;
}
@@ -692,9 +681,7 @@ void QDBusConnectionPrivate::deliverCall(const CallDeliveryEvent& data) const
QVarLengthArray<void *, 10> params;
params.reserve(metaTypes.count());
-#if __BYTE_ORDER != __LITTLE_ENDIAN
- QVarLengthArray<integer, 4> auxParameters;
-#endif
+ QVarLengthArray<QVariant, 4> auxParameters;
// let's create the parameter list
// first one is the return type -- add it below
@@ -707,25 +694,65 @@ void QDBusConnectionPrivate::deliverCall(const CallDeliveryEvent& data) const
if (id == QDBusConnectionPrivate::messageMetaType)
break;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- params.append(const_cast<void *>( msg.at(i - 1).constData() ));
-#else
- if (id == int(msg.at(i).type()))
+ if (id == int(msg.at(i - 1).userType()))
+ // no conversion needed
params.append(const_cast<void *>( msg.at(i - 1).constData() ));
else {
- // need some help
- integer aux;
- const QVariant &var = msg.at(i - 1);
- if (id == QMetaType::Short)
- aux.s = var.toInt();
- else if (id == QMetaType::UShort)
- aux.us = var.toUInt();
- else
- aux.uc = var.toUInt();
- auxParameters.append(aux);
- params.append( &auxParameters[auxParameters.count()] );
+ // convert to what the function expects
+ auxParameters.append(QVariant());
+
+ const QVariant &in = msg.at(i - 1);
+ QVariant &out = auxParameters[auxParameters.count() - 1];
+
+ bool error = false;
+ if (id == QVariant::List) {
+ int mid = in.userType();
+ // the only conversion possible here is from a specialised QList<T> to QVariantList
+ if (mid == QDBusTypeHelper<bool>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<bool>::toVariantList(in));
+ else if (mid == QDBusTypeHelper<short>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<short>::toVariantList(in));
+ else if (mid == QDBusTypeHelper<ushort>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<ushort>::toVariantList(in));
+ else if (mid == QDBusTypeHelper<int>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<int>::toVariantList(in));
+ else if (mid == QDBusTypeHelper<uint>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<uint>::toVariantList(in));
+ else if (mid == QDBusTypeHelper<qlonglong>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<qlonglong>::toVariantList(in));
+ else if (mid == QDBusTypeHelper<qulonglong>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<qulonglong>::toVariantList(in));
+ else if (mid == QDBusTypeHelper<double>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<double>::toVariantList(in));
+ else
+ error = true;
+ } else if (in.type() == QVariant::UInt) {
+ if (id == QMetaType::UChar) {
+ uchar uc = in.toUInt();
+ out = qVariantFromValue(uc);
+ } else if (id == QMetaType::UShort) {
+ ushort us = in.toUInt();
+ out = qVariantFromValue(us);
+ } else {
+ error = true;
+ }
+ } else if (in.type() == QVariant::Int) {
+ if (id == QMetaType::Short) {
+ short s = in.toInt();
+ out = qVariantFromValue(s);
+ } else {
+ error = true;
+ }
+ } else {
+ error = true;
+ }
+
+ if (error)
+ qFatal("Internal error: got invalid meta type %d when trying to convert to meta type %d",
+ in.userType(), id);
+
+ params.append( const_cast<void *>(out.constData()) );
}
-#endif
}
bool takesMessage = false;
@@ -740,13 +767,13 @@ void QDBusConnectionPrivate::deliverCall(const CallDeliveryEvent& data) const
void *null = 0;
if (metaTypes[0] != QMetaType::Void) {
QVariant arg(metaTypes[0], null);
- params.append( arg.data() );
outputArgs.append( arg );
+ params[0] = const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData());
}
for ( ; i < metaTypes.count(); ++i) {
QVariant arg(metaTypes[i], null);
- params.append( arg.data() );
outputArgs.append( arg );
+ params.append( const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData()) );
}
// make call:
@@ -770,10 +797,9 @@ void QDBusConnectionPrivate::deliverCall(const CallDeliveryEvent& data) const
}
else {
// generate internal error
- QDBusMessage reply = QDBusMessage::error(msg,
- QLatin1String("com.trolltech.QtDBus.InternalError"),
- QLatin1String("Failed to deliver message"));
- qDebug("Internal error: Failed to deliver message");
+ QDBusMessage reply = QDBusMessage::error(msg, QDBusError(QDBusError::InternalError,
+ QLatin1String("Failed to deliver message")));
+ qWarning("Internal error: Failed to deliver message");
send(reply);
}
}
@@ -793,14 +819,16 @@ void QDBusConnectionPrivate::customEvent(QEvent *event)
}
QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *parent)
- : QObject(parent), ref(1), mode(InvalidMode), connection(0), server(0)
+ : QObject(parent), ref(1), mode(InvalidMode), connection(0), server(0), busService(0)
{
extern bool qDBusInitThreads();
static const int msgType = registerMessageMetaType();
static const bool threads = qDBusInitThreads();
+ static const bool metatypes = QDBusMetaTypeId::innerInitialize();
Q_UNUSED(msgType);
Q_UNUSED(threads);
+ Q_UNUSED(metatypes);
dbus_error_init(&error);
@@ -809,23 +837,12 @@ QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *parent)
QDBusConnectionPrivate::~QDBusConnectionPrivate()
{
- Q_ASSERT(knownObjects.isEmpty());
-
if (dbus_error_is_set(&error))
dbus_error_free(&error);
closeConnection();
-
- KnownInterfacesHash::iterator it = knownInterfaces.begin();
- while (it != knownInterfaces.end()) {
- const QSharedDataPointer<QDBusIntrospection::Interface>& item = *it;
-
- const_cast<QDBusIntrospection::Interface*>(item.constData())->ref.deref();
-
- it = knownInterfaces.erase(it);
- }
-
rootNode.clear(); // free resources
+ qDeleteAll(cachedMetaObjects);
}
void QDBusConnectionPrivate::closeConnection()
@@ -933,8 +950,8 @@ void QDBusConnectionPrivate::relaySignal(QObject *obj, const char *interface, co
return;
}
- qDebug() << "Emitting signal" << message;
- qDebug() << "for paths:";
+ //qDebug() << "Emitting signal" << message;
+ //qDebug() << "for paths:";
dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything
huntAndEmit(connection, msg, obj, &rootNode);
dbus_message_unref(msg);
@@ -956,7 +973,7 @@ int QDBusConnectionPrivate::findSlot(QObject* obj, const char *slotName, QList<i
return -1;
}
- int inputCount = qDBusParametersForMethod(normalizedName, params);
+ int inputCount = qDBusParametersForMethod(obj->metaObject()->method(midx), params);
if ( inputCount == -1 || inputCount + 1 != params.count() )
return -1; // failed to parse or invalid arguments or output arguments
@@ -996,7 +1013,7 @@ bool QDBusConnectionPrivate::activateObject(const ObjectTreeNode *node, const QD
QDBusAdaptorConnector *connector;
if (node->flags & QDBusConnection::ExportAdaptors &&
(connector = qDBusFindAdaptorConnector(node->obj))) {
- int newflags = node->flags | QDBusConnection::ExportNonScriptableSlots;
+ int newflags = node->flags | QDBusConnection::ExportAllSlots;
if (msg.interface().isEmpty()) {
// place the call in all interfaces
@@ -1023,12 +1040,13 @@ bool QDBusConnectionPrivate::activateObject(const ObjectTreeNode *node, const QD
// try the object itself:
if (node->flags & QDBusConnection::ExportSlots && activateCall(node->obj, node->flags, msg))
return true;
-
+#if 0
// nothing matched
qDebug("Call failed: no match for %s%s%s at %s",
qPrintable(msg.interface()), msg.interface().isEmpty() ? "" : ".",
qPrintable(msg.name()),
qPrintable(msg.path()));
+#endif
return false;
}
@@ -1101,8 +1119,8 @@ bool QDBusConnectionPrivate::handleSignal(const QString &path, const QDBusMessag
bool result = false;
SignalHookHash::const_iterator it = signalHooks.find(path);
- qDebug("looking for: %s", path.toLocal8Bit().constData());
- qDebug() << signalHooks.keys();
+ //qDebug("looking for: %s", path.toLocal8Bit().constData());
+ //qDebug() << signalHooks.keys();
for ( ; it != signalHooks.constEnd() && it.key() == path; ++ it) {
const SignalHook &hook = it.value();
if ( !hook.name.isEmpty() && hook.name != msg.name() )
@@ -1197,11 +1215,17 @@ void QDBusConnectionPrivate::setConnection(DBusConnection *dbc)
dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0);
#endif
- qDebug("base service: %s", service);
+ //qDebug("base service: %s", service);
}
+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);
@@ -1216,11 +1240,14 @@ static void qDBusResultReceived(DBusPendingCall *pending, void *user_data)
// 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)
- CallDeliveryEvent *e = prepareReply(call->receiver, call->methodIdx, call->metaTypes,
- QDBusMessage::fromDBusMessage(reply,
- QDBusConnection(connection->name)));
+
+ QDBusMessage msg = QDBusMessage::fromDBusMessage(reply, QDBusConnection(connection->name));
+ qDebug() << "got message: " << msg;
+ CallDeliveryEvent *e = prepareReply(call->receiver, call->methodIdx, call->metaTypes, msg);
if (e)
connection->deliverCall(*e);
+ else
+ qDebug() << "Deliver failed!";
delete e;
}
dbus_pending_call_unref(pending);
@@ -1241,8 +1268,39 @@ bool QDBusConnectionPrivate::send(const QDBusMessage& message) const
return isOk;
}
+QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
+ int mode)
+{
+ if (!QCoreApplication::instance() || mode == QDBusConnection::NoUseEventLoop) {
+ DBusMessage *msg = message.toDBusMessage();
+ if (!msg)
+ return QDBusMessage();
+
+ DBusMessage *reply = dbus_connection_send_with_reply_and_block(connection, msg,
+ -1, &error);
+ handleError();
+ dbus_message_unref(msg);
+
+ if (lastError.isValid())
+ return QDBusMessage::fromError(lastError);
+
+ return QDBusMessage::fromDBusMessage(reply, QDBusConnection(name));
+ } else { // use the event loop
+ QDBusReplyWaiter waiter;
+ if (sendWithReplyAsync(message, &waiter, SLOT(reply(const QDBusMessage&))) > 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) const
+ const char *method)
{
DBusMessage *msg = message.toDBusMessage();
if (!msg)
@@ -1286,76 +1344,192 @@ void QDBusConnectionPrivate::registerObject(const ObjectTreeNode *node)
QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(node->obj);
// disconnect and reconnect to avoid duplicates
- connector->disconnect(SIGNAL(relaySignal(QObject *,const char*, const char*,QVariantList)),
- this, SLOT(relaySignal(QObject*, const char*, const char*,QVariantList)));
- connect(connector, SIGNAL(relaySignal(QObject *,const char*, const char*,QVariantList)),
- SLOT(relaySignal(QObject*, const char*, const char*,QVariantList)));
+ connector->disconnect(SIGNAL(relaySignal(QObject*,const char*,const char*,QVariantList)),
+ this, SLOT(relaySignal(QObject*,const char*,const char*,QVariantList)));
+ connect(connector, SIGNAL(relaySignal(QObject*,const char*,const char*,QVariantList)),
+ SLOT(relaySignal(QObject*,const char*,const char*,QVariantList)));
}
}
-QSharedDataPointer<QDBusIntrospection::Interface>
-QDBusConnectionPrivate::findInterface(const QString& name)
+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
+
+ // similar to QDBusConnectionPrivate::findSlot! Merge!
+ QByteArray normalizedName = QMetaObject::normalizedSignature(signal + 1);
+ SignalHook hook;
+ hook.midx = receiver->metaObject()->indexOfSignal(normalizedName);
+ Q_ASSERT(hook.midx != -1); // cannot happen
+ if (hook.midx < QDBusAbstractInterface::staticMetaObject.methodCount())
+ return; // don't connect to this signal
+
+ int inputCount = qDBusParametersForMethod(receiver->metaObject()->method(hook.midx), hook.params);
+ if ( inputCount == -1 || inputCount + 1 != hook.params.count() )
+ return; // failed to parse or invalid arguments or output arguments
+
+ // build the D-Bus signal name and signature
+ QString source = service;
+ source += path;
+ normalizedName.truncate(normalizedName.indexOf('('));
+ hook.name = QString::fromUtf8(normalizedName);
+ hook.interface = interface;
+ hook.obj = receiver;
+ for (int i = 1; i <= inputCount; ++i)
+ if (hook.params.at(i) != messageMetaType)
+ hook.signature += QLatin1String( QDBusType::dbusSignature( QVariant::Type(hook.params.at(i)) ) );
+
+ // add it to our list:
QWriteLocker locker(&lock);
- QSharedDataPointer<QDBusIntrospection::Interface> data = knownInterfaces.value(name);
- if (!data) {
- data = new QDBusIntrospection::Interface;
- data->name = name;
- data->ref.ref(); // don't delete
-
- knownInterfaces.insert(name, data);
+ SignalHookHash::ConstIterator it = signalHooks.find(source);
+ SignalHookHash::ConstIterator end = signalHooks.end();
+ for ( ; it != end && it.key() == source; ++it) {
+ const SignalHook &entry = it.value();
+ if (entry.interface == hook.interface &&
+ entry.name == hook.name &&
+ entry.signature == hook.signature &&
+ entry.obj == hook.obj &&
+ entry.midx == hook.midx)
+ return; // already there, no need to re-add
}
- return data;
+
+ connectSignal(source, hook);
}
-QDBusIntrospection::Object*
-QDBusConnectionPrivate::findObject(const QString& service, const QString& path)
+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
+
+ // similar to QDBusConnectionPrivate::findSlot! Merge!
+ QByteArray normalizedName = QMetaObject::normalizedSignature(signal + 1);
+ SignalHook hook;
+ hook.midx = receiver->metaObject()->indexOfSignal(normalizedName);
+ Q_ASSERT(hook.midx != -1); // cannot happen
+ if (hook.midx < QDBusAbstractInterface::staticMetaObject.methodCount())
+ return; // we won't find it, so don't bother
+
+ int inputCount = qDBusParametersForMethod(receiver->metaObject()->method(hook.midx), hook.params);
+ if ( inputCount == -1 || inputCount + 1 != hook.params.count() )
+ return; // failed to parse or invalid arguments or output arguments
+
+ // build the D-Bus signal name and signature
+ QString source = service;
+ source += path;
+ normalizedName.truncate(normalizedName.indexOf('('));
+ hook.name = QString::fromUtf8(normalizedName);
+ hook.interface = interface;
+ hook.obj = receiver;
+ for (int i = 1; i <= inputCount; ++i)
+ if (hook.params.at(i) != messageMetaType)
+ hook.signature += QLatin1String( QDBusType::dbusSignature( QVariant::Type(hook.params.at(i)) ) );
+
+ // remove it from our list:
QWriteLocker locker(&lock);
- QDBusIntrospection::Object* data = knownObjects.value(service + path);
- if (!data) {
- data = new QDBusIntrospection::Object;
- data->service = service;
- data->path = path;
-
- knownObjects.insert(service + path, data);
+ SignalHookHash::Iterator it = signalHooks.find(source);
+ SignalHookHash::Iterator end = signalHooks.end();
+ for ( ; it != end && it.key() == source; ++it) {
+ const SignalHook &entry = it.value();
+ if (entry.interface == hook.interface &&
+ entry.name == hook.name &&
+ entry.signature == hook.signature &&
+ entry.obj == hook.obj &&
+ entry.midx == hook.midx) {
+ // found it
+ signalHooks.erase(it);
+ return;
+ }
}
- return data;
+ qWarning("QDBusConnectionPrivate::disconnectRelay called for a signal that was not found");
}
-void QDBusConnectionPrivate::disposeOfLocked(QDBusIntrospection::Object* p)
+QString QDBusConnectionPrivate::getNameOwner(const QString& name)
{
- if (p && !p->ref.deref()) { // ref--
- // no one else is using it
- // get rid of the reference
- QString objName = p->service + p->path;
-
-#ifndef QT_NO_DEBUG
- // debug code
- Q_ASSERT(p == knownObjects.take(objName));
-#else
- // non-debug
- knownObjects.remove(objName);
-#endif
+ if (QDBusUtil::isValidUniqueConnectionName(name))
+ return name;
+ if (!connection || !QDBusUtil::isValidBusName(name))
+ return QString();
+
+ QDBusMessage msg = QDBusMessage::methodCall(QLatin1String(DBUS_SERVICE_DBUS),
+ QLatin1String(DBUS_PATH_DBUS), QLatin1String(DBUS_INTERFACE_DBUS),
+ QLatin1String("GetNameOwner"));
+ msg << name;
+ QDBusMessage reply = sendWithReply(msg, QDBusConnection::NoUseEventLoop);
+ if (!lastError.isValid() && reply.type() == QDBusMessage::ReplyMessage)
+ return reply.first().toString();
+ return QString();
+}
- // remove sub-objects too
- if (!objName.endsWith(QLatin1Char('/')))
- objName.append(QLatin1Char('/'));
- foreach (QString subObjName, p->childObjects)
- disposeOfLocked(knownObjects.value(objName + subObjName));
+QDBusInterfacePrivate *
+QDBusConnectionPrivate::findInterface(const QString &service,
+ const QString &path,
+ const QString &interface)
+{
+
+ if (!connection || !QDBusUtil::isValidObjectPath(path))
+ return 0;
+ if (!interface.isEmpty() && !QDBusUtil::isValidInterfaceName(interface))
+ return 0;
- delete p;
- }
+ // check if it's there first -- FIXME: add binding mode
+ QString owner = getNameOwner(service);
+ if (owner.isEmpty())
+ return 0;
+
+ QString tmp(interface);
+ QDBusMetaObject *mo = findMetaObject(owner, path, tmp);
+ if (mo)
+ return new QDBusInterfacePrivate(QDBusConnection(name), this, owner, path, tmp, mo);
+ return 0; // error has been set
}
-void QDBusConnectionPrivate::disposeOf(QDBusObjectPrivate* p)
+QDBusMetaObject *
+QDBusConnectionPrivate::findMetaObject(const QString &service, const QString &path,
+ QString &interface)
{
- // We're called from QDBusConnectionPrivate's destructor
- // that means the object it represents is going out of scope
+ if (!interface.isEmpty()) {
+ QReadLocker locker(&lock);
+ QDBusMetaObject *mo = cachedMetaObjects.value(interface, 0);
+ if (mo)
+ return mo;
+ }
+
+ // introspect the target object:
+ QDBusMessage msg = QDBusMessage::methodCall(service, path,
+ QLatin1String(DBUS_INTERFACE_INTROSPECTABLE),
+ QLatin1String("Introspect"));
+ // we have to spin the event loop because the call could be targetting ourselves
+ QDBusMessage reply = sendWithReply(msg, QDBusConnection::UseEventLoop);
+
+ // it doesn't exist yet, we have to create it
QWriteLocker locker(&lock);
- disposeOfLocked( const_cast<QDBusIntrospection::Object*>(p->data) );
+ 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.first().toString();
+ else {
+ lastError = reply;
+ if (reply.type() != QDBusMessage::ErrorMessage || lastError != QDBusError::UnknownMethod)
+ return 0; // error
+ }
+
+ // release the lock and return
+ return QDBusMetaObject::createMetaObject(interface, xml, cachedMetaObjects, lastError);
}
void QDBusReplyWaiter::reply(const QDBusMessage &msg)
@@ -1363,4 +1537,5 @@ void QDBusReplyWaiter::reply(const QDBusMessage &msg)
replyMsg = msg;
QTimer::singleShot(0, this, SLOT(quit()));
}
+
#include "qdbusconnection_p.moc"