dbus/qt Makefile.am, 1.12, 1.13 README, NONE,
1.1 qdbusabstractadaptor.cpp, NONE, 1.1 qdbusabstractadaptor.h,
NONE, 1.1 qdbusconnection.cpp, 1.3, 1.4 qdbusconnection.h, 1.3,
1.4 qdbusconnection_p.h, 1.3, 1.4 qdbuserror.cpp, 1.1,
1.2 qdbuserror.h, 1.2, 1.3 qdbusintegrator.cpp, 1.1,
1.2 qdbusinterface.cpp, NONE, 1.1 qdbusinterface.h, NONE,
1.1 qdbusinterface_p.h, NONE, 1.1 qdbusintrospection.cpp, NONE,
1.1 qdbusintrospection.h, NONE, 1.1 qdbusmacros.h, 1.2,
1.3 qdbusmarshall.cpp, 1.2, 1.3 qdbusmarshall.h, 1.1,
1.2 qdbusmessage.cpp, 1.1, 1.2 qdbusmessage.h, 1.2,
1.3 qdbusmessage_p.h, 1.1, 1.2 qdbusobject.cpp, NONE,
1.1 qdbusobject.h, NONE, 1.1 qdbusobject_p.h, NONE,
1.1 qdbusserver.cpp, 1.1, 1.2 qdbusserver.h, 1.2,
1.3 qdbusstandardinterfaces.cpp, NONE,
1.1 qdbusstandardinterfaces.h, NONE, 1.1 qdbusthread.cpp, NONE,
1.1 qdbustype.cpp, NONE, 1.1 qdbustype.h, NONE,
1.1 qdbusutil.cpp, NONE, 1.1 qdbusutil.h, NONE,
1.1 qdbusvariant.h, 1.2, 1.3 qdbusxmlparser.cpp, NONE,
1.1 qdbusxmlparser_p.h, NONE, 1.1
Thiago J. Macieira
thiago at freedesktop.org
Wed Feb 15 08:25:14 PST 2006
Update of /cvs/dbus/dbus/qt
In directory gabe:/tmp/cvs-serv17445
Modified Files:
Makefile.am qdbusconnection.cpp qdbusconnection.h
qdbusconnection_p.h qdbuserror.cpp qdbuserror.h
qdbusintegrator.cpp qdbusmarshall.cpp qdbusmarshall.h
qdbusmessage.cpp qdbusmessage.h qdbusmessage_p.h
qdbusserver.cpp qdbusserver.h qdbusvariant.h
Added Files:
README qdbusabstractadaptor.cpp qdbusabstractadaptor.h
qdbusinterface.cpp qdbusinterface.h qdbusinterface_p.h
qdbusintrospection.cpp qdbusintrospection.h qdbusmacros.h
qdbusobject.cpp qdbusobject.h qdbusobject_p.h
qdbusstandardinterfaces.cpp qdbusstandardinterfaces.h
qdbusthread.cpp qdbustype.cpp qdbustype.h qdbusutil.cpp
qdbusutil.h qdbusxmlparser.cpp qdbusxmlparser_p.h
Log Message:
Merge the changes to the bindings from the KDE Subversion server.
This is a major change: library is source- and binary-incompatible to
what it used to be.
All testcases are green, functionality is preserved.
It is not feature-complete. Development will continue in the branch in the
Subversion server for a while.
Index: Makefile.am
===================================================================
RCS file: /cvs/dbus/dbus/qt/Makefile.am,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- Makefile.am 30 Sep 2005 15:20:08 -0000 1.12
+++ Makefile.am 15 Feb 2006 16:25:11 -0000 1.13
@@ -6,11 +6,19 @@
lib_LTLIBRARIES=libdbus-qt4-1.la
dbusinclude_HEADERS= \
- qdbuserror.h \
- qdbusmessage.h \
- qdbusserver.h \
+ qdbusmacros.h \
+ qdbuserror.h \
+ qdbusmessage.h \
+ qdbusserver.h \
qdbusconnection.h \
- qdbusvariant.h
+ qdbusvariant.h \
+ qdbusobject.h \
+ qdbusinterface.h \
+ qdbustype.h \
+ qdbusstandardinterfaces.h \
+ qdbusutil.h \
+ qdbusintrospection.h \
+ qdbusabstractadaptor.h
libdbus_qt4_1_la_SOURCES = \
$(top_srcdir)/qt/qdbusconnection.cpp \
@@ -19,29 +27,46 @@
$(top_srcdir)/qt/qdbusmarshall.cpp \
$(top_srcdir)/qt/qdbusmessage.cpp \
$(top_srcdir)/qt/qdbusserver.cpp \
+ $(top_srcdir)/qt/qdbustype.cpp \
+ $(top_srcdir)/qt/qdbusobject.cpp \
+ $(top_srcdir)/qt/qdbusinterface.cpp \
+ $(top_srcdir)/qt/qdbusstandardinterfaces.cpp \
+ $(top_srcdir)/qt/qdbusxmlparser.cpp \
+ $(top_srcdir)/qt/qdbusutil.cpp \
+ $(top_srcdir)/qt/qdbusintrospection.cpp \
+ $(top_srcdir)/qt/qdbusabstractadaptor.cpp \
+ $(top_srcdir)/qt/qdbusthread.cpp \
+ \
+ $(top_srcdir)/dbus/qdbus.h \
+ $(top_srcdir)/qt/qdbusabstractadaptor.h \
$(top_srcdir)/qt/qdbusconnection.h \
- $(top_srcdir)/qt/qdbuserror.h \
- $(top_srcdir)/qt/qdbusmessage.h \
- $(top_srcdir)/qt/qdbusserver.h \
$(top_srcdir)/qt/qdbusconnection_p.h \
- $(top_srcdir)/dbus/qdbus.h \
+ $(top_srcdir)/qt/qdbuserror.h \
+ $(top_srcdir)/qt/qdbusinterface.h \
+ $(top_srcdir)/qt/qdbusinterface_p.h \
+ $(top_srcdir)/qt/qdbusintrospection.h \
+ $(top_srcdir)/qt/qdbusmacros.h \
$(top_srcdir)/qt/qdbusmarshall.h \
+ $(top_srcdir)/qt/qdbusmessage.h \
$(top_srcdir)/qt/qdbusmessage_p.h \
- $(top_srcdir)/qt/qdbusvariant.h
+ $(top_srcdir)/qt/qdbusobject.h \
+ $(top_srcdir)/qt/qdbusobject_p.h \
+ $(top_srcdir)/qt/qdbusserver.h \
+ $(top_srcdir)/qt/qdbusstandardinterfaces.
+ $(top_srcdir)/qt/qdbustype.h \
+ $(top_srcdir)/qt/qdbusvariant.h \
+ $(top_srcdir)/qt/qdbusxmlparser_p.h
-$(top_srcdir)/qt/qdbusserver.cpp: qdbusserver.moc
-$(top_srcdir)/qt/qdbusconnection.cpp: qdbusconnection.moc
+$(top_srcdir)/qt/qdbusabstractadaptor.lo: qdbusabstractadaptor.moc
+$(top_srcdir)/qt/qdbusserver.lo: qdbusserver.moc
+$(top_srcdir)/qt/qdbusconnection.lo: qdbusconnection_p.moc
-CLEANFILES=qdbusserver.moc qdbusconnection.moc
+CLEANFILES=qdbusabstractadaptor.moc qdbusserver.moc qdbusconnection.moc
libdbus_qt4_1_la_LIBADD= $(DBUS_QT_LIBS) $(top_builddir)/dbus/libdbus-1.la
libdbus_qt4_1_la_LDFLAGS= -version-info 1:0 -no-undefined
-# _p.h files are a exception
-qdbusconnection.moc: qdbusconnection_p.h
- $(QT_MOC) -o qdbusconnection.moc $(top_srcdir)/qt/qdbusconnection_p.h
-
%.moc: %.h
$(QT_MOC) $< > $@
endif
--- NEW FILE: README ---
These are the Qt4 D-Bus bindings.
They are being maintained by Trolltech AS. As we are currently
considering placing this code in a future version of Qt, we would like
to ask any contributors to contact us before submitting code to this
repository.
For more information, please contact
Thiago Macieira <thiago.macieira at trolltech.com>
--- NEW FILE: qdbusabstractadaptor.cpp ---
/* -*- mode: C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbusabstractadaptor.h"
#include <QtCore/qmetaobject.h>
#include <QtCore/qtimer.h>
QDBusAbstractAdaptor::QDBusAbstractAdaptor(QObject* parent)
: QObject(parent)
{
QTimer::singleShot(0, this, SLOT(polish()));
}
QDBusAbstractAdaptor::~QDBusAbstractAdaptor()
{
}
void QDBusAbstractAdaptor::setAutoRelaySignals(bool enable)
{
const QMetaObject *us = metaObject();
for (int idx = staticMetaObject.methodCount(); idx < us->methodCount(); ++idx) {
QMetaMethod mm = us->method(idx);
if (mm.methodType() != QMetaMethod::Signal)
continue;
// try to connect/disconnect to a signal on the parent that has the same method signature
QByteArray sig = mm.signature();
sig.prepend(QSIGNAL_CODE + '0');
if (enable)
connect(parent(), sig, sig);
else
parent()->disconnect(sig, this, sig);
}
}
void QDBusAbstractAdaptor::polish()
{
// future work:
// connect every signal in this adaptor to a slot that will relay them into D-Bus
}
#include "qdbusabstractadaptor.moc"
--- NEW FILE: qdbusabstractadaptor.h ---
/* -*- mode: C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSABSTRACTADAPTOR_H
#define QDBUSABSTRACTADAPTOR_H
#include <QtCore/qobject.h>
#include "qdbusmacros.h"
class QDBUS_EXPORT QDBusAbstractAdaptor: public QObject
{
Q_OBJECT
public:
QDBusAbstractAdaptor(QObject* parent);
~QDBusAbstractAdaptor();
protected:
void setAutoRelaySignals(bool enable);
private slots:
void polish();
};
#endif
Index: qdbusconnection.cpp
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusconnection.cpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- qdbusconnection.cpp 1 Dec 2005 00:07:20 -0000 1.3
+++ qdbusconnection.cpp 15 Feb 2006 16:25:12 -0000 1.4
@@ -1,6 +1,8 @@
/* qdbusconnection.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
@@ -15,16 +17,21 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, write to the Free Software Foundation
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
-#include <QtCore/qdebug.h>
-#include <QtCore/qcoreapplication.h>
+#include <qdebug.h>
+#include <qcoreapplication.h>
#include "qdbusconnection.h"
+#include "qdbuserror.h"
+#include "qdbusmessage.h"
#include "qdbusconnection_p.h"
+#include "qdbusinterface_p.h"
+#include "qdbusobject_p.h"
+#include "qdbusutil.h"
QT_STATIC_CONST_IMPL char *QDBusConnection::default_connection_name = "qt_dbus_default_connection";
@@ -197,14 +204,7 @@
{
if (!d || !d->connection)
return false;
-
- DBusMessage *msg = message.toDBusMessage();
- if (!msg)
- return false;
-
- bool isOk = dbus_connection_send(d->connection, msg, 0);
- dbus_message_unref(msg);
- return isOk;
+ return d->send(message);
}
int QDBusConnection::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
@@ -221,57 +221,98 @@
if (!d || !d->connection)
return QDBusMessage::fromDBusMessage(0);
- DBusMessage *msg = message.toDBusMessage();
- if (!msg)
- return QDBusMessage::fromDBusMessage(0);
- DBusMessage *reply = dbus_connection_send_with_reply_and_block(d->connection, msg,
- -1, &d->error);
- d->handleError();
- dbus_message_unref(msg);
+ if (!QCoreApplication::instance()) {
+ DBusMessage *msg = message.toDBusMessage();
+ if (!msg)
+ return QDBusMessage::fromDBusMessage(0);
- return QDBusMessage::fromDBusMessage(reply);
+ DBusMessage *reply = dbus_connection_send_with_reply_and_block(d->connection, msg,
+ -1, &d->error);
+ d->handleError();
+ dbus_message_unref(msg);
+
+ if (lastError().isValid())
+ return QDBusMessage::fromError(lastError());
+
+ return QDBusMessage::fromDBusMessage(reply);
+ } else {
+ QDBusReplyWaiter waiter;
+ if (d->sendWithReplyAsync(message, &waiter, SLOT(reply(const QDBusMessage&))) > 0) {
+ // enter the event loop and wait for a reply
+ waiter.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
+
+ d->lastError = waiter.replyMsg; // set or clear error
+ return waiter.replyMsg;
+ }
+
+ return QDBusMessage::fromDBusMessage(0);
+ }
}
-bool QDBusConnection::connect(const QString &path, const QString &interface,
+bool QDBusConnection::connect(const QString &service, const QString &path, const QString& interface,
const QString &name, QObject *receiver, const char *slot)
{
+ return connect(service, path, interface, name, QString(), receiver, slot);
+}
+
+bool QDBusConnection::connect(const QString &service, const QString &path, const QString& interface,
+ const QString &name, const QString &signature,
+ QObject *receiver, const char *slot)
+{
if (!receiver || !slot || !d || !d->connection)
return false;
- QDBusConnectionPrivate::SignalHook hook;
+ QString source = getNameOwner(service);
+ if (source.isEmpty())
+ return false;
+ source += path;
+ // check the slot
+ QDBusConnectionPrivate::SignalHook hook;
+ if ((hook.midx = QDBusConnectionPrivate::findSlot(receiver, slot + 1, hook.params)) == -1)
+ return false;
+
hook.interface = interface;
hook.name = name;
+ hook.signature = signature;
hook.obj = QPointer<QObject>(receiver);
- if (!hook.setSlot(slot + 1))
- return false;
- d->signalHooks.insertMulti(path, hook);
+ d->signalHooks.insertMulti(source, hook);
d->connect(receiver, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)));
return true;
}
+bool QDBusConnection::registerObject(const QString &path, QObject *object, RegisterOptions options)
+{
+ return registerObject(path, QString(), object, options);
+}
+
bool QDBusConnection::registerObject(const QString &path, const QString &interface,
- QObject *object)
+ QObject *object, RegisterOptions options)
{
- if (!d || !d->connection || !object || path.isEmpty() || interface.isEmpty())
+ if (!d || !d->connection || !object || !options || !QDBusUtil::isValidObjectPath(path))
return false;
- QDBusConnectionPrivate::ObjectHook hook;
- hook.interface = interface;
- hook.obj = object;
+ QString iface = interface;
+ if (options & ExportForAnyInterface)
+ iface.clear();
- QDBusConnectionPrivate::ObjectHookHash::iterator it = d->objectHooks.find(path);
- while (it != d->objectHooks.end() && it.key() == path) {
- if (it.value().interface == interface) {
- d->objectHooks.erase(it);
- break;
- }
- ++it;
- }
+ QDBusConnectionPrivate::ObjectDataHash& hook = d->objectHooks[path];
- d->objectHooks.insert(path, hook);
+ // if we're replacing and matching any interface, then we're replacing every interface
+ // this catches ExportAdaptors | Reexport too
+ if (( options & ( ExportForAnyInterface | Reexport )) == ( ExportForAnyInterface | Reexport ))
+ hook.clear();
+
+ // we're not matching any interface, but if we're not replacing, make sure it doesn't exist yet
+ else if (( options & Reexport ) == 0 && hook.find(iface) != hook.end())
+ return false;
+
+ QDBusConnectionPrivate::ObjectData& data = hook[iface];
+
+ data.flags = options;
+ data.obj = object;
d->connect(object, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)));
qDebug("REGISTERED FOR %s", path.toLocal8Bit().constData());
@@ -284,10 +325,45 @@
if (!d || !d->connection)
return;
- // TODO - check interfaces
d->objectHooks.remove(path);
}
+QDBusInterface QDBusConnection::findInterface(const QString& service, const QString& path,
+ const QString& interface)
+{
+ // create one
+ QDBusInterfacePrivate *priv = new QDBusInterfacePrivate;
+ priv->conn = *this;
+
+ if (!QDBusUtil::isValidObjectPath(path) || !QDBusUtil::isValidInterfaceName(interface))
+ return QDBusInterface(priv);
+
+ // check if it's there first
+ QString owner = getNameOwner(service);
+ if (owner.isEmpty())
+ return QDBusInterface(priv);
+
+ // getNameOwner returns empty if d is 0
+ Q_ASSERT(d);
+ priv->service = owner;
+ priv->path = path;
+ priv->data = d->findInterface(interface).constData();
+
+ return QDBusInterface(priv); // will increment priv's refcount
+}
+
+QDBusObject QDBusConnection::findObject(const QString& service, const QString& path)
+{
+ QDBusObjectPrivate* priv = 0;
+ if (d && QDBusUtil::isValidObjectPath(path)) {
+ QString owner = getNameOwner(service);
+
+ if (!owner.isEmpty())
+ priv = new QDBusObjectPrivate(d, owner, path);
+ }
+ return QDBusObject(priv, *this);
+}
+
bool QDBusConnection::isConnected( ) const
{
return d && d->connection && dbus_connection_get_is_connected(d->connection);
@@ -307,21 +383,38 @@
bool QDBusConnection::requestName(const QString &name, NameRequestMode mode)
{
- //FIXME: DBUS_NAME_FLAGS_* are bit fields not enumeration
- static const int DBusModes[] = { 0, DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
- DBUS_NAME_FLAG_REPLACE_EXISTING };
- Q_ASSERT(mode == 0 || mode == AllowReplace ||
- mode == ReplaceExisting );
+ static const int DBusModes[] = { DBUS_NAME_FLAG_ALLOW_REPLACEMENT, 0,
+ DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_ALLOW_REPLACEMENT};
- DBusError error;
- dbus_error_init (&error);
- dbus_bus_request_name(d->connection, name.toUtf8(), DBusModes[mode], &error);
- if (dbus_error_is_set (&error)) {
- qDebug("Error %s\n", error.message);
- dbus_error_free (&error);
+ int retval = dbus_bus_request_name(d->connection, name.toUtf8(), DBusModes[mode], &d->error);
+ d->handleError();
+ return retval == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ||
+ retval == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER;
+}
+
+bool QDBusConnection::releaseName(const QString &name)
+{
+ int retval = dbus_bus_release_name(d->connection, name.toUtf8(), &d->error);
+ d->handleError();
+ if (lastError().isValid())
return false;
- }
- return true;
+ return retval == DBUS_RELEASE_NAME_REPLY_RELEASED;
}
-#include "qdbusconnection.moc"
+QString QDBusConnection::getNameOwner(const QString& name)
+{
+ if (QDBusUtil::isValidUniqueConnectionName(name))
+ return name;
+ if (!d || !QDBusUtil::isValidBusName(name))
+ return QString();
+
+ QDBusMessage msg = QDBusMessage::methodCall(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS, "GetNameOwner");
+ msg << name;
+ QDBusMessage reply = sendWithReply(msg);
+ if (!lastError().isValid() && reply.type() == QDBusMessage::ReplyMessage)
+ return reply.first().toString();
+ return QString();
+}
+
+#include "qdbusconnection_p.moc"
Index: qdbusconnection.h
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusconnection.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- qdbusconnection.h 1 Dec 2005 00:07:20 -0000 1.3
+++ qdbusconnection.h 15 Feb 2006 16:25:12 -0000 1.4
@@ -1,6 +1,8 @@
/* qdbusconnection.h QDBusConnection object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
@@ -15,18 +17,21 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, write to the Free Software Foundation
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSCONNECTION_H
#define QDBUSCONNECTION_H
-#include "dbus/qdbus.h"
+#include "qdbusmacros.h"
#include <QtCore/qstring.h>
class QDBusConnectionPrivate;
+class QDBusXmlParser;
+class QDBusObject;
+class QDBusInterface;
class QDBusError;
class QDBusMessage;
class QByteArray;
@@ -46,8 +51,11 @@
bool isConnected() const;
QDBusError lastError() const;
- enum NameRequestMode { NoReplace = 0, AllowReplace = 1, ReplaceExisting = 2 };
+ enum NameRequestMode { NoReplace = 0, ProhibitReplace = 1, ReplaceExisting = 2 };
bool requestName(const QString &name, NameRequestMode mode = NoReplace);
+ bool releaseName(const QString& name);
+ QString getNameOwner(const QString& name);
+
QString baseService() const;
@@ -56,13 +64,42 @@
int sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
const char *slot) const;
- bool connect(const QString &path, const QString &interface,
+ bool connect(const QString &service, const QString &path, const QString &interface,
const QString &name, QObject *receiver, const char *slot);
+ bool connect(const QString &service, const QString &path, const QString &interface,
+ const QString &name, const QString& signature,
+ QObject *receiver, const char *slot);
- bool registerObject(const QString &path, const QString &interface,
- QObject *object);
+ enum RegisterOption {
+ ExportForAnyInterface = 0x01,
+ ExportAdaptors = 0x03,
+
+ ExportOwnSlots = 0x10,
+ ExportOwnSignals = 0x20,
+ ExportOwnProperties = 0x40,
+ ExportOwnContents = 0xf0,
+
+ ExportNonScriptableSlots = 0x100,
+ ExportNonScriptableSignals = 0x200,
+ ExportNonScriptableProperties = 0x400,
+ ExportNonScriptables = 0xf00,
+
+ ExportChildObjects = 0x1000,
+
+ Reexport = 0x100000,
+ };
+ Q_DECLARE_FLAGS(RegisterOptions, RegisterOption);
+
+ bool registerObject(const QString &path, const QString &interface, QObject *object,
+ RegisterOptions options = ExportOwnContents);
+ bool registerObject(const QString &path, QObject *object,
+ RegisterOptions options = ExportAdaptors);
void unregisterObject(const QString &path);
+ QDBusObject findObject(const QString& service, const QString& path);
+ QDBusInterface findInterface(const QString& service, const QString& path, const QString& interface);
+
+
static QDBusConnection addConnection(BusType type,
const QString &name = QLatin1String(default_connection_name));
static QDBusConnection addConnection(const QString &address,
@@ -72,7 +109,9 @@
QT_STATIC_CONST char *default_connection_name;
private:
+ friend class QDBusObject;
QDBusConnectionPrivate *d;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDBusConnection::RegisterOptions)
#endif
Index: qdbusconnection_p.h
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusconnection_p.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- qdbusconnection_p.h 23 Sep 2005 16:24:36 -0000 1.3
+++ qdbusconnection_p.h 15 Feb 2006 16:25:12 -0000 1.4
@@ -1,6 +1,8 @@
/* qdbusconnection_p.h QDBusConnection private object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
@@ -15,8 +17,8 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, write to the Free Software Foundation
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
@@ -38,16 +40,24 @@
#include "qdbuserror.h"
#include <QtCore/qatomic.h>
+#include <QtCore/qmutex.h>
#include <QtCore/qhash.h>
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qeventloop.h>
+#include <QtCore/qmutex.h>
#include <dbus/dbus.h>
+#include "qdbusmessage.h"
+#include "qdbusintrospection.h"
+
class QDBusMessage;
class QSocketNotifier;
class QTimerEvent;
+class QDBusObjectPrivate;
+class CallDeliveryEvent;
typedef struct DBusConnection;
typedef struct DBusServer;
@@ -56,6 +66,43 @@
{
Q_OBJECT
public:
+ // structs and enums
+ enum ConnectionMode { InvalidMode, ServerMode, ClientMode };
+
+ struct Watcher
+ {
+ Watcher(): watch(0), read(0), write(0) {}
+ DBusWatch *watch;
+ QSocketNotifier *read;
+ QSocketNotifier *write;
+ };
+
+ struct SignalHook
+ {
+ QString interface, name, signature;
+ QPointer<QObject> obj;
+ int midx;
+ QList<int> params;
+ };
+
+ struct ObjectData
+ {
+ QPointer<QObject> obj;
+ int flags;
+ };
+
+public:
+ // typedefs
+ typedef QMultiHash<int, Watcher> WatcherHash;
+ typedef QHash<int, DBusTimeout *> TimeoutHash;
+ typedef QMultiHash<QString, SignalHook> SignalHookHash;
+ typedef QHash<QString, ObjectData> ObjectDataHash;
+ typedef QHash<QString, ObjectDataHash> ObjectHookHash;
+ typedef QHash<QString, QSharedDataPointer<QDBusIntrospection::Interface> > KnownInterfacesHash;
+ typedef QHash<QString, QDBusIntrospection::Object* > KnownObjectsHash;
+
+public:
+ // public methods
QDBusConnectionPrivate(QObject *parent = 0);
~QDBusConnectionPrivate();
@@ -66,66 +113,81 @@
void closeConnection();
void timerEvent(QTimerEvent *e);
- bool handleSignal(DBusMessage *msg) const;
- bool handleObjectCall(DBusMessage *message) const;
+ bool handleSignal(const QString &path, const QDBusMessage &msg);
+ bool send(const QDBusMessage &message) const;
+ int sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
+ const char *method) const;
+
+ bool handleSignal(const QDBusMessage &msg);
+ bool handleObjectCall(const QDBusMessage &message);
bool handleError();
+ void disposeOfLocked(QDBusIntrospection::Object* obj);
+ void disposeOf(QDBusObjectPrivate* obj);
+ QSharedDataPointer<QDBusIntrospection::Interface> findInterface(const QString& name);
+ QDBusIntrospection::Object* findObject(const QString& service,
+ const QString& path);
+
+ bool activateReply(QObject *object, int idx, const QList<int>& metaTypes,
+ const QDBusMessage &msg);
+ bool activateSignal(const SignalHook& hook, const QDBusMessage &msg);
+ bool activateCall(QObject* object, int flags, const QDBusMessage &msg);
+ bool activateAdaptor(QObject *object, int flags, const QDBusMessage &msg);
+ bool activateObject(const ObjectData& data, const QDBusMessage &msg);
+ void deliverCall(const CallDeliveryEvent &data) const;
+
+protected:
+ virtual void customEvent(QEvent *event);
+
public slots:
+ // public slots
void socketRead(int);
void socketWrite(int);
void objectDestroyed(QObject *o);
public:
+ // public member variables
DBusError error;
QDBusError lastError;
- enum ConnectionMode { InvalidMode, ServerMode, ClientMode };
-
QAtomic ref;
+ QMutex mutex;
ConnectionMode mode;
DBusConnection *connection;
DBusServer *server;
- static int messageMetaType;
- static int registerMessageMetaType();
- bool handleSignal(const QString &path, const QDBusMessage &msg) const;
- int sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
- const char *method) const;
-
- struct Watcher
- {
- Watcher(): watch(0), read(0), write(0) {}
- DBusWatch *watch;
- QSocketNotifier *read;
- QSocketNotifier *write;
- };
- typedef QMultiHash<int, Watcher> WatcherHash;
WatcherHash watchers;
-
- typedef QHash<int, DBusTimeout *> TimeoutHash;
TimeoutHash timeouts;
-
- struct SignalHook
- {
- QString interface, name;
- QPointer<QObject> obj;
- int midx;
- QVarLengthArray<int, 10> params;
-
- bool setSlot(const char *slotName);
- };
-
- typedef QMultiHash<QString, SignalHook> SignalHookHash;
SignalHookHash signalHooks;
-
- struct ObjectHook
- {
- QString interface;
- QPointer<QObject> obj;
- };
- typedef QMultiHash<QString, ObjectHook> ObjectHookHash;
ObjectHookHash objectHooks;
QList<DBusTimeout *> pendingTimeouts;
+
+public:
+ // public mutable member variables
+ mutable KnownInterfacesHash knownInterfaces;
+ mutable KnownObjectsHash knownObjects;
+
+public:
+ // static methods
+ static int messageMetaType;
+ static int registerMessageMetaType();
+ static int findSlot(QObject *obj, const char *slotName, QList<int>& params);
};
+class QDBusReplyWaiter: public QEventLoop
+{
+ Q_OBJECT
+public:
+ QDBusMessage replyMsg;
+
+#ifndef QT_NO_DEBUG
+ int level;
+ int exec(ProcessEventsFlags flags);
+ void exit(int = 0);
+#endif
+
+public slots:
+ void reply(const QDBusMessage &msg);
+};
+
#endif
Index: qdbuserror.cpp
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbuserror.cpp,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- qdbuserror.cpp 23 Sep 2005 13:08:26 -0000 1.1
+++ qdbuserror.cpp 15 Feb 2006 16:25:12 -0000 1.2
@@ -1,6 +1,8 @@
/* qdbuserror.h QDBusError object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
@@ -15,16 +17,17 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, write to the Free Software Foundation
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbuserror.h"
-#include <QtCore/qdebug.h>
+#include <qdebug.h>
#include <dbus/dbus.h>
+#include "qdbusmessage.h"
QDBusError::QDBusError(const DBusError *error)
{
@@ -35,6 +38,16 @@
msg = QString::fromUtf8(error->message);
}
+QDBusError::QDBusError(const QDBusMessage &qdmsg)
+{
+ if (qdmsg.type() != QDBusMessage::ErrorMessage)
+ return;
+
+ nm = qdmsg.name();
+ if (qdmsg.count())
+ msg = qdmsg[0].toString();
+}
+
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const QDBusError &msg)
{
Index: qdbuserror.h
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbuserror.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- qdbuserror.h 23 Sep 2005 16:24:36 -0000 1.2
+++ qdbuserror.h 15 Feb 2006 16:25:12 -0000 1.3
@@ -1,6 +1,8 @@
/* qdbuserror.h QDBusError object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
@@ -15,23 +17,25 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, write to the Free Software Foundation
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSERROR_H
#define QDBUSERROR_H
-#include "dbus/qdbus.h"
+#include "qdbusmacros.h"
#include <QtCore/qstring.h>
struct DBusError;
+class QDBusMessage;
class QDBUS_EXPORT QDBusError
{
public:
QDBusError(const DBusError *error = 0);
+ QDBusError(const QDBusMessage& msg);
inline QString name() const { return nm; }
inline QString message() const { return msg; }
Index: qdbusintegrator.cpp
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusintegrator.cpp,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- qdbusintegrator.cpp 23 Sep 2005 13:08:26 -0000 1.1
+++ qdbusintegrator.cpp 15 Feb 2006 16:25:12 -0000 1.2
@@ -1,6 +1,8 @@
/* qdbusintegrator.cpp QDBusConnection private implementation
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
@@ -15,22 +17,54 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, write to the Free Software Foundation
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qcoreevent.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qmetaobject.h>
-#include <QtCore/qsocketnotifier.h>
+#include <qcoreapplication.h>
+#include <qcoreevent.h>
+#include <qdebug.h>
+#include <qmetaobject.h>
+#include <qsocketnotifier.h>
+#include <qcoreevent.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"
int QDBusConnectionPrivate::messageMetaType = 0;
+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;
+ bool generateReply : 1;
+};
+
static dbus_bool_t qDBusAddTimeout(DBusTimeout *timeout, void *data)
{
Q_ASSERT(timeout);
@@ -103,6 +137,7 @@
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)));
}
}
@@ -111,6 +146,7 @@
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)));
}
}
@@ -188,168 +224,560 @@
bool handled = false;
QDBusMessage amsg = QDBusMessage::fromDBusMessage(message);
- qDebug() << "got message: " << dbus_message_get_type(message) << amsg;
+ qDebug() << "got message:" << amsg;
if (msgType == DBUS_MESSAGE_TYPE_SIGNAL) {
- handled = d->handleSignal(message);
+ handled = d->handleSignal(amsg);
} else if (msgType == DBUS_MESSAGE_TYPE_METHOD_CALL) {
- handled = d->handleObjectCall(message);
+ handled = d->handleObjectCall(amsg);
}
return handled ? DBUS_HANDLER_RESULT_HANDLED :
DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
-static bool qInvokeDBusSlot(const QDBusConnectionPrivate::SignalHook& hook, const QDBusMessage &msg)
+static bool checkAsyncTag(const char *tag)
{
- int count = msg.count();
- if (!(count == hook.params.count()
- || (count + 1 == hook.params.count()
- && hook.params[count] == QDBusConnectionPrivate::messageMetaType)))
+ if (!tag || !*tag)
return false;
- QVarLengthArray<void *, 16> params;
- params.append(0); // return value
- for (int i = 0; i < msg.count(); ++i) {
- const QVariant &v = msg.at(i);
- if (int(v.type()) != hook.params[i]) {
- return false;
- }
- params.append(const_cast<void *>(v.constData()));
+ const char *p = strstr(tag, "async");
+ if (p != NULL &&
+ (p == tag || *(p-1) == ' ') &&
+ (p[6] == '\0' || p[6] == ' '))
+ return true;
+
+ p = strstr(tag, "Q_ASYNC");
+ if (p != NULL &&
+ (p == tag || *(p-1) == ' ') &&
+ (p[8] == '\0' || p[8] == ' '))
+ 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;
}
- if (count + 1 == hook.params.count())
- params.append(const_cast<QDBusMessage *>(&msg));
- return hook.obj->qt_metacall(QMetaObject::InvokeMetaMethod, hook.midx, params.data()) < 0;
+ return retval;
}
-static bool qInvokeDBusSlot(QObject *object, int idx, const QDBusMessage &msg)
+static bool typesMatch(int metaId, QVariant::Type variantType)
{
- Q_ASSERT(object);
+ if (metaId == (int)variantType)
+ return true;
- const QMetaMethod method = object->metaObject()->method(idx);
- if (!method.signature())
- return false;
+ if (variantType == QVariant::Int && metaId == QMetaType::Short)
+ return true;
- QVarLengthArray<void *> params;
- params.append(0); // ### return type
+ if (variantType == QVariant::UInt && (metaId == QMetaType::UShort ||
+ metaId == QMetaType::UChar))
+ return true;
- QList<QByteArray> parameterTypes = method.parameterTypes();
+ return false; // no match
+}
- // check parameters, the slot should have <= parameters than the message
- // also allow the QDBusMessage itself as last parameter slot
- if ((parameterTypes.count() > msg.count())
- || (parameterTypes.count() + 1 != msg.count())
- && parameterTypes.last() != "QDBusMessage") {
- qWarning("Cannot deliver asynchronous reply to object named '%s' because of parameter "
- "mismatch. Please check your sendWithReplyAsync() statements.",
- object->objectName().toLocal8Bit().constData());
- return false;
+static int returnTypeId(const char *name)
+{
+ if (!name || !*name)
+ return QMetaType::Void;
+
+ // force normalizedSignature to work for us
+ QVarLengthArray<char, 32> buf(strlen(name) + 3);
+ buf.append("_(", 2);
+ buf.append(name, strlen(name));
+ buf.append(')');
+
+ QByteArray normalized = QMetaObject::normalizedSignature( buf.data() );
+ normalized.truncate(normalized.length() - 1);
+ return QMetaType::type(normalized.constData() + 2);
+}
+
+static int typeId(const char *type)
+{
+ int id = static_cast<int>( QVariant::nameToType(type) );
+ if (id == QVariant::UserType)
+ id = QMetaType::type(type);
+
+ switch (id) {
+ case QVariant::Bool:
+ case QVariant::Int:
+ case QVariant::UInt:
+ case QVariant::Char:
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ case QMetaType::UChar:
+ case QVariant::LongLong:
+ case QVariant::ULongLong:
+ case QVariant::Double:
+ case QVariant::String:
+ case QVariant::Date:
+ case QVariant::Time:
+ case QVariant::DateTime:
+ case QVariant::Map:
+ case QVariant::StringList:
+ case QVariant::ByteArray:
+ case QVariant::List:
+ return id;
+
+ default:
+ if (id == qMetaTypeId<QDBusVariant>() || id == QDBusConnectionPrivate::messageMetaType)
+ return id;
+
+ return 0; // invalid
}
+}
+
- int i;
- for (i = 0; i < parameterTypes.count(); ++i) {
- const QByteArray param = parameterTypes.at(i);
- if (param == msg.at(i).typeName()) {
- params.append(const_cast<void *>(msg.at(i).constData()));
- } else if (i == parameterTypes.count() - 1 && param == "QDBusMessage") {
- params.append(const_cast<void *>(static_cast<const void *>(&msg)));
- } else {
- qWarning("Parameter mismatch while delivering message, expected '%s', got '%s'",
- msg.at(i).typeName(), param.constData());
- return false;
+// calculates the metatypes for the method
+// the slot must have the parameters in the following form:
+// - zero or more value or const-ref parameters of any kind
+// - zero or one const ref of QDBusMessage
+// - zero or more non-const ref parameters
+// No parameter may be a template.
+// this function returns -1 if the parameters don't match the above form
+// this function returns the number of *input* parameters, including the QDBusMessage one if any
+// this function does not check the return type, so metaTypes[0] is always 0 and always present
+// metaTypes.count() >= retval + 1 in all cases
+//
+// sig must be the normalised signature for the method
+static int parametersForMethod(const QByteArray &sig, 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);
+ metaTypes.clear();
+
+ metaTypes.append(0); // return type
+ int inputCount = 0;
+ bool seenMessage = false;
+ foreach (QByteArray type, parameterTypes) {
+ if (type.endsWith('*')) {
+ qWarning("Could not parse the method '%s'", sig.constData());
+ // pointer?
+ return -1;
}
+
+ if (type.endsWith('&')) {
+ type.truncate(type.length() - 1);
+ int id = typeId(type);
+ if (id == 0) {
+ qWarning("Could not parse the method '%s'", sig.constData());
+ // invalid type in method parameter list
+ return -1;
+ }
+
+ metaTypes.append( id );
+
+ if (metaTypes.last() == 0) {
+ qWarning("Could not parse the method '%s'", sig.constData());
+ // void?
+ return -1;
+ }
+
+ continue;
+ }
+
+ if (seenMessage) { // && !type.endsWith('&')
+ qWarning("Could not parse the method '%s'", sig.constData());
+ // non-output parameters after message or after output params
+ return -1; // not allowed
+ }
+
+ int id = typeId(type);
+ if (id == 0) {
+ qWarning("Could not parse the method '%s'", sig.constData());
+ // invalid type in method parameter list
+ return -1;
+ }
+ metaTypes.append(id);
+ ++inputCount;
+
+ if (id == QDBusConnectionPrivate::messageMetaType)
+ seenMessage = true;
}
- return object->qt_metacall(QMetaObject::InvokeMetaMethod, idx, params.data()) < 0;
+
+ return inputCount;
}
-static bool qInvokeDBusSlot(QObject *object, QDBusMessage *msg)
+static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags,
+ const QDBusTypeList &types, QList<int>& metaTypes, bool &isAsync, int &msgPos)
{
- Q_ASSERT(object);
- Q_ASSERT(msg);
+ // find the first slot
+ const QMetaObject *super = mo;
+ while (qstrcmp(super->className(), "QObject") != 0 &&
+ qstrcmp(super->className(), "QDBusAbstractAdaptor") != 0)
+ super = super->superClass();
+
+ int attributeMask = (flags & QDBusConnection::ExportNonScriptableSlots) ?
+ 0 : QMetaMethod::Scriptable;
- const QMetaObject *mo = object->metaObject();
- QVarLengthArray<void *> params;
- params.append(0); // ### return type
+ for (int idx = super->methodCount() ; idx <= mo->methodCount(); ++idx) {
+ QMetaMethod mm = mo->method(idx);
- /* Try to find a slot with all args and the QDBusMessage */
- QByteArray slotName = msg->name().toUtf8(); // QVarLengthArray?
- slotName.append("(");
- for (int i = 0; i < msg->count(); ++i) {
- slotName.append(msg->at(i).typeName()).append(",");
- params.append(const_cast<void *>(msg->at(i).constData()));
- }
- slotName.append("QDBusMessage)");
+ // check access:
+ if (mm.access() != QMetaMethod::Public)
+ continue;
- int idx = mo->indexOfSlot(slotName.constData());
- if (idx >= 0) {
- params.append(msg);
- return object->qt_metacall(QMetaObject::InvokeMetaMethod, idx, params.data()) < 0;
- }
+ // check type:
+ // unnecessary, since slots are never public:
+ //if (mm.methodType() != QMetaMethod::Slot)
+ // continue;
- /* Try to find only args, without the QDBusMessage */
- slotName.chop(13);
- slotName[slotName.count() - 1] = ')';
+ // check name:
+ QByteArray sig = QMetaObject::normalizedSignature(mm.signature());
+ int paren = sig.indexOf('(');
+ if (paren != name.length() || !sig.startsWith( name ))
+ continue;
- idx = mo->indexOfSlot(slotName.constData());
- if (idx >= 0 && (mo->method(idx).attributes() & QMetaMethod::Scriptable))
- return object->qt_metacall(QMetaObject::InvokeMetaMethod, idx, params.data()) < 0;
+ int returnType = returnTypeId(mm.typeName());
+ isAsync = checkAsyncTag(mm.tag());
- /* Try to find a slot with only QDBusMessage */
- slotName = msg->name().toUtf8();
- slotName.append("(QDBusMessage)");
+ // consistency check:
+ if (isAsync && returnType != QMetaType::Void)
+ continue;
- idx = mo->indexOfSlot(slotName.constData());
- if (idx >= 0)
- return QMetaObject::invokeMethod(object, msg->name().toUtf8().constData(),
- Q_ARG(QDBusMessage, *msg));
+ int inputCount = parametersForMethod(sig, metaTypes);
+ if (inputCount == -1)
+ continue; // problem parsing
- return false;
+ metaTypes[0] = returnType;
+ msgPos = 0;
+ if (inputCount > 0 &&
+ metaTypes.at(inputCount) == QDBusConnectionPrivate::messageMetaType) {
+ // no input parameters is allowed as long as the message meta type is there
+ msgPos = inputCount;
+ --inputCount;
+ }
+
+ if (inputCount) {
+ // try to match the parameters
+ if (inputCount < types.count())
+ continue; // not enough parameters
+
+ bool matches = true;
+ int i;
+ for (i = 0; i < types.count(); ++i)
+ if ( !typesMatch(metaTypes.at(i + 1), types.at(i).qvariantType()) ) {
+ matches = false;
+ break;
+ }
+
+ if (!matches)
+ continue; // we didn't match them all
+
+ // consistency check:
+ if (isAsync && metaTypes.count() > i + 1)
+ continue;
+ }
+
+ if (!msgPos && (mm.attributes() & attributeMask) != attributeMask)
+ continue; // not exported
+
+ // if we got here, this slot matched
+ return idx;
+ }
+
+ // no slot matched
+ return -1;
+}
+
+bool QDBusConnectionPrivate::activateSignal(const QDBusConnectionPrivate::SignalHook& hook,
+ const QDBusMessage &msg)
+{
+ // This is called by QDBusConnectionPrivate::handleSignal to deliver a signal
+ // that was received from D-Bus
+ //
+ // Signals are delivered to slots if the parameters match
+ // Slots can have less parameters than there are on the message
+ // Slots can optionally have one final parameter that is a QDBusMessage
+ // Slots receive read-only copies of the message (i.e., pass by value or by const-ref)
+ return activateReply(hook.obj, hook.midx, hook.params, msg);
}
-int QDBusConnectionPrivate::registerMessageMetaType()
+bool QDBusConnectionPrivate::activateReply(QObject *object, int idx, const QList<int> &metaTypes,
+ const QDBusMessage &msg)
{
- int tp = messageMetaType = qRegisterMetaType<QDBusMessage>("QDBusMessage");
- return tp;
+ // This is called by qDBusResultReceived and is used to deliver the return value
+ // 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)
+ Q_ASSERT(object);
+
+ int n = metaTypes.count() - 1;
+ if (metaTypes[n] == QDBusConnectionPrivate::messageMetaType)
+ --n;
+
+ // check that types match
+ for (int i = 0; i < n; ++i)
+ if (!typesMatch(metaTypes.at(i + 1), msg.at(i).type()))
+ return false; // no match
+
+ // we can deliver
+ // prepare for the call
+ CallDeliveryEvent *data = new CallDeliveryEvent;
+ data->conn = this;
+ data->object = object;
+ data->flags = 0;
+ data->message = msg;
+ data->metaTypes = metaTypes;
+ data->slotIdx = idx;
+ data->generateReply = false;
+
+ QCoreApplication::postEvent( this, data );
+
+ return true;
}
-bool QDBusConnectionPrivate::SignalHook::setSlot(const char *slotName)
+bool QDBusConnectionPrivate::activateCall(QObject* object, int flags,
+ const QDBusMessage &msg)
{
- Q_ASSERT(static_cast<QObject *>(obj)); Q_ASSERT(slotName);
+ // This is called by QDBusConnectionPrivate::handleObjectCall to place a call
+ // to a slot on the object.
+ //
+ // The call is delivered to the first slot that matches the following conditions:
+ // - has the same name as the message's target name
+ // - ALL of the message's types are found in slot's parameter list
+ // - optionally has one more parameter of type QDBusMessage
+ // If none match, then the slot of the same name as the message target and with
+ // the first type of QDBusMessage is delivered.
+ //
+ // Because the marshalling of D-Bus data into QVariant loses the information on
+ // the original types, the message signature is used to determine the original type.
+ // Aside from that, the "int" and "unsigned" types will be tried as well.
+ //
+ // Return message handling depends on whether the asynchronous tag ("async" or "Q_ASYNC")
+ // tag is found, whether the slot takes a QDBusMessage parameter and whether there are
+ // return values (non-const reference parameters or a return type).
+ // The table indicates the possibilities:
+ // async QDBusMessage parameter return values return message generated
+ // yes irrelevant irrelevant no
+ // no irrelevant yes yes
+ // no yes no no
+ // no no no yes
+ //
+ // When a return message is generated, the slot's return type, if any, will be placed
+ // in the message's first position. If there are non-const reference parameters to the
+ // slot, they must appear at the end and will be placed in the subsequent message
+ // positions.
+
+ Q_ASSERT(object);
- QByteArray normalizedName = QMetaObject::normalizedSignature(slotName);
- const QMetaObject *mo = obj->metaObject();
- midx = mo->indexOfMethod(normalizedName.constData());
- if (midx < 0)
- return false;
+ QList<int> metaTypes;
+ int idx;
+ bool isAsync;
+ int msgPos;
+
+ {
+ const QMetaObject *mo = object->metaObject();
+ QDBusTypeList typeList(msg.signature().toUtf8());
- const QList<QByteArray> ptypes = mo->method(midx).parameterTypes();
- for (int i = 0; i < ptypes.count(); ++i) {
- int t = QVariant::nameToType(ptypes.at(i).constData());
- if (t == QVariant::UserType)
- t = QMetaType::type(ptypes.at(i).constData());
- if (t == QVariant::Invalid)
+ // find a slot that matches according to the rules above
+ idx = ::findSlot(mo, msg.name().toUtf8(), flags, typeList, metaTypes, isAsync, msgPos);
+ if (idx == -1)
+ // no match
return false;
- params.append(t);
}
+ bool generateReply;
+ if (isAsync)
+ generateReply = false;
+ else if (metaTypes[0] != QMetaType::Void)
+ generateReply = true;
+ else {
+ if (msgPos != 0)
+ // generate a reply if there are more parameters past QDBusMessage
+ generateReply = metaTypes.count() > msgPos + 1;
+ else
+ // generate a reply if there are more parameters than input parameters
+ generateReply = metaTypes.count() > msg.count() + 1;
+ }
+
+ // found the slot to be called
+ // prepare for the call:
+ CallDeliveryEvent *call = new CallDeliveryEvent;
+ call->conn = this;
+
+ // parameters:
+ call->object = object;
+ call->flags = flags;
+ call->message = msg;
+
+ // save our state:
+ call->metaTypes = metaTypes;
+ call->slotIdx = idx;
+ call->generateReply = generateReply;
+
+ QCoreApplication::postEvent( this, call );
+
+ // ready
return true;
}
+void QDBusConnectionPrivate::deliverCall(const CallDeliveryEvent& data) const
+{
+ // resume state:
+ const QList<int>& metaTypes = data.metaTypes;
+ const QDBusMessage& msg = data.message;
+
+ QVarLengthArray<void *, 10> params;
+ params.reserve(metaTypes.count());
+
+#if __BYTE_ORDER != __LITTLE_ENDIAN
+ union integer
+ {
+ short s;
+ unsigned short us;
+ unsigned char uc;
+ }
+ QVarLengthArray<integer, 4> auxParameters;
+#endif
+ // let's create the parameter list
+
+ // first one is the return type -- add it below
+ params.append(0);
+
+ // add the input parameters
+ int i;
+ for (i = 0; i < msg.count(); ++i) {
+ int id = metaTypes[i + 1];
+ if (id == QDBusConnectionPrivate::messageMetaType)
+ break;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ params.append(const_cast<void *>( msg.at(i).constData() ));
+#else
+ if (id == msg.at(i).type())
+ params.append(const_cast<void *>( msg.at(i).constData() ));
+ else {
+ // need some help
+ integer aux;
+ const QVariant &var = msg.at(i);
+ 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()] );
+ }
+#endif
+ }
+
+ bool takesMessage = false;
+ if (metaTypes.count() > i + 1 && metaTypes[i + 1] == QDBusConnectionPrivate::messageMetaType) {
+ 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);
+ params.append( arg.data() );
+ outputArgs.append( arg );
+ }
+ for ( ; i < metaTypes.count(); ++i) {
+ QVariant arg(metaTypes[i], null);
+ params.append( arg.data() );
+ outputArgs.append( arg );
+ }
+
+ // make call:
+ bool fail;
+ if (data.object.isNull())
+ fail = true;
+ else
+ fail = data.object->qt_metacall(QMetaObject::InvokeMetaMethod,
+ data.slotIdx, params.data()) >= 0;
+
+ // do we create a reply?
+ if (data.generateReply) {
+ if (!fail) {
+ // yes
+ QDBusMessage reply = QDBusMessage::methodReply(msg);
+ reply += outputArgs;
+
+ qDebug() << "Automatically sending reply:" << reply;
+ send(reply);
+ }
+ else {
+ // generate internal error
+ QDBusMessage reply = QDBusMessage::error(msg, "com.trolltech.QtDBus.InternalError",
+ "Failed to deliver message");
+ qDebug("Internal error: Failed to deliver message");
+ send(reply);
+ }
+ }
+
+ return;
+}
+
+void QDBusConnectionPrivate::customEvent(QEvent *event)
+{
+ // nothing else should be sending custom events at us
+ CallDeliveryEvent* call = static_cast<CallDeliveryEvent *>(event);
+
+ // self check:
+ Q_ASSERT(call->conn == this);
+
+ deliverCall(*call);
+}
+
QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *parent)
: QObject(parent), ref(1), mode(InvalidMode), connection(0), server(0)
{
+ extern bool qDBusInitThreads();
static const int msgType = registerMessageMetaType();
+ static const bool threads = qDBusInitThreads();
+
Q_UNUSED(msgType);
+ Q_UNUSED(threads);
dbus_error_init(&error);
}
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);
+ }
}
void QDBusConnectionPrivate::closeConnection()
@@ -413,7 +841,6 @@
}
if (mode == ClientMode)
while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS);
- // ### break out of loop?
}
void QDBusConnectionPrivate::socketWrite(int fd)
@@ -432,11 +859,20 @@
{
ObjectHookHash::iterator it = objectHooks.begin();
while (it != objectHooks.end()) {
- if (static_cast<QObject *>(it.value().obj) == obj)
+ ObjectDataHash::iterator dit = it->begin();
+ while (dit != it->end()) {
+ if (static_cast<QObject *>(dit.value().obj) == obj)
+ dit = it->erase(dit);
+ else
+ ++dit;
+ }
+
+ if (it->isEmpty())
it = objectHooks.erase(it);
else
++it;
}
+
SignalHookHash::iterator sit = signalHooks.begin();
while (sit != signalHooks.end()) {
if (static_cast<QObject *>(sit.value().obj) == obj)
@@ -447,56 +883,135 @@
obj->disconnect(this);
}
-bool QDBusConnectionPrivate::handleObjectCall(DBusMessage *message) const
+bool QDBusConnectionPrivate::activateAdaptor(QObject* object, int flags,
+ const QDBusMessage &msg)
{
- QDBusMessage msg = QDBusMessage::fromDBusMessage(message);
+ // This is called by QDBusConnectionPrivate::handleObjectCall to place a call to a slot
+ // on the object.
+ //
+ // The call is routed through the adaptor sub-objects
- ObjectHook hook;
- ObjectHookHash::ConstIterator it = objectHooks.find(msg.path());
- while (it != objectHooks.constEnd() && it.key() == msg.path()) {
- if (it.value().interface == msg.interface()) {
- hook = it.value();
- break;
- } else if (it.value().interface.isEmpty()) {
- hook = it.value();
+ Q_ASSERT(object);
+ flags |= QDBusConnection::ExportNonScriptableSlots;
+
+ const QObjectList& children = object->children();
+ QObjectList::const_iterator child = children.begin(),
+ end = children.end();
+ for ( ; child != end; ++child) {
+ // check if this is an adaptor
+ if (!qobject_cast<QDBusAbstractAdaptor *>(*child))
+ continue; // not adaptor
+
+ const QMetaObject *mo = (*child)->metaObject();
+ int ciend = mo->classInfoCount();
+ for (int i = 0; i < ciend; ++i) {
+ QMetaClassInfo mci = mo->classInfo(i);
+ if (strcmp(mci.name(), "DBus Interface") == 0 && *mci.value()) {
+ // one interface.
+ // is this it?
+ if (msg.interface().isEmpty() || msg.interface() == mci.value())
+ return activateCall(*child, flags, msg);
+ }
}
- ++it;
}
+ return false;
+}
- if (!hook.obj) {
- qDebug("NO OBJECT for %s", msg.path().toLocal8Bit().constData());
- return false;
+int QDBusConnectionPrivate::registerMessageMetaType()
+{
+ int tp = messageMetaType = qRegisterMetaType<QDBusMessage>("QDBusMessage");
+ return tp;
+}
+
+int QDBusConnectionPrivate::findSlot(QObject* obj, const char *slotName, QList<int>& params)
+{
+ Q_ASSERT(slotName);
+ QByteArray normalizedName = QMetaObject::normalizedSignature(slotName);
+ int midx = obj->metaObject()->indexOfMethod(normalizedName);
+ if (midx == -1) {
+ qWarning("No such slot '%s' while connecting D-Bus", slotName);
+ return -1;
}
- if (!qInvokeDBusSlot(hook.obj, &msg)) {
- qDebug("NO SUCH SLOT: %s(QDBusMessage)", msg.name().toLocal8Bit().constData());
+ int inputCount = parametersForMethod(normalizedName, params);
+ if ( inputCount == -1 || inputCount + 1 != params.count() )
+ return -1; // failed to parse or invalid arguments or output arguments
+
+ return midx;
+}
+
+bool QDBusConnectionPrivate::activateObject(const QDBusConnectionPrivate::ObjectData &hook,
+ const QDBusMessage &msg)
+{
+ if (!hook.obj)
+ return false; // object is gone
+
+ if (hook.flags & QDBusConnection::ExportAdaptors)
+ return activateAdaptor(hook.obj, hook.flags, msg);
+ else
+ return activateCall(hook.obj, hook.flags, msg);
+}
+
+bool QDBusConnectionPrivate::handleObjectCall(const QDBusMessage &msg)
+{
+ ObjectHookHash::ConstIterator it = objectHooks.find(msg.path());
+ if (it == objectHooks.constEnd())
return false;
+
+ bool ok = false;
+ const ObjectDataHash& hook = it.value();
+ ObjectDataHash::ConstIterator hit;
+ if (msg.interface().isEmpty()) {
+ // we must go through all the objects and interfaces
+
+ for (hit = hook.begin(); hit != hook.end(); ++hit) {
+ ok = activateObject(hit.value(), msg);
+ if (ok)
+ break; // processed
+ }
+ } else {
+ // find the interface:
+ hit = hook.find(msg.interface());
+ if (hit != hook.end())
+ ok = activateObject(hit.value(), msg);
+
+ if (!ok) {
+ // try adaptors (or any interface)
+ hit = hook.find(QString());
+ if (hit != hook.end())
+ ok = activateObject(hit.value(), msg);
+ }
}
- return true;
+ qDebug(ok ? "Call scheduled" : "Call failed");
+ return ok;
}
-bool QDBusConnectionPrivate::handleSignal(const QString &path, const QDBusMessage &msg) const
+bool QDBusConnectionPrivate::handleSignal(const QString &path, const QDBusMessage &msg)
{
SignalHookHash::const_iterator it = signalHooks.find(path);
qDebug("looking for: %s", path.toLocal8Bit().constData());
qDebug() << signalHooks.keys();
- while (it != signalHooks.constEnd() && it.key() == path) {
+ for ( ; it != signalHooks.constEnd() && it.key() == path; ++ it) {
const SignalHook &hook = it.value();
- if ((hook.name.isEmpty() || hook.name == msg.name())
- && (hook.interface.isEmpty() || hook.interface == msg.interface()))
- qInvokeDBusSlot(hook, msg);
- ++it;
+ if ( hook.obj.isNull() )
+ continue;
+ if ( !hook.name.isEmpty() && hook.name != msg.name() )
+ continue;
+ if ( !hook.interface.isEmpty() && hook.interface != msg.interface() )
+ continue;
+ if ( !hook.signature.isEmpty() && hook.signature != msg.signature() )
+ continue;
+
+ activateSignal(hook, msg);
}
return true;
}
-bool QDBusConnectionPrivate::handleSignal(DBusMessage *message) const
+bool QDBusConnectionPrivate::handleSignal(const QDBusMessage& msg)
{
- QDBusMessage msg = QDBusMessage::fromDBusMessage(message);
-
// yes, it is a single "|" below...
- return handleSignal(QString(), msg) | handleSignal(msg.path(), msg);
+ return handleSignal(QString(), msg) | handleSignal(msg.sender() + msg.path(), msg);
}
static dbus_int32_t server_slot = -1;
@@ -569,53 +1084,152 @@
qDebug("base service: %s", service);
}
-struct QDBusPendingCall
-{
- QPointer<QObject> receiver;
- int methodIdx;
- DBusPendingCall *pending;
-};
-
static void qDBusResultReceived(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);
- qInvokeDBusSlot(call->receiver, call->methodIdx, QDBusMessage::fromDBusMessage(reply));
+ connection->activateReply(call->receiver, call->methodIdx, call->metaTypes,
+ QDBusMessage::fromDBusMessage(reply));
}
dbus_pending_call_unref(pending);
delete call;
}
+bool QDBusConnectionPrivate::send(const QDBusMessage& message) const
+{
+ DBusMessage *msg = message.toDBusMessage();
+ if (!msg)
+ return false;
+
+ dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything
+
+ qDebug() << "sending message:" << message;
+ bool isOk = dbus_connection_send(connection, msg, 0);
+ dbus_message_unref(msg);
+ return isOk;
+}
+
int QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
- const char *method) const
+ const char *method) const
{
DBusMessage *msg = message.toDBusMessage();
if (!msg)
return 0;
int slotIdx = -1;
- if (receiver && method && *method) {
- QByteArray normalized = QMetaObject::normalizedSignature(method + 1);
- slotIdx = receiver->metaObject()->indexOfMethod(normalized.constData());
- if (slotIdx == -1)
- qWarning("QDBusConnection::sendWithReplyAsync: no such method: '%s'",
- normalized.constData());
- }
+ QList<int> metaTypes;
+ if (receiver && method && *method)
+ slotIdx = findSlot(receiver, method + 1, metaTypes);
+ qDebug() << "sending message:" << message;
DBusPendingCall *pending = 0;
if (dbus_connection_send_with_reply(connection, msg, &pending, message.timeout())) {
if (slotIdx != -1) {
QDBusPendingCall *pcall = new QDBusPendingCall;
pcall->receiver = receiver;
+ pcall->metaTypes = metaTypes;
pcall->methodIdx = slotIdx;
+ pcall->connection = this;
pcall->pending = dbus_pending_call_ref(pending);
dbus_pending_call_set_notify(pending, qDBusResultReceived, pcall, 0);
}
+ dbus_pending_call_unref(pending);
return dbus_message_get_serial(msg);
}
return 0;
}
+
+QSharedDataPointer<QDBusIntrospection::Interface>
+QDBusConnectionPrivate::findInterface(const QString& name)
+{
+ QMutexLocker locker(&mutex);
+ 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);
+ }
+ return data;
+}
+
+QDBusIntrospection::Object*
+QDBusConnectionPrivate::findObject(const QString& service, const QString& path)
+{
+ QMutexLocker locker(&mutex);
+ QDBusIntrospection::Object* data = knownObjects.value(service + path);
+ if (!data) {
+ data = new QDBusIntrospection::Object;
+ data->service = service;
+ data->path = path;
+
+ knownObjects.insert(service + path, data);
+ }
+
+ return data;
+}
+
+void QDBusConnectionPrivate::disposeOfLocked(QDBusIntrospection::Object* p)
+{
+ 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
+
+ // remove sub-objects too
+ if (!objName.endsWith('/'))
+ objName.append('/');
+ foreach (QString subObjName, p->childObjects)
+ disposeOfLocked(knownObjects.value(objName + subObjName));
+
+ delete p;
+ }
+}
+
+void QDBusConnectionPrivate::disposeOf(QDBusObjectPrivate* p)
+{
+ // We're called from QDBusConnectionPrivate's destructor
+ // that means the object it represents is going out of scope
+
+ QMutexLocker locker(&mutex);
+ disposeOfLocked( const_cast<QDBusIntrospection::Object*>(p->data) );
+}
+
+#ifndef QT_NO_DEBUG
+int QDBusReplyWaiter::exec(QEventLoop::ProcessEventsFlags flags)
+{
+ static int eventlevel;
+ level = ++eventlevel;
+ qDebug("QDBusReplyWaiter::exec %p level %d starting", this, level);
+ int retcode = QEventLoop::exec(flags);
+ qDebug("QDBusReplyWaiter::exec %p level %d exiting", this, level);
+ --eventlevel;
+ return retcode;
+}
+
+void QDBusReplyWaiter::exit(int retcode)
+{
+ qDebug("QDBusReplyWaiter::exit %p level %d called", this, level);
+ QEventLoop::exit(retcode);
+}
+#endif
+
+void QDBusReplyWaiter::reply(const QDBusMessage &msg)
+{
+ replyMsg = msg;
+ QTimer::singleShot(0, this, SLOT(quit()));
+}
--- NEW FILE: qdbusinterface.cpp ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbusinterface.h"
#include "qdbusobject.h"
#include "qdbusstandardinterfaces.h"
#include "qdbusinterface_p.h"
QDBusInterface::QDBusInterface(QDBusInterfacePrivate* p)
: d(p)
{
d->ref.ref();
}
QDBusInterface::QDBusInterface(const QDBusObject& obj, const QString& name)
: d(0)
{
*this = obj.connection().findInterface(obj.service(), obj.path(), name);
}
QDBusInterface::QDBusInterface(QDBusConnection& conn, const QString& service, const QString& path,
const QString& name)
: d(0)
{
*this = conn.findInterface(service, path, name);
}
QDBusInterface::~QDBusInterface()
{
if (!d->ref.deref())
delete d;
}
QDBusInterface& QDBusInterface::operator=(const QDBusInterface& other)
{
other.d->ref.ref();
QDBusInterfacePrivate* old = qAtomicSetPtr(&d, other.d);
if (old && !old->ref.deref())
delete old;
return *this;
}
QDBusConnection QDBusInterface::connection() const
{
return d->conn;
}
QString QDBusInterface::service() const
{
return d->service;
}
QString QDBusInterface::path() const
{
return d->path;
}
QString QDBusInterface::interface() const
{
return d->data->name;
}
QString QDBusInterface::introspectionData() const
{
d->introspect();
return d->data->introspection;
}
const QDBusIntrospection::Interface& QDBusInterface::interfaceData() const
{
d->introspect();
return *d->data;
}
const QDBusIntrospection::Annotations& QDBusInterface::annotationData() const
{
d->introspect();
return d->data->annotations;
}
const QDBusIntrospection::Methods& QDBusInterface::methodData() const
{
d->introspect();
return d->data->methods;
}
const QDBusIntrospection::Signals& QDBusInterface::signalData() const
{
d->introspect();
return d->data->signals_;
}
const QDBusIntrospection::Properties& QDBusInterface::propertyData() const
{
d->introspect();
return d->data->properties;
}
QDBusMessage QDBusInterface::callWithArgs(const QDBusIntrospection::Method& method,
const QList<QVariant>& a_args,
CallMode mode)
{
QString signature(""); // empty, not null
QVariantList args = a_args;
if (!method.inputArgs.isEmpty())
{
// go over the list of parameters for the method
QDBusIntrospection::Arguments::const_iterator it = method.inputArgs.begin(),
end = method.inputArgs.end();
int arg;
for (arg = 0; it != end; ++it, ++arg)
{
// find the marshalled name for this type
QString typeSig = QLatin1String(it->type.dbusSignature());
signature += typeSig;
}
}
else
args.clear();
if (method.annotations.contains(ANNOTATION_NO_WAIT))
mode = NoWaitForReply;
return callWithArgs(method.name, signature, args, mode);
}
QDBusMessage QDBusInterface::callWithArgs(const QString& method, const QList<QVariant>& args,
CallMode mode)
{
QString m = method, sig;
// split out the signature from the method
int pos = method.indexOf('.');
if (pos != -1) {
m.truncate(pos);
sig = method.mid(pos + 1);
}
return callWithArgs(m, sig, args, mode);
}
QDBusMessage QDBusInterface::callWithArgs(const QString& method, const QString& signature,
const QList<QVariant>& args, CallMode mode)
{
QDBusMessage msg = QDBusMessage::methodCall(service(), path(), interface(), method, signature);
msg.QList<QVariant>::operator=(args);
QDBusMessage reply;
if (mode == WaitForReply)
reply = d->conn.sendWithReply(msg);
else
d->conn.send(msg);
d->lastError = reply; // will clear if reply isn't an error
// ensure that there is at least one element
if (reply.isEmpty())
reply << QVariant();
return reply;
}
bool QDBusInterface::connect(const QDBusIntrospection::Signal& sig, QObject* obj, const char *slot)
{
QString signature(""); // empty, not null
if (!sig.outputArgs.isEmpty())
{
// go over the list of parameters for the method
QDBusIntrospection::Arguments::const_iterator it = sig.outputArgs.begin(),
end = sig.outputArgs.end();
int arg;
for (arg = 0; it != end; ++it, ++arg)
{
// find the marshalled name for this type
QString typeSig = QLatin1String(it->type.dbusSignature());
signature += typeSig;
}
}
return connect(sig.name, signature, obj, slot);
}
bool QDBusInterface::connect(const QString& signalName, QObject* obj, const char *slot)
{
QString s = signalName, sig;
// split out the signature from the name
int pos = signalName.indexOf('.');
if (pos != -1) {
s.truncate(pos);
sig = signalName.mid(pos + 1);
}
return connect(s, sig, obj, slot);
}
bool QDBusInterface::connect(const QString& signalName, const QString& signature,
QObject* obj, const char *slot)
{
return d->conn.connect(service(), path(), interface(), signalName, signature, obj, slot);
}
QVariant QDBusInterface::propertyGet(const QDBusIntrospection::Property& prop)
{
// sanity checking
if (prop.access == QDBusIntrospection::Property::Write)
return QVariant(); // write-only prop
QDBusPropertiesInterface pi(object());
return pi.get(interface(), prop.name);
}
QVariant QDBusInterface::propertyGet(const QString& propName)
{
// can't do sanity checking
QDBusPropertiesInterface pi(object());
return pi.get(interface(), propName);
}
void QDBusInterface::propertySet(const QDBusIntrospection::Property& prop, QVariant newValue)
{
// sanity checking
if (prop.access == QDBusIntrospection::Property::Read)
return;
QDBusPropertiesInterface pi(object());
pi.set(interface(), prop.name, newValue);
}
void QDBusInterface::propertySet(const QString& propName, QVariant newValue)
{
// can't do sanity checking
QDBusPropertiesInterface pi(object());
pi.set(interface(), propName, newValue);
}
--- NEW FILE: qdbusinterface.h ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSINTERFACE_H
#define QDBUSINTERFACE_H
#include "qdbusmessage.h"
#include "qdbusobject.h"
#include "qdbusintrospection.h"
#include <QtCore/qstring.h>
#include <QtCore/qvariant.h>
#include <QtCore/qlist.h>
class QDBusConnection;
class QDBusInterfacePrivate;
/**
* Base class for all DBUS interfaces in the QtDBUS binding.
*/
class QDBUS_EXPORT QDBusInterface
{
friend class QDBusConnection;
public:
enum CallMode {
WaitForReply,
NoWaitForReply
};
public:
/**
* Construct an interface of the given name
*/
QDBusInterface(const QDBusObject& obj, const QString& name);
/**
* @overload.
* Construct an interface of the given name
*/
QDBusInterface(QDBusConnection& conn, const QString& service, const QString& path, const QString& name);
/**
* Construct a copy of the interface.
*/
QDBusInterface(const QDBusInterface&);
/**
* Destructs this interface.
*/
virtual ~QDBusInterface();
/**
* Copy the interface.
*/
QDBusInterface& operator=(const QDBusInterface&);
/**
* Returns the object associated with this interface.
*/
inline QDBusObject object()
{ return QDBusObject(*this); }
inline const QDBusObject object() const
{ return QDBusObject(*this); }
/**
* Returns the connection this interface is on.
*/
QDBusConnection connection() const;
/**
* Returns the name of the service this interface is associated with.
*/
QString service() const;
/**
* Returns the object path that this interface is associated with.
*/
QString path() const;
/**
* Returns the name of this interface.
*/
QString interface() const;
/**
* Returns the introspection XML fragment data of this interface.
*/
virtual QString introspectionData() const;
/**
* Returns the interface data for this interface.
*/
const QDBusIntrospection::Interface& interfaceData() const;
/**
* Returns the annotations present in this interface, if any.
*/
const QDBusIntrospection::Annotations& annotationData() const;
/**
* List all methods in this interface.
*/
const QDBusIntrospection::Methods& methodData() const;
/**
* List all signals in this interface.
*/
const QDBusIntrospection::Signals& signalData() const;
/**
* List all properties in this interface.
*/
const QDBusIntrospection::Properties& propertyData() const;
/**
* Call the given method.
*/
QDBusMessage callWithArgs(const QDBusIntrospection::Method& method,
const QList<QVariant>& args = QList<QVariant>(),
CallMode mode = WaitForReply);
/**
* Call the given method.
*/
QDBusMessage callWithArgs(const QString& method, const QList<QVariant>& args = QList<QVariant>(),
CallMode mode = WaitForReply);
/**
* Call the given method.
*/
QDBusMessage callWithArgs(const QString& method, const QString& signature,
const QList<QVariant>& args = QList<QVariant>(),
CallMode mode = WaitForReply);
/**
* Connects the DBUS signal to the given slot.
*/
bool connect(const QDBusIntrospection::Signal&, QObject* obj, const char *slot);
/**
* Connects the DBUS signal to the given slot.
*/
bool connect(const QString& signalName, QObject* obj, const char *slot);
/**
* Connects the DBUS signal to the given slot.
*/
bool connect(const QString& signalName, const QString& signature,
QObject* obj, const char *slot);
/**
* Gets the value of the given property.
*/
QVariant propertyGet(const QDBusIntrospection::Property&);
/**
* Gets the value of the given property.
*/
QVariant propertyGet(const QString& property);
/**
* Sets the value of the given property.
*/
void propertySet(const QDBusIntrospection::Property&, QVariant newValue);
/**
* Sets the value of the given property.
*/
void propertySet(const QString& property, QVariant newValue);
/**
* Casts to QDBusObject.
*/
inline operator QDBusObject()
{ return QDBusObject(*this); }
/**
* Casts to const QDBusObject.
*/
inline operator const QDBusObject() const
{ return QDBusObject(*this); }
/**
* Call the given method.
*/
template<typename MethodType>
inline QDBusMessage call(MethodType m)
{
return callWithArgs(m);
}
/**
* Call the given method.
*/
template<typename MethodType, typename T1>
inline QDBusMessage call(MethodType m, T1 t1)
{
QList<QVariant> args;
args << t1;
return callWithArgs(m, args);
}
/**
* Call the given method.
*/
template<typename MethodType, typename T1, typename T2>
inline QDBusMessage call(MethodType m, T1 t1, T2 t2)
{
QList<QVariant> args;
args << t1 << t2;
return callWithArgs(m, args);
}
/**
* Call the given method.
*/
template<typename MethodType, typename T1, typename T2, typename T3>
inline QDBusMessage call(MethodType m, T1 t1, T2 t2, T3 t3)
{
QList<QVariant> args;
args << t1 << t2 << t3;
return callWithArgs(m, args);
}
/**
* Call the given method.
*/
template<typename MethodType, typename T1, typename T2, typename T3, typename T4>
inline QDBusMessage call(MethodType m, T1 t1, T2 t2, T3 t3, T4 t4)
{
QList<QVariant> args;
args << t1 << t2 << t3 << t4;
return callWithArgs(m, args);
}
/**
* Call the given method.
*/
template<typename MethodType, typename T1, typename T2, typename T3, typename T4, typename T5>
inline QDBusMessage call(MethodType m, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{
QList<QVariant> args;
args << t1 << t2 << t3 << t4 << t5;
return callWithArgs(m, args);
}
/**
* Call the given method.
*/
template<typename MethodType, typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6>
inline QDBusMessage call(MethodType m, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{
QList<QVariant> args;
args << t1 << t2 << t3 << t4 << t5 << t6;
return callWithArgs(m, args);
}
/**
* Call the given method.
*/
template<typename MethodType, typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7>
inline QDBusMessage call(MethodType m, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{
QList<QVariant> args;
args << t1 << t2 << t3 << t4 << t5 << t6 << t7;
return callWithArgs(m, args);
}
/**
* Call the given method.
*/
template<typename MethodType, typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8>
inline QDBusMessage call(MethodType m, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{
QList<QVariant> args;
args << t1 << t2 << t3 << t4 << t5 << t6 << t7 << t8;
return callWithArgs(m, args);
}
private:
QDBusInterface(QDBusInterfacePrivate*);
QDBusInterfacePrivate *d;
};
#endif
--- NEW FILE: qdbusinterface_p.h ---
/*
*
* Copyright (C) 2006 Thiago José Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#ifndef QDBUSINTERFACEPRIVATE_H
#define QDBUSINTERFACEPRIVATE_H
#include "qdbusobject.h"
#include "qdbusinterface.h"
#include "qdbusconnection.h"
#include "qdbuserror.h"
#define ANNOTATION_NO_WAIT "com.trolltech.DBus.NoWaitForReply"
class QDBusInterfacePrivate
{
public:
QAtomic ref;
QDBusConnection conn;
QString service;
QString path;
QDBusError lastError;
//QConstSharedDataPointer<QDBusIntrospection::Interface> data;
const QDBusIntrospection::Interface* data;
inline bool needsIntrospection() const
{ return data->introspection.isNull(); }
inline void introspect()
{ if (needsIntrospection()) QDBusObject(conn, service, path).introspect(); }
};
#endif
--- NEW FILE: qdbusintrospection.cpp ---
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbusintrospection.h"
#include "qdbusxmlparser_p.h"
/*!
\class QDBusIntrospection
\brief Information about introspected objects and interfaces on D-Bus.
This class provides structures and methods for parsing the XML introspection data for D-Bus.
Normally, you don't have to use the methods provided here: QDBusInterface and QDBusObject will
do that for you.
But they may prove useful if the XML data was obtained through other means (like parsing a file).
*/
/*!
\struct QDBusIntrospection::Argument
\brief One argument to a D-Bus method or signal.
This struct represents one argument passed to a method or received from a method or signal in
D-Bus. The struct does not contain information on the direction (input or output).
*/
/*!
\var QDBusIntrospection::Argument::type
The argument type.
*/
/*!
\var QDBusIntrospection::Argument::name
The argument name. The argument name is optional, so this may be a null QString.
*/
/*!
\struct QDBusIntrospection::Method
\brief Information about one method.
This struct represents one method discovered through introspection. A method is composed of
its \a name, its input arguments, its output arguments, and, optionally, annotations. There are no
"in-out" arguments.
*/
/*!
\var QDBusIntrospection::Method::name
The method's name.
*/
/*!
\var QDBusIntrospection::Method::inputArgs
A list of the method's input arguments.
*/
/*!
\var QDBusIntrospection::Method::outputArgs
A list of the method's output arguments (i.e., return values).
*/
/*!
\var QDBusIntrospection::Method::annotations
The annotations associated with the method. Each annotation is a pair of strings, where the key
is of the same format as a D-Bus interface name. The value is arbitrary.
*/
/*!
\struct QDBusIntrospection::Signal
\brief Information about one signal.
This struct represents one signal discovered through introspection. A signal is composed of
its \a name, its output arguments, and, optionally, annotations.
*/
/*!
\var QDBusIntrospection::Signal::outputArgs
A list of the signal's arguments.
*/
/*!
\var QDBusIntrospection::Signal::annotations
The annotations associated with the signal. Each annotation is a pair of strings, where the key
is of the same format as a D-Bus interface name. The value is arbitrary.
*/
/*!
\struct QDBusIntrospection::Property
\brief Information about one property.
This struct represents one property discovered through introspection. A property is composed of
its \a name, its \a type, its \a access rights, and, optionally, annotations.
*/
/*!
\var QDBusIntrospection::Property::name
The property's name.
*/
/*!
\var QDBusIntrospection::Property::type
The property's type.
*/
/*!
\enum QDBusIntrospection::Property::Access
The possible access rights for a property:
- Read
- Write
- ReadWrite
*/
/*!
\var QDBusIntrospection::Property::access
The property's access rights.
*/
/*!
\var QDBusIntrospection::Property::annotations
The annotations associated with the property. Each annotation is a pair of strings, where the key
is of the same format as a D-Bus interface name. The value is arbitrary.
*/
/*!
\struct QDBusIntrospection::Interface
\brief Information about one interface on the bus.
Each interface on D-Bus has an unique \a name, identifying where that interface was defined.
Interfaces may have annotations, methods, signals and properties, but none are mandatory.
*/
/*!
\var QDBusIntrospection::Interface::name
The interface's name.
*/
/*!
\var QDBusIntrospection::Interface::introspection
The XML document fragment describing this interface.
If parsed again through parseInterface, the object returned should have the same contents as
this object.
*/
/*!
\var QDBusIntrospection::Interface::annotations
The annotations associated with the interface. Each annotation is a pair of strings, where the key
is of the same format as a D-Bus interface name. The value is arbitrary.
*/
/*!
\var QDBusIntrospection::Interface::methods
The methods available in this interface. Note that method names are not unique (i.e., methods
can be overloaded with multiple arguments types).
*/
/*!
\var QDBusIntrospection::Interface::signals_
The signals available in this interface. Note that signal names are not unique (i.e., signals
can be overloaded with multiple argument types).
This member is called "signals_" because "signals" is a reserved keyword in Qt.
*/
/*!
\var QDBusIntrospection::Interface::properties
The properties available in this interface. Property names are unique.
*/
/*!
\struct QDBusIntrospection::Object
\brief Information about one object on the bus.
An object on the D-Bus bus is represented by its service and path on the service but, unlike
interfaces, objects are mutable. That is, their contents can change with time. Therefore,
while the (service, path) pair uniquely identifies an object, the information contained in
this struct may no longer represent the object.
An object can contain interfaces and child (sub) objects.
*/
/*!
\var QDBusIntrospection::Object::service
The object's service name.
\sa parseObject, parseObjectTree
*/
/*!
\var QDBusIntrospection::Object::path
The object's path on the service. This is an absolute path.
\sa parseObject, parseObjectTree
*/
/*!
\var QDBusIntrospection::Object::introspection
The XML document fragment describing this object, its interfaces and sub-objects at the time
of the parsing.
The result of parseObject with this XML data should be the same as the Object struct.
*/
/*!
\var QDBusIntrospection::Object::interfaces
The list of interface names in this object.
*/
/*!
\var QDBusIntrospection::Object::childObjects
The list of child object names in this object. Note that this is a relative name, not an
absolute path. To obtain the absolute path, concatenate with \ref path.
*/
/*!
\struct QDBusIntrospection::ObjectTree
\brief Complete information about one object node and its descendency.
This struct contains the same data as QDBusIntrospection::Object, plus the actual data for the
interfaces and child (sub) objects that was available in the XML document.
*/
/*!
\var QDBusIntrospection::ObjectTree::interfaceData
A map of interfaces and their names.
*/
/*!
\var QDBusIntrospection::ObjectTree::childObjectData
A map of object paths and their data. The map key contains the relative path to the object.
Note this map contains only the child notes that do have information about the sub-object's
contents. If the XML data did not contain the information, only the object name will be listed
in childObjects, but not in childObjectData.
*/
/*!
\typedef QDBusIntrospection::Annotations
Contains a QMap of an annotation pair. The annotation's name is stored in the QMap key and
must be unique. The annotation's value is stored in the QMap's value and is arbitrary.
*/
/*!
\typedef QDBusIntrospection::Arguments
Contains a list of arguments to either a Method or a Signal. The arguments' order is important.
*/
/*!
\typedef QDBusIntrospection::Methods
Contains a QMap of methods and their names. The method's name is stored in the map's key and
is not necessarily unique. The order in which multiple methods with the same name are stored
in this map is undefined.
*/
/*!
\typedef QDBusIntrospection::Signals
Contains a QMap of signals and their names. The signal's name is stored in the map's key and
is not necessarily unique. The order in which multiple signals with the same name are stored
in this map is undefined.
*/
/*!
\typedef QDBusIntrospection::Properties
Contains a QMap of properties and their names. Each property must have a unique name.
*/
/*!
\typedef QDBusIntrospection::Interfaces
Contains a QMap of interfaces and their names. Each interface has a unique name.
*/
/*!
\typedef QDBusIntrospection::Objects
Contains a QMap of objects and their paths relative to their immediate parent.
\sa parseObjectTree
*/
/*!
Parses the XML document fragment containing one interface.
The first element tag in this XML data must be either <node> or <interface>. If it is
<node>, then the <interface> tag must be a child tag of the <node> one.
If there are multiple interfaces in this XML data, it is undefined which one will be
returned.
\param xml the XML data to be parsed
\returns the parsed interface
*/
QDBusIntrospection::Interface
QDBusIntrospection::parseInterface(const QString &xml)
{
// be lazy
Interfaces ifs = parseInterfaces(xml);
if (ifs.isEmpty())
return Interface();
// return the first in map order (probably alphabetical order)
return *ifs.constBegin().value();
}
/*!
Parses the XML document fragment containing several interfaces.
If the first element tag in this document fragment is <node>, the interfaces parsed will
be those found as child elements of the <node> tag.
\param xml the XML data to be parsed
\returns the parsed interfaces
*/
QDBusIntrospection::Interfaces
QDBusIntrospection::parseInterfaces(const QString &xml)
{
QDBusXmlParser parser(QString(), QString(), xml);
return parser.interfaces();
}
/*!
Parses the XML document fragment containing one object.
The first element tag in this document must be <node>. If that tag does not contain
a name attribute, the \a path argument will be used to determine the path of this
object node.
This function does not parse the interfaces contained in the node, nor sub-object's contents.
It will only list their names. If you need to know their contents, use parseObjectTree.
\param xml the XML data to be parsed
\param service the service where this object is found
\param path the absolute path to this node on the remote service
\returns the parsed object
*/
QDBusIntrospection::Object
QDBusIntrospection::parseObject(const QString &xml, const QString &service, const QString &path)
{
QDBusXmlParser parser(service, path, xml);
QSharedDataPointer<QDBusIntrospection::Object> retval = parser.object();
if (!retval)
return QDBusIntrospection::Object();
return *retval;
}
/*!
Parses the XML document fragment containing one object node and returns all the information
about the interfaces and sub-objects.
The Objects map returned will contain the absolute path names in the key.
\param xml the XML data to be parsed
\param service the service where this object is found
\param path the absolute path to this node on the remote service
\returns the parsed objects and interfaces
*/
QDBusIntrospection::ObjectTree
QDBusIntrospection::parseObjectTree(const QString &xml, const QString &service, const QString &path)
{
QDBusXmlParser parser(service, path, xml);
QSharedDataPointer<QDBusIntrospection::ObjectTree> retval = parser.objectTree();
if (!retval)
return QDBusIntrospection::ObjectTree();
return *retval;
}
--- NEW FILE: qdbusintrospection.h ---
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSINTROSPECTION_H
#define QDBUSINTROSPECTION_H
#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qmap.h>
#include <QtCore/qpair.h>
#include <QtCore/qshareddata.h>
#include "qdbustype.h"
#include "qdbusmacros.h"
class QDBUS_EXPORT QDBusIntrospection
{
public:
// forward declarations
struct Argument;
struct Method;
struct Signal;
struct Property;
struct Interface;
struct Object;
struct ObjectTree;
// typedefs
typedef QMap<QString, QString> Annotations;
typedef QList<Argument> Arguments;
typedef QMultiMap<QString, Method> Methods;
typedef QMultiMap<QString, Signal> Signals;
typedef QMap<QString, Property> Properties;
typedef QMap<QString, QSharedDataPointer<Interface> > Interfaces;
typedef QMap<QString, QSharedDataPointer<ObjectTree> > Objects;
public:
// the structs
struct Argument
{
QDBusType type;
QString name;
inline bool operator==(const Argument& other) const
{ return name == other.name && type == other.type; }
};
struct Method
{
QString name;
Arguments inputArgs;
Arguments outputArgs;
Annotations annotations;
inline bool operator==(const Method& other) const
{ return name == other.name && annotations == other.annotations &&
inputArgs == other.inputArgs && outputArgs == other.outputArgs; }
};
struct Signal
{
QString name;
Arguments outputArgs;
Annotations annotations;
inline bool operator==(const Signal& other) const
{ return name == other.name && annotations == other.annotations &&
outputArgs == other.outputArgs; }
};
struct Property
{
enum Access { Read, Write, ReadWrite };
QString name;
QDBusType type;
Access access;
Annotations annotations;
inline bool operator==(const Property& other) const
{ return access == other.access && name == other.name &&
annotations == other.annotations && type == other.type; }
};
struct Interface: public QSharedData
{
QString name;
QString introspection;
Annotations annotations;
Methods methods;
Signals signals_;
Properties properties;
inline bool operator==(const Interface &other) const
{ return name == other.name; }
};
struct Object: public QSharedData
{
QString service;
QString path;
QString introspection;
QStringList interfaces;
QStringList childObjects;
};
struct ObjectTree: public Object
{
Interfaces interfaceData;
Objects childObjectData;
};
public:
static Interface parseInterface(const QString &xml);
static Interfaces parseInterfaces(const QString &xml);
static Object parseObject(const QString &xml, const QString &service = QString(),
const QString &path = QString());
static ObjectTree parseObjectTree(const QString &xml,
const QString &service,
const QString &path);
private:
QDBusIntrospection();
};
#endif
Index: qdbusmarshall.cpp
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusmarshall.cpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- qdbusmarshall.cpp 22 Jan 2006 19:45:14 -0000 1.2
+++ qdbusmarshall.cpp 15 Feb 2006 16:25:12 -0000 1.3
@@ -1,6 +1,8 @@
/* qdbusmarshall.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
@@ -15,21 +17,22 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, write to the Free Software Foundation
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbusmarshall.h"
+#include "qdbustype.h"
#include "qdbusvariant.h"
-#include <QtCore/qdebug.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qmap.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qvector.h>
+#include <qdebug.h>
+#include <qvariant.h>
+#include <qlist.h>
+#include <qmap.h>
+#include <qstringlist.h>
+#include <qvarlengtharray.h>
+#include <qvector.h>
#include <dbus/dbus.h>
@@ -60,6 +63,10 @@
switch (dbus_message_iter_get_arg_type(it)) {
case DBUS_TYPE_BYTE:
return qIterGet<unsigned char>(it);
+ case DBUS_TYPE_INT16:
+ return qIterGet<dbus_int16_t>(it);
+ case DBUS_TYPE_UINT16:
+ return qIterGet<dbus_uint16_t>(it);
case DBUS_TYPE_INT32:
return qIterGet<dbus_int32_t>(it);
case DBUS_TYPE_UINT32:
@@ -78,15 +85,26 @@
return QString::fromUtf8(qIterGet<char *>(it));
case DBUS_TYPE_ARRAY: {
int arrayType = dbus_message_iter_get_element_type(it);
- if (arrayType == DBUS_TYPE_STRING || arrayType == DBUS_TYPE_OBJECT_PATH) {
+ if (arrayType == DBUS_TYPE_STRING || arrayType == DBUS_TYPE_OBJECT_PATH ||
+ arrayType == DBUS_TYPE_SIGNATURE) {
return qFetchStringList(it);
+ } else if (arrayType == DBUS_TYPE_BYTE) {
+ DBusMessageIter sub;
+ dbus_message_iter_recurse(it, &sub);
+ int len = dbus_message_iter_get_array_len(&sub);
+ char* data;
+ dbus_message_iter_get_fixed_array(&sub,&data,&len);
+ return QByteArray(data,len);
} else if (arrayType == DBUS_TYPE_DICT_ENTRY) {
// ### support other types of maps?
QMap<QString, QVariant> map;
DBusMessageIter sub;
+
dbus_message_iter_recurse(it, &sub);
if (!dbus_message_iter_has_next(&sub))
+ // empty map
return map;
+
do {
DBusMessageIter itemIter;
dbus_message_iter_recurse(&sub, &itemIter);
@@ -96,43 +114,30 @@
map.insertMulti(key, qFetchParameter(&itemIter));
} while (dbus_message_iter_next(&sub));
return map;
- } else {
- QList<QVariant> list;
- DBusMessageIter sub;
- dbus_message_iter_recurse(it, &sub);
- if (!dbus_message_iter_has_next(&sub))
- return list;
- do {
- list.append(qFetchParameter(&sub));
- } while (dbus_message_iter_next(&sub));
- return list;
}
- break; }
+ }
+ // fall through
+ // common handling for structs and lists
+ case DBUS_TYPE_STRUCT: {
+ QList<QVariant> list;
+ DBusMessageIter sub;
+ dbus_message_iter_recurse(it, &sub);
+ if (!dbus_message_iter_has_next(&sub))
+ return list;
+ do {
+ list.append(qFetchParameter(&sub));
+ } while (dbus_message_iter_next(&sub));
+ return list;
+ }
case DBUS_TYPE_VARIANT: {
QDBusVariant dvariant;
DBusMessageIter sub;
dbus_message_iter_recurse(it, &sub);
- dvariant.signature = QString::fromUtf8(dbus_message_iter_get_signature(&sub));
+ dvariant.type = QDBusType(dbus_message_iter_get_signature(&sub));
dvariant.value = qFetchParameter(&sub);
return qVariantFromValue(dvariant);
}
-#if 0
- case DBUS_TYPE_DICT: {
- QMap<QString, QVariant> map;
- DBusMessageIter sub;
- dbus_message
- if (dbus_message_iter_init_dict_iterator(it, &dictIt)) {
- do {
- map[QString::fromUtf8(dbus_message_iter_get_dict_key(&dictIt))] =
- qFetchParameter(&dictIt);
- } while (dbus_message_iter_next(&dictIt));
- }
- return map;
- break; }
- case DBUS_TYPE_CUSTOM:
- return qGetCustomValue(it);
- break;
-#endif
+
default:
qWarning("Don't know how to handle type %d '%c'", dbus_message_iter_get_arg_type(it), dbus_message_iter_get_arg_type(it));
return QVariant();
@@ -153,148 +158,305 @@
} while (dbus_message_iter_next(&it));
}
-#define DBUS_APPEND(type,dtype,var) \
-type dtype##v=(var); \
-dbus_message_append_args(msg, dtype, &dtype##v, DBUS_TYPE_INVALID)
-#define DBUS_APPEND_LIST(type,dtype,var,size) \
-type dtype##v=(var); \
-dbus_message_append_args(msg, DBUS_TYPE_ARRAY, dtype, &dtype##v, size, DBUS_TYPE_INVALID)
-
-
-static void qAppendToMessage(DBusMessageIter *it, const QString &str)
+// convert the variant to the given type and return true if it worked.
+// if the type is not known, guess it from the variant and set.
+// return false if conversion failed.
+static bool checkType(QVariant &var, QDBusType &type)
{
- QByteArray ba = str.toUtf8();
- const char *cdata = ba.constData();
- dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &cdata);
-}
+ if (!type.isValid()) {
+ // guess it from the variant
+ type = QDBusType::guessFromVariant(var);
+ return true;
+ }
-static QVariant::Type qVariantListType(const QList<QVariant> &list)
-{
- // TODO - catch lists that have a list as first parameter
- QVariant::Type tp = list.value(0).type();
- if (tp < QVariant::Int || tp > QVariant::Double)
- return QVariant::Invalid;
+ // only catch the conversions that won't work
+ // let QVariant do the hard work
+
+ // QVariant can't convert QDBusVariant:
+ if (var.userType() == qMetaTypeId<QDBusVariant>()) {
+ if (type.dbusType() == DBUS_TYPE_VARIANT)
+ return true; // no change
- for (int i = 1; i < list.count(); ++i) {
- const QVariant &var = list.at(i);
- if (var.type() != tp
- && (var.type() != QVariant::List || qVariantListType(var.toList()) != tp))
- return QVariant::Invalid;
+ // convert manually
+ QDBusVariant dvariant = qvariant_cast<QDBusVariant>(var);
+ var = dvariant.value;
+ return checkType(var, type);
+ }
+
+ if (type.dbusType() == DBUS_TYPE_VARIANT) {
+ // variant can handle anything. Let it pass
+ return true;
}
- return tp;
-}
-static const char *qDBusListType(const QList<QVariant> &list)
-{
- static const char *DBusArgs[] = { 0, 0, DBUS_TYPE_INT32_AS_STRING, DBUS_TYPE_UINT32_AS_STRING,
- DBUS_TYPE_INT64_AS_STRING, DBUS_TYPE_UINT64_AS_STRING, DBUS_TYPE_DOUBLE_AS_STRING };
+ switch (var.userType()) {
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ case QMetaType::UChar:
+ case QVariant::Int:
+ case QVariant::UInt:
+ case QVariant::LongLong:
+ case QVariant::ULongLong:
+ case QVariant::Double:
+ case QVariant::String:
+ if (type.isBasic())
+ // QVariant can handle this on its own
+ return true;
- return DBusArgs[qVariantListType(list)];
+ // cannot handle this
+ qWarning("Invalid conversion from %s to '%s'", var.typeName(),
+ type.dbusSignature().constData());
+ var.clear();
+ return false;
+
+ case QVariant::ByteArray:
+ // make sure it's an "ARRAY of BYTE"
+ if (type.qvariantType() != QVariant::ByteArray) {
+ qWarning("Invalid conversion from %s to '%s'", var.typeName(),
+ type.dbusSignature().constData());
+ var.clear();
+ return false;
+ }
+ return true;
+
+ case QVariant::StringList:
+ // make sure it's "ARRAY of STRING"
+ if (type.qvariantType() != QVariant::StringList) {
+ qWarning("Invalid conversion from %s to '%s'", var.typeName(),
+ type.dbusSignature().constData());
+ var.clear();
+ return false;
+ }
+ return true;
+
+ case QVariant::List:
+ // could be either struct or array
+ if (type.dbusType() != DBUS_TYPE_ARRAY && type.dbusType() != DBUS_TYPE_STRUCT) {
+ qWarning("Invalid conversion from %s to '%s'", var.typeName(),
+ type.dbusSignature().constData());
+ var.clear();
+ return false;
+ }
+
+ return true;
+
+ case QVariant::Map:
+ if (!type.isMap()) {
+ qWarning("Invalid conversion from %s to '%s'", var.typeName(),
+ type.dbusSignature().constData());
+ var.clear();
+ return false;
+ }
+
+ return true;
+
+ case QVariant::Invalid:
+ // create an empty variant
+ var.convert(type.qvariantType());
+ break;
+ }
+
+ qWarning("Found unknown QVariant type %d (%s) when converting to DBus", (int)var.type(),
+ var.typeName());
+ var.clear();
+ return false;
}
-static void qListToIterator(DBusMessageIter *it, const QList<QVariant> &list);
+static void qVariantToIteratorInternal(DBusMessageIter *it, const QVariant &var,
+ const QDBusType &type);
-static void qVariantToIterator(DBusMessageIter *it, const QVariant &var)
+static void qListToIterator(DBusMessageIter *it, const QList<QVariant> &list,
+ const QDBusTypeList &list);
+
+template<typename T>
+static void qIterAppend(DBusMessageIter *it, const QDBusType &type, T arg)
{
- static const int Variant2DBus[] = { DBUS_TYPE_INVALID,
- DBUS_TYPE_BOOLEAN, DBUS_TYPE_INT32, DBUS_TYPE_UINT32,
- DBUS_TYPE_INT64, DBUS_TYPE_UINT64, DBUS_TYPE_DOUBLE };
+ dbus_message_iter_append_basic(it, type.dbusType(), &arg);
+}
- // these really are static asserts
- Q_ASSERT(QVariant::Invalid == 0);
- Q_ASSERT(QVariant::Int == 2);
- Q_ASSERT(QVariant::Double == 6);
+static void qAppendArrayToMessage(DBusMessageIter *it, const QDBusType &subType,
+ const QVariant &var)
+{
+ DBusMessageIter sub;
+ dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, subType.dbusSignature(), &sub);
- switch (var.type()) {
- case QVariant::Int:
- case QVariant::UInt:
- case QVariant::LongLong:
- case QVariant::ULongLong:
- case QVariant::Double:
- dbus_message_iter_append_basic(it, Variant2DBus[var.type()],
- var.constData());
- break;
- case QVariant::String:
- qAppendToMessage(it, var.toString());
- break;
+ switch (var.type())
+ {
case QVariant::StringList: {
const QStringList list = var.toStringList();
- DBusMessageIter sub;
- dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
- DBUS_TYPE_STRING_AS_STRING, &sub);
- for (int s = 0; s < list.count(); ++s)
- qAppendToMessage(&sub, list.at(s));
- dbus_message_iter_close_container(it, &sub);
+ foreach (QString str, list)
+ qIterAppend(&sub, subType, str.toUtf8().constData());
break;
}
- case QVariant::List: {
- const QList<QVariant> &list = var.toList();
- const char *listType = qDBusListType(list);
- if (!listType) {
- qWarning("Don't know how to marshall list.");
- break;
- }
- DBusMessageIter sub;
- dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, listType, &sub);
- qListToIterator(&sub, list);
- dbus_message_iter_close_container(it, &sub);
+
+ case QVariant::ByteArray: {
+ const QByteArray array = var.toByteArray();
+ const char* cdata = array.constData();
+ dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &cdata, array.length());
break;
}
+
case QVariant::Map: {
- // ### TODO - marshall more than qstring/qstring maps
- const QMap<QString, QVariant> &map = var.toMap();
- DBusMessageIter sub;
- QVarLengthArray<char, 16> sig;
- sig.append(DBUS_DICT_ENTRY_BEGIN_CHAR);
- sig.append(DBUS_TYPE_STRING);
- sig.append(DBUS_TYPE_STRING);
- sig.append(DBUS_DICT_ENTRY_END_CHAR);
- sig.append('\0');
- qDebug() << QString::fromAscii(sig.constData());
- dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, sig.constData(), &sub);
+ const QVariantMap map = var.toMap();
+ const QDBusTypeList& subTypes = subType.subTypes();
for (QMap<QString, QVariant>::const_iterator mit = map.constBegin();
mit != map.constEnd(); ++mit) {
DBusMessageIter itemIterator;
dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, 0, &itemIterator);
- qAppendToMessage(&itemIterator, mit.key());
- qAppendToMessage(&itemIterator, mit.value().toString());
+
+ // let the string be converted to QVariant
+ qVariantToIteratorInternal(&itemIterator, mit.key(), subTypes[0]);
+ qVariantToIteratorInternal(&itemIterator, mit.value(), subTypes[1]);
+
dbus_message_iter_close_container(&sub, &itemIterator);
}
- dbus_message_iter_close_container(it, &sub);
break;
}
- case QVariant::UserType: {
- if (var.userType() == QMetaTypeId<QDBusVariant>::qt_metatype_id()) {
- DBusMessageIter sub;
- QDBusVariant dvariant = qvariant_cast<QDBusVariant>(var);
- dbus_message_iter_open_container(it, DBUS_TYPE_VARIANT,
- dvariant.signature.toUtf8().constData(), &sub);
- qVariantToIterator(&sub, dvariant.value);
- dbus_message_iter_close_container(it, &sub);
- break;
- }
+
+ case QVariant::List: {
+ const QVariantList list = var.toList();
+ foreach (QVariant v, list)
+ qVariantToIteratorInternal(&sub, v, subType);
+ break;
}
- // fall through
+
default:
- qWarning("Don't know how to handle type %s", var.typeName());
+ qFatal("qAppendArrayToMessage got unknown type!");
break;
}
+
+ dbus_message_iter_close_container(it, &sub);
}
-void qListToIterator(DBusMessageIter *it, const QList<QVariant> &list)
+static void qAppendStructToMessage(DBusMessageIter *it, const QDBusTypeList &typeList,
+ const QVariantList &list)
{
- if (list.isEmpty())
- return;
+ DBusMessageIter sub;
+ dbus_message_iter_open_container(it, DBUS_TYPE_STRUCT, NULL, &sub);
+ qListToIterator(&sub, list, typeList);
+ dbus_message_iter_close_container(it, &sub);
+}
+static void qAppendVariantToMessage(DBusMessageIter *it, const QDBusType & /* type */,
+ const QVariant &var)
+{
+ QVariant v;
+ QDBusType t;
+
+ if (var.userType() == qMetaTypeId<QDBusVariant>()) {
+ QDBusVariant dvariant = qvariant_cast<QDBusVariant>(var);
+ v = dvariant.value;
+ t = dvariant.type;
+ }
+ else {
+ v = var;
+ t = QDBusType::guessFromVariant(v);
+ }
+
+ // now add this variant
+ DBusMessageIter sub;
+ dbus_message_iter_open_container(it, DBUS_TYPE_VARIANT, t.dbusSignature(), &sub);
+ qVariantToIteratorInternal(&sub, v, t);
+ dbus_message_iter_close_container(it, &sub);
+}
+
+static void qVariantToIterator(DBusMessageIter *it, QVariant var, QDBusType type)
+{
+ if (var.isNull() && !type.isValid())
+ return; // cannot add a null like this
+ if (!checkType(var, type))
+ return; // type checking failed
+
+ qVariantToIteratorInternal(it, var, type);
+}
+
+static void qVariantToIteratorInternal(DBusMessageIter *it, const QVariant &var,
+ const QDBusType &type)
+{
+ switch (type.dbusType()) {
+ case DBUS_TYPE_BYTE:
+ qIterAppend( it, type, static_cast<unsigned char>(var.toUInt()) );
+ break;
+ case DBUS_TYPE_BOOLEAN:
+ qIterAppend( it, type, static_cast<dbus_bool_t>(var.toBool()) );
+ break;
+ case DBUS_TYPE_INT16:
+ qIterAppend( it, type, static_cast<dbus_int16_t>(var.toInt()) );
+ break;
+ case DBUS_TYPE_UINT16:
+ qIterAppend( it, type, static_cast<dbus_uint16_t>(var.toUInt()) );
+ break;
+ case DBUS_TYPE_INT32:
+ qIterAppend( it, type, static_cast<dbus_int32_t>(var.toInt()) );
+ break;
+ case DBUS_TYPE_UINT32:
+ qIterAppend( it, type, static_cast<dbus_uint32_t>(var.toUInt()) );
+ break;
+ case DBUS_TYPE_INT64:
+ qIterAppend( it, type, static_cast<dbus_int64_t>(var.toLongLong()) );
+ break;
+ case DBUS_TYPE_UINT64:
+ qIterAppend( it, type, static_cast<dbus_uint64_t>(var.toULongLong()) );
+ break;
+ case DBUS_TYPE_DOUBLE:
+ qIterAppend( it, type, var.toDouble() );
+ break;
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ qIterAppend( it, type, var.toString().toUtf8().constData() );
+ break;
+
+ // compound types:
+ case DBUS_TYPE_ARRAY:
+ // could be many things
+ qAppendArrayToMessage( it, type.arrayElement(), var );
+ break;
+
+ case DBUS_TYPE_VARIANT:
+ qAppendVariantToMessage( it, type, var );
+ break;
+
+ case DBUS_TYPE_STRUCT:
+ qAppendStructToMessage( it, type.subTypes(), var.toList() );
+ break;
+
+ case DBUS_TYPE_DICT_ENTRY:
+ qFatal("qVariantToIterator got a DICT_ENTRY!");
+ break;
+
+ default:
+ qWarning("Found unknown DBus type '%s'", type.dbusSignature().constData());
+ break;
+ }
+}
+
+void qListToIterator(DBusMessageIter *it, const QList<QVariant> &list)
+{
for (int i = 0; i < list.count(); ++i)
- qVariantToIterator(it, list.at(i));
+ qVariantToIterator(it, list.at(i), QDBusType());
}
-void QDBusMarshall::listToMessage(const QList<QVariant> &list, DBusMessage *msg)
+void qListToIterator(DBusMessageIter *it, const QList<QVariant> &list, const QDBusTypeList &types)
+{
+ int min = qMin(list.count(), types.count());
+ for (int i = 0; i < min; ++i)
+ qVariantToIterator(it, list.at(i), types.at(i));
+
+ for (int i = min; i < types.count(); ++i)
+ // we're missing a few arguments, so add default parameters
+ qVariantToIterator(it, QVariant(), types.at(i));
+}
+
+void QDBusMarshall::listToMessage(const QList<QVariant> &list, DBusMessage *msg,
+ const QString &signature)
{
Q_ASSERT(msg);
DBusMessageIter it;
dbus_message_iter_init_append(msg, &it);
- qListToIterator(&it, list);
+
+ if (signature.isEmpty())
+ qListToIterator(&it, list);
+ else
+ qListToIterator(&it, list, QDBusTypeList(signature.toUtf8()));
}
Index: qdbusmarshall.h
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusmarshall.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- qdbusmarshall.h 23 Sep 2005 13:08:26 -0000 1.1
+++ qdbusmarshall.h 15 Feb 2006 16:25:12 -0000 1.2
@@ -1,6 +1,8 @@
/* qdbusmarshall.h QDBusMarshall object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
@@ -15,8 +17,8 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, write to the Free Software Foundation
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
@@ -25,14 +27,15 @@
struct DBusMessage;
+template <typename T> class QList;
class QVariant;
-template <typename T>
-class QList;
+class QString;
class QDBusMarshall
{
public:
- static void listToMessage(const QList<QVariant> &list, DBusMessage *message);
+ static void listToMessage(const QList<QVariant> &list, DBusMessage *message,
+ const QString& signature);
static void messageToList(QList<QVariant> &list, DBusMessage *message);
};
Index: qdbusmessage.cpp
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusmessage.cpp,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- qdbusmessage.cpp 23 Sep 2005 13:08:26 -0000 1.1
+++ qdbusmessage.cpp 15 Feb 2006 16:25:12 -0000 1.2
@@ -1,6 +1,8 @@
/* qdbusmessage.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
@@ -15,19 +17,20 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, write to the Free Software Foundation
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbusmessage.h"
-#include <QtCore/qdebug.h>
-#include <QtCore/qstringlist.h>
+#include <qdebug.h>
+#include <qstringlist.h>
#include <dbus/dbus.h>
#include "qdbusmarshall.h"
+#include "qdbuserror.h"
#include "qdbusmessage_p.h"
QDBusMessagePrivate::QDBusMessagePrivate(QDBusMessage *qq)
@@ -44,8 +47,31 @@
}
///////////////
+/*!
+ \class QDBusMessage
+ \brief Represents one message sent or received over the DBus bus.
+
+ This object can represent any of four different types of messages possible on the bus
+ (see MessageType)
+ - Method calls
+ - Method return values
+ - Signal emissions
+ - Error codes
+
+ Objects of this type are created with the four static functions signal, methodCall,
+ methodReply and error.
+*/
+/*!
+ Constructs a new DBus message representing a signal emission. A DBus signal is emitted
+ from one application and is received by all applications that are listening for that signal
+ from that interface.
+ \param path the path of the object that is emitting the signal
+ \param interface the interface that is emitting the signal
+ \param name the name of the signal (a.k.a. method name)
+ \returns a QDBusMessage object that can be sent with with QDBusConnection::send
+*/
QDBusMessage QDBusMessage::signal(const QString &path, const QString &interface,
const QString &name)
{
@@ -58,19 +84,58 @@
return message;
}
+/*!
+ Constructs a new DBus message representing a method call. A method call always informs
+ its destination address (service, path, interface and method).
+
+ The DBus bus allows calling a method on a given remote object without specifying the
+ destination interface, if the method name is unique. However, if two interfaces on the
+ remote object export the same method name, the result is undefined (one of the two may be
+ called or an error may be returned).
+
+ When using DBus in a peer-to-peer context (i.e., not on a bus), the service parameter is
+ optional.
+
+ Optionally, a signature parameter can be passed, indicating the type of the parameters to
+ be marshalled over the bus. If there are more arguments thanentries in the signature, the
+ tailing arguments will be silently dropped and not sent. If there are less arguments,
+ default values will be inserted (default values are those created by QVariant::convert
+ when a variant of type QVariant::Invalid is converted to the type).
+
+ The QDBusObject and QDBusInterface classes provide a simpler abstraction to synchronous
+ method calling.
+
+ \param service the remote service to be called (can be a well-known name, a bus
+ address or null)
+ \param path the path of the object on the remote service to be called
+ \param interface the remote interface that is wanted (can be null)
+ \param method the remote method to be called (a.k.a., name)
+ \param sig the DBus signature (set to null to discard processing and guess the
+ method signature from the arguments; empty means no arguments)
+ \returns a QDBusMessage object that can be sent with QDBusConnection::send,
+ QDBusConnection::sendWithReply, or QDBusConnection::sendWithReplyAsync
+*/
QDBusMessage QDBusMessage::methodCall(const QString &service, const QString &path,
- const QString &interface, const QString &method)
+ const QString &interface, const QString &method,
+ const QString &sig)
{
QDBusMessage message;
message.d->type = DBUS_MESSAGE_TYPE_METHOD_CALL;
message.d->service = service;
message.d->path = path;
message.d->interface = interface;
- message.d->method = method;
+ message.d->name = method;
+ message.d->signature = sig;
return message;
}
+/*!
+ Constructs a new DBus message representing the return values from a called method.
+
+ \param other the method call DBus message that this is a reply to
+ \returns a QDBusMessage object that can be sent with QDBusConnection::send
+*/
QDBusMessage QDBusMessage::methodReply(const QDBusMessage &other)
{
Q_ASSERT(other.d->msg);
@@ -82,11 +147,63 @@
return message;
}
+/*!
+ Constructs a DBus message representing an error condition.
+
+ \param other the QDBusMessage object that generated this error
+ \param name the DBus error name (error names must follow the same convention that
+ interface names do)
+ \param msg the error message
+ \return a QDBusMessage object that can be sent with QDBusMessage::send
+*/
+QDBusMessage QDBusMessage::error(const QDBusMessage &other, const QString &name,
+ const QString &msg)
+{
+ Q_ASSERT(other.d->msg);
+
+ QDBusMessage message;
+ message.d->type = DBUS_MESSAGE_TYPE_ERROR;
+ message.d->name = name;
+ message.d->message = msg;
+ message.d->reply = dbus_message_ref(other.d->msg);
+
+ return message;
+}
+
+/*!
+ \overload
+ Constructs a DBus message representing an error condition.
+
+ \param other the QDBusMessage object that generated this error
+ \param error the QDBusError object representing this error
+ \return a QDBusMessage object that can be sent with QDBusMessage::send
+*/
+QDBusMessage QDBusMessage::error(const QDBusMessage &other, const QDBusError &error)
+{
+ Q_ASSERT(other.d->msg);
+
+ QDBusMessage message;
+ message.d->type = DBUS_MESSAGE_TYPE_ERROR;
+ message.d->name = error.name();
+ message.d->message = error.message();
+ message.d->reply = dbus_message_ref(other.d->msg);
+
+ return message;
+}
+
+/*!
+ Constructs an empty, invalid QDBusMessage object.
+
+ \sa methodCall, methodReply, signal, error
+*/
QDBusMessage::QDBusMessage()
{
d = new QDBusMessagePrivate(this);
}
+/*!
+ Constructs a copy of the other object.
+*/
QDBusMessage::QDBusMessage(const QDBusMessage &other)
: QList<QVariant>(other)
{
@@ -94,12 +211,18 @@
d->ref.ref();
}
+/*!
+ Disposes of the object and frees any resources that were being held.
+*/
QDBusMessage::~QDBusMessage()
{
if (!d->ref.deref())
delete d;
}
+/*!
+ Copies the contents of the other object.
+*/
QDBusMessage &QDBusMessage::operator=(const QDBusMessage &other)
{
QList<QVariant>::operator=(other);
@@ -107,14 +230,20 @@
return *this;
}
+/*!
+ \internal
+ Constructs a DBusMessage object from this object. The returned value must be de-referenced
+ with dbus_message_unref.
+*/
DBusMessage *QDBusMessage::toDBusMessage() const
{
DBusMessage *msg = 0;
+
switch (d->type) {
case DBUS_MESSAGE_TYPE_METHOD_CALL:
msg = dbus_message_new_method_call(d->service.toUtf8().constData(),
d->path.toUtf8().constData(), d->interface.toUtf8().constData(),
- d->method.toUtf8().constData());
+ d->name.toUtf8().constData());
break;
case DBUS_MESSAGE_TYPE_SIGNAL:
msg = dbus_message_new_signal(d->path.toUtf8().constData(),
@@ -123,14 +252,22 @@
case DBUS_MESSAGE_TYPE_METHOD_RETURN:
msg = dbus_message_new_method_return(d->reply);
break;
+ case DBUS_MESSAGE_TYPE_ERROR:
+ msg = dbus_message_new_error(d->reply, d->name.toUtf8().constData(),
+ d->message.toUtf8().constData());
+ break;
}
if (!msg)
return 0;
- QDBusMarshall::listToMessage(*this, msg);
+ QDBusMarshall::listToMessage(*this, msg, d->signature);
return msg;
}
+/*!
+ \internal
+ Constructs a QDBusMessage by parsing the given DBusMessage object.
+*/
QDBusMessage QDBusMessage::fromDBusMessage(DBusMessage *dmsg)
{
QDBusMessage message;
@@ -140,40 +277,94 @@
message.d->type = dbus_message_get_type(dmsg);
message.d->path = QString::fromUtf8(dbus_message_get_path(dmsg));
message.d->interface = QString::fromUtf8(dbus_message_get_interface(dmsg));
- message.d->name = QString::fromUtf8(dbus_message_get_member(dmsg));
- message.d->sender = QString::fromUtf8(dbus_message_get_sender(dmsg));
+ message.d->name = message.d->type == DBUS_MESSAGE_TYPE_ERROR ?
+ QString::fromUtf8(dbus_message_get_error_name(dmsg)) :
+ QString::fromUtf8(dbus_message_get_member(dmsg));
+ message.d->service = QString::fromUtf8(dbus_message_get_sender(dmsg));
+ message.d->signature = QString::fromUtf8(dbus_message_get_signature(dmsg));
message.d->msg = dbus_message_ref(dmsg);
QDBusMarshall::messageToList(message, dmsg);
+ return message;
+}
+/*!
+ Creates a QDBusMessage that represents the same error as the QDBusError object.
+*/
+QDBusMessage QDBusMessage::fromError(const QDBusError &error)
+{
+ QDBusMessage message;
+ message.d->type = DBUS_MESSAGE_TYPE_ERROR;
+ message.d->name = error.name();
+ message << error.message();
return message;
}
+/*!
+ Returns the path of the object that this message is being sent to (in the case of a
+ method call) or being received from (for a signal).
+*/
QString QDBusMessage::path() const
{
return d->path;
}
+/*!
+ Returns the interface of the method being called (in the case of a method call) or of
+ the signal being received from.
+*/
QString QDBusMessage::interface() const
{
return d->interface;
}
+/*!
+ Returns the name of the signal that was emitted or the name of the error that was
+ received.
+ \sa member
+*/
QString QDBusMessage::name() const
{
return d->name;
}
-QString QDBusMessage::sender() const
+/*!
+ \fn QDBusMessage::member
+ Returns the name of the method being called.
+*/
+
+/*!
+ \fn QDBusMessage::method
+ \overload
+ Returns the name of the method being called.
+*/
+
+/*!
+ Returns the name of the service or the bus address of the remote method call.
+*/
+QString QDBusMessage::service() const
{
- return d->sender;
+ return d->service;
}
+/*!
+ \fn QDBusMessage::sender
+ Returns the unique name of the remote sender.
+*/
+
+/*!
+ Returns the timeout (in milliseconds) for this message to be processed.
+*/
int QDBusMessage::timeout() const
{
return d->timeout;
}
+/*!
+ Sets the timeout for this message to be processed.
+
+ \param ms the time, in milliseconds
+*/
void QDBusMessage::setTimeout(int ms)
{
d->timeout = ms;
@@ -205,6 +396,18 @@
return dbus_message_get_reply_serial(d->msg);
}
+/*!
+ Returns the signature of the signal that was received or for the output arguments
+ of a method call.
+*/
+QString QDBusMessage::signature() const
+{
+ return d->signature;
+}
+
+/*!
+ Returns the message type.
+*/
QDBusMessage::MessageType QDBusMessage::type() const
{
switch (d->type) {
@@ -222,11 +425,32 @@
}
#ifndef QT_NO_DEBUG
+QDebug operator<<(QDebug dbg, QDBusMessage::MessageType t)
+{
+ switch (t)
+ {
+ case QDBusMessage::MethodCallMessage:
+ return dbg << "MethodCall";
+ case QDBusMessage::ReplyMessage:
+ return dbg << "MethodReturn";
+ case QDBusMessage::SignalMessage:
+ return dbg << "Signal";
+ case QDBusMessage::ErrorMessage:
+ return dbg << "Error";
+ default:
+ return dbg << "Invalid";
+ }
+}
+
QDebug operator<<(QDebug dbg, const QDBusMessage &msg)
{
- dbg.nospace() << "QDBusMessage(" << msg.path() << ", " << msg.interface() << ", "
- << msg.name() << ", " << msg.sender() << ", "
- << static_cast<QList<QVariant> >(msg) << ")";
+ dbg.nospace() << "QDBusMessage(type=" << msg.type()
+ << ", service=" << msg.service()
+ << ", path=" << msg.path()
+ << ", interface=" << msg.interface()
+ << ", name=" << msg.name()
+ << ", signature=" << msg.signature()
+ << ", contents=" << static_cast<QList<QVariant> >(msg) << ")";
return dbg.space();
}
#endif
Index: qdbusmessage.h
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusmessage.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- qdbusmessage.h 23 Sep 2005 16:24:36 -0000 1.2
+++ qdbusmessage.h 15 Feb 2006 16:25:12 -0000 1.3
@@ -1,6 +1,8 @@
/* qdbusmessage.h QDBusMessage object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
@@ -15,22 +17,22 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, write to the Free Software Foundation
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSMESSAGE_H
#define QDBUSMESSAGE_H
-#include "dbus/qdbus.h"
-
+#include "qdbusmacros.h"
#include <QtCore/qlist.h>
#include <QtCore/qvariant.h>
#include <limits.h>
class QDBusMessagePrivate;
+class QDBusError;
struct DBusMessage;
class QDBUS_EXPORT QDBusMessage: public QList<QVariant>
@@ -49,23 +51,32 @@
static QDBusMessage signal(const QString &path, const QString &interface,
const QString &name);
- static QDBusMessage methodCall(const QString &service, const QString &path,
- const QString &interface, const QString &method);
+ static QDBusMessage methodCall(const QString &destination, const QString &path,
+ const QString &interface, const QString &method,
+ const QString &signature = QString());
static QDBusMessage methodReply(const QDBusMessage &other);
+ static QDBusMessage error(const QDBusMessage &other, const QString &name,
+ const QString &message = QString());
+ static QDBusMessage error(const QDBusMessage &other, const QDBusError &error);
QString path() const;
QString interface() const;
- QString name() const; //rename to member?
- QString sender() const; //rename to service?
+ QString name() const;
+ inline QString member() const { return name(); }
+ inline QString method() const { return name(); }
+ QString service() const;
+ inline QString sender() const { return service(); }
MessageType type() const;
int timeout() const;
void setTimeout(int ms);
+ QString signature() const;
//protected:
DBusMessage *toDBusMessage() const;
static QDBusMessage fromDBusMessage(DBusMessage *dmsg);
+ static QDBusMessage fromError(const QDBusError& error);
int serialNumber() const;
int replySerialNumber() const;
Index: qdbusmessage_p.h
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusmessage_p.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- qdbusmessage_p.h 23 Sep 2005 13:08:26 -0000 1.1
+++ qdbusmessage_p.h 15 Feb 2006 16:25:12 -0000 1.2
@@ -1,6 +1,8 @@
/* qdbusmessage.h QDBusMessage private object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
@@ -15,17 +17,16 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, write to the Free Software Foundation
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSMESSAGE_P_H
#define QDBUSMESSAGE_P_H
-#include <QtCore/qatomic.h>
-#include <QtCore/qstring.h>
-
+#include <qatomic.h>
+#include <qstring.h>
struct DBusMessage;
class QDBusMessagePrivate
@@ -34,7 +35,7 @@
QDBusMessagePrivate(QDBusMessage *qq);
~QDBusMessagePrivate();
- QString path, interface, name, service, method, sender;
+ QString service, path, interface, name, message, signature;
DBusMessage *msg;
DBusMessage *reply;
QDBusMessage *q;
--- NEW FILE: qdbusobject.cpp ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbusmessage.h"
#include "qdbusconnection.h"
#include "qdbusobject.h"
#include "qdbusinterface.h"
#include "qdbusstandardinterfaces.h"
#include "qdbuserror.h"
#include "qdbusxmlparser_p.h"
#include "qdbusobject_p.h"
#include "qdbusutil.h"
QDBusObject::QDBusObject(QDBusObjectPrivate* p, const QDBusConnection& conn)
:d(p), m_conn(conn)
{
}
QDBusObject::QDBusObject(const QDBusConnection& conn, const QString& service, const QString& path)
: m_conn(conn)
{
*this = m_conn.findObject(service, path);
}
QDBusObject::QDBusObject(const QDBusInterface& iface)
: m_conn(iface.connection())
{
*this = m_conn.findObject(iface.service(), iface.path());
}
QDBusObject::QDBusObject(const QDBusObject& other)
: d(other.d), m_conn(other.m_conn)
{
}
QDBusObject::~QDBusObject()
{
}
QDBusObject& QDBusObject::operator=(const QDBusObject& other)
{
#if 0
if (other.d)
other.d->ref.ref();
QDBusObjectPrivate* old = qAtomicSetPtr(&d, other.d);
if (old && !old->ref.deref())
m_conn.d->disposeOf(d);
#endif
d = other.d;
return *this;
}
QDBusConnection QDBusObject::connection() const
{
return m_conn;
}
QString QDBusObject::service() const
{
return d ? d->data->service : QString();
}
QString QDBusObject::path() const
{
return d ? d->data->path : QString();
}
QString QDBusObject::introspect() const
{
if (!d)
// not connected
return QString();
if (d->data->introspection.isNull()) {
// Try to introspect
QDBusIntrospectableInterface iface = *this;
QString xml = iface.introspect();
if (!m_conn.lastError().isValid()) {
// this will change the contents of d->data
QDBusXmlParser::parse(d, xml);
}
}
return d->data->introspection;
}
QSharedDataPointer<QDBusIntrospection::Object> QDBusObject::introspectionData() const
{
QSharedDataPointer<QDBusIntrospection::Object> retval;
if (d)
retval = const_cast<QDBusIntrospection::Object*>(d->data);
return retval;
}
QStringList QDBusObject::interfaces() const
{
introspect();
return d ? d->data->interfaces : QStringList();
}
QMap<QString, QDBusObject> QDBusObject::children() const
{
QMap<QString, QDBusObject> retval;
#if 0
if (!d)
return retval;
QString prefix = d->path;
if (!prefix.endsWith('/'))
prefix.append('/');
foreach (QString sub, d->childObjects)
retval.insert(sub, QDBusObject( m_conn.d->findObject(d->path, prefix + sub), m_conn ));
return retval;
#endif
qFatal("fixme!");
return retval;
}
bool QDBusObject::isValid() const
{
return d && m_conn.isConnected() && QDBusUtil::isValidBusName(d->data->service) &&
QDBusUtil::isValidObjectPath(d->data->path);
}
#if 0 // we don't have a way of determining if an object exists or not
bool QDBusObject::exists() const
{
if (!isValid())
return false;
// call a non-existant interface/method
QDBusMessage msg = QDBusMessage::methodCall(d->service, d->path,
"org.freedesktop.DBus.NonExistant", "NonExistant");
QDBusMessage reply = m_conn.sendWithReply(msg);
// ignore the reply
QDBusError err = m_conn.lastError();
if (!err.isValid()) {
qWarning("D-Bus call to %s:%s on a supposedly non-existant interface worked!",
qPrintable(d->service), qPrintable(d->path));
return true;
}
if (err.name == DBUS_ERROR_SERVICE_UNKNOWN ||
err.name == DBUS_ERROR_BAD_ADDRESS
return !m_conn.lastError().isValid();
}
#endif
--- NEW FILE: qdbusobject.h ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSOBJECT_H
#define QDBUSOBJECT_H
#include <QtCore/qstring.h>
#include <QtCore/qvariant.h>
#include <QtCore/qlist.h>
#include <QtCore/qshareddata.h>
#include "qdbusconnection.h"
#include "qdbusintrospection.h"
class QDBusInterface;
class QDBusObject;
template<class Interface>
inline Interface qdbus_cast(QDBusObject& obj, Interface * = 0);
template<class Interface>
inline const Interface qdbus_cast(const QDBusObject& obj, Interface * = 0);
class QDBusObjectPrivate;
/**
* QDBusObject
* Base object for DBUS objects imported and exported.
*/
class QDBUS_EXPORT QDBusObject
{
friend class QDBusConnection;
public:
// public constructors
/**
* Construct a QDBusObject referencing the remote object given.
*/
QDBusObject(const QDBusConnection& conn, const QString& service, const QString& path);
/**
* Copy constructor.
*/
QDBusObject(const QDBusObject& other);
/**
* Construct from an interface.
*/
QDBusObject(const QDBusInterface& iface);
// public destructors
/**
* Destructor.
*/
~QDBusObject();
public:
// public functions
/**
* Assignment operator
*/
QDBusObject& operator=(const QDBusObject&);
/**
* Returns the connection this object is bound to.
*/
QDBusConnection connection() const;
/**
* Returns the service this object is associated to.
*/
QString service() const;
/**
* Returns the path on the service this object is on.
*/
QString path() const;
/**
* Returns the introspection XML data of this object node.
*/
QString introspect() const;
/**
* Returns the introspection data for this object node.
*/
QSharedDataPointer<QDBusIntrospection::Object> introspectionData() const;
/**
* Returns all the interfaces in this object.
*/
QStringList interfaces() const;
/**
* Returns all the children object in this object.
*/
QMap<QString, QDBusObject> children() const;
/**
* Returns true if the object being referenced exists.
*/
//bool exists() const;
/**
* Returns true if we're referencing a valid object.
*/
bool isValid() const;
/**
* Cast this object to an interface, if possible.
*/
template<typename Interface>
inline operator Interface()
{ return qdbus_cast<Interface>(*this); }
/**
* Cast this object to an interface, if possible.
*/
template<typename Interface>
inline operator const Interface() const
{ return qdbus_cast<Interface>(*this); }
private:
QDBusObject(QDBusObjectPrivate*, const QDBusConnection& conn);
QSharedDataPointer<QDBusObjectPrivate> d;
QDBusConnection m_conn;
};
template<class Interface>
inline Interface qdbus_cast(QDBusObject& obj, Interface *)
{
return Interface(obj);
}
template<class Interface>
inline const Interface qdbus_cast(const QDBusObject& obj, Interface *)
{
return Interface(obj);
}
#endif // QDBUSOBJECT_H
--- NEW FILE: qdbusobject_p.h ---
/*
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#ifndef QDBUSOBJECTPRIVATE_H
#define QDBUSOBJECTPRIVATE_H
#include "QtCore/qatomic.h"
#include "QtCore/qstringlist.h"
#include "qdbusobject.h"
#include "qdbusinterface.h"
#include "qdbusconnection_p.h"
class QDBusObject;
class QDBusInterface;
class QDBusXmlParser;
class QDBusObjectPrivate: public QSharedData
{
public:
inline QDBusObjectPrivate(QDBusConnectionPrivate* ptr, const QString &service,
const QString &path)
: parent(ptr),
data( )
{
QDBusIntrospection::Object * d = ptr->findObject(service, path);
d->ref.ref();
data = d;
}
inline ~QDBusObjectPrivate()
{ parent->disposeOf(this); }
QDBusConnectionPrivate* parent;
const QDBusIntrospection::Object* data;
};
#endif
Index: qdbusserver.cpp
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusserver.cpp,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- qdbusserver.cpp 23 Sep 2005 13:08:26 -0000 1.1
+++ qdbusserver.cpp 15 Feb 2006 16:25:12 -0000 1.2
@@ -1,6 +1,8 @@
/* qdbusserver.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
@@ -15,8 +17,8 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, write to the Free Software Foundation
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
Index: qdbusserver.h
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusserver.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- qdbusserver.h 23 Sep 2005 16:24:36 -0000 1.2
+++ qdbusserver.h 15 Feb 2006 16:25:12 -0000 1.3
@@ -23,7 +23,7 @@
#ifndef QDBUSSERVER_H
#define QDBUSSERVER_H
-#include "dbus/qdbus.h"
+#include "qdbusmacros.h"
#include <QtCore/qobject.h>
#include <QtCore/qstring.h>
--- NEW FILE: qdbusstandardinterfaces.cpp ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbusstandardinterfaces.h"
QDBusPeerInterface::~QDBusPeerInterface()
{
}
QDBusIntrospectableInterface::~QDBusIntrospectableInterface()
{
}
QDBusPropertiesInterface::~QDBusPropertiesInterface()
{
}
QDBusBusInterface::~QDBusBusInterface()
{
}
const char* QDBusBusInterface::staticIntrospectionData()
{
// FIXME!
// This should be auto-generated!
return
"<interface name=\"org.freedesktop.DBus\">"
"<method name=\"RequestName\">"
"<arg direction=\"in\" type=\"s\"/>"
"<arg direction=\"in\" type=\"u\"/>"
"<arg direction=\"out\" type=\"u\"/>"
"</method>"
"<method name=\"ReleaseName\">"
"<arg direction=\"in\" type=\"s\"/>"
"<arg direction=\"out\" type=\"u\"/>"
"</method>"
"<method name=\"StartServiceByName\">"
"<arg direction=\"in\" type=\"s\"/>"
"<arg direction=\"in\" type=\"u\"/>"
"<arg direction=\"out\" type=\"u\"/>"
"</method>"
"<method name=\"Hello\">"
"<arg direction=\"out\" type=\"s\"/>"
"</method>"
"<method name=\"NameHasOwner\">"
"<arg direction=\"in\" type=\"s\"/>"
"<arg direction=\"out\" type=\"b\"/>"
"</method>"
"<method name=\"ListNames\">"
"<arg direction=\"out\" type=\"as\"/>"
"</method>"
"<method name=\"AddMatch\">"
"<arg direction=\"in\" type=\"s\"/>"
"</method>"
"<method name=\"RemoveMatch\">"
"<arg direction=\"in\" type=\"s\"/>"
"</method>"
"<method name=\"GetNameOwner\">"
"<arg direction=\"in\" type=\"s\"/>"
"<arg direction=\"out\" type=\"s\"/>"
"</method>"
"<method name=\"ListQueuedOwners\">"
"<arg direction=\"in\" type=\"s\"/>"
"<arg direction=\"out\" type=\"as\"/>"
"</method>"
"<method name=\"GetConnectionUnixUser\">"
"<arg direction=\"in\" type=\"s\"/>"
"<arg direction=\"out\" type=\"u\"/>"
"</method>"
"<method name=\"GetConnectionUnixProcessID\">"
"<arg direction=\"in\" type=\"s\"/>"
"<arg direction=\"out\" type=\"u\"/>"
"</method>"
"<method name=\"GetConnectionSELinuxSecurityContext\">"
"<arg direction=\"in\" type=\"s\"/>"
"<arg direction=\"out\" type=\"ay\"/>"
"</method>"
"<method name=\"ReloadConfig\">"
"</method>"
"<signal name=\"NameOwnerChanged\">"
"<arg type=\"s\"/>"
"<arg type=\"s\"/>"
"<arg type=\"s\"/>"
"</signal>"
"<signal name=\"NameLost\">"
"<arg type=\"s\"/>"
"</signal>"
"<signal name=\"NameAcquired\">"
"<arg type=\"s\"/>"
"</signal>"
"</interface>";
}
--- NEW FILE: qdbusstandardinterfaces.h ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUS_STANDARD_INTERFACES_H
#define QDBUS_STANDARD_INTERFACES_H
#include "qdbusinterface.h"
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
#include <dbus/dbus.h>
class QDBusConnection;
class QDBUS_EXPORT QDBusPeerInterface: public QDBusInterface
{
public:
static inline const char* staticInterfaceName()
{ return DBUS_INTERFACE_PEER; }
static inline const char* staticIntrospectionData()
{
return
"<interface name=\"org.freedesktop.DBus.Peer\">"
"<method name=\"Ping\" />"
"</interface>";
}
public:
explicit QDBusPeerInterface(const QDBusObject& obj)
: QDBusInterface(obj, staticInterfaceName())
{ }
QDBusPeerInterface(QDBusConnection& conn, const QString& service, const QString& path)
: QDBusInterface(conn, service, path, staticInterfaceName())
{ }
~QDBusPeerInterface();
inline virtual QString introspectionData() const
{ return staticIntrospectionData(); }
inline void ping()
{ call(QLatin1String("Ping")); }
};
class QDBUS_EXPORT QDBusIntrospectableInterface: public QDBusInterface
{
public:
static inline const char* staticInterfaceName()
{ return DBUS_INTERFACE_INTROSPECTABLE; }
static inline const char* staticIntrospectionData()
{
return
"<interface name=\"org.freedesktop.DBus.Introspectable\">"
"<method name=\"Introspect\">"
"<arg name=\"xml_data\" type=\"s\" direction=\"out\" />"
"</method>"
"</interface>";
}
public:
explicit QDBusIntrospectableInterface(const QDBusObject& obj)
: QDBusInterface(obj, staticInterfaceName())
{ }
QDBusIntrospectableInterface(QDBusConnection& conn, const QString& service, const QString& path)
: QDBusInterface(conn, service, path, staticInterfaceName())
{ }
~QDBusIntrospectableInterface();
inline virtual QString introspectionData() const
{ return staticIntrospectionData(); }
inline QString introspect()
{ return call(QLatin1String("Introspect")).at(0).toString(); }
};
class QDBUS_EXPORT QDBusPropertiesInterface: public QDBusInterface
{
public:
static inline const char* staticInterfaceName()
{ return DBUS_INTERFACE_PROPERTIES; }
static inline const char* staticIntrospectionData()
{
return
"<interface name=\"org.freedesktop.DBus.Properties\">"
"<method name=\"Get\">"
"<arg name=\"interface_name\" type=\"s\" direction=\"in\"/>"
"<arg name=\"property_name\" type=\"s\" direction=\"in\"/>"
"<arg name=\"value\" type=\"v\" direction=\"out\"/>"
"</method>"
"<method name=\"Set\">"
"<arg name=\"interface_name\" type=\"s\" direction=\"in\"/>"
"<arg name=\"property_name\" type=\"s\" direction=\"in\"/>"
"<arg name=\"value\" type=\"v\" direction=\"in\"/>"
"</method>";
}
public:
explicit QDBusPropertiesInterface(const QDBusObject& obj)
: QDBusInterface(obj, staticInterfaceName())
{ }
QDBusPropertiesInterface(QDBusConnection& conn, const QString& service, const QString& path)
: QDBusInterface(conn, service, path, staticInterfaceName())
{ }
~QDBusPropertiesInterface();
inline virtual QString introspectionData() const
{ return staticIntrospectionData(); }
inline void set(const QString& interfaceName, const QString& propertyName, QVariant value)
{ call(QLatin1String("Set.ssv"), interfaceName, propertyName, value); }
inline QVariant get(const QString& interfaceName, const QString& propertyName)
{ return call(QLatin1String("Get.ss"), interfaceName, propertyName).at(0); }
};
class QDBUS_EXPORT QDBusBusInterface: public QDBusInterface
{
public:
static inline const char* staticInterfaceName()
{ return DBUS_INTERFACE_DBUS; }
static const char* staticIntrospectionData();
public:
explicit QDBusBusInterface(const QDBusObject& obj)
: QDBusInterface(obj, staticInterfaceName())
{ }
QDBusBusInterface(QDBusConnection& conn, const QString& service, const QString& path)
: QDBusInterface(conn, service, path, staticInterfaceName())
{ }
~QDBusBusInterface();
inline virtual QString introspectionData() const
{ return staticIntrospectionData(); }
inline unsigned requestName(const QString& name, unsigned flags)
{ return call(QLatin1String("RequestName.su"), name, flags).at(0).toUInt(); }
inline unsigned releaseName(const QString& name)
{ return call(QLatin1String("ReleaseName.s"), name).at(0).toUInt(); }
inline unsigned startServiceByName(const QString& name, unsigned flags)
{ return call(QLatin1String("StartServiceByName.su"), name, flags).at(0).toUInt(); }
inline QString Hello()
{ return call(QLatin1String("Hello")).at(0).toString(); }
inline bool nameHasOwner(const QString& name)
{ return call(QLatin1String("NameHasOwner.s"), name).at(0).toBool(); }
inline QStringList listNames()
{ return call(QLatin1String("ListNames")).at(0).toStringList(); }
inline void addMatch(const QString& rule)
{ call(QLatin1String("AddMatch"), rule); }
inline void removeMatch(const QString& rule)
{ call(QLatin1String("RemoveMatch"), rule); }
inline QString getNameOwner(const QString& name)
{ return call(QLatin1String("GetNameOwner.s"), name).at(0).toString(); }
inline QStringList listQueuedOwners(const QString& name)
{ return call(QLatin1String("ListQueuedOwners.s"), name).at(0).toStringList(); }
inline quint32 getConnectionUnixUser(const QString& connectionName)
{ return call(QLatin1String("GetConnectionUnixUser.s"), connectionName).at(0).toUInt(); }
inline quint32 getConnectionUnixProcessID(const QString& connectionName)
{ return call(QLatin1String("GetConnectionUnixProcessID.s"), connectionName).at(0).toUInt(); }
inline QByteArray getConnectionSELinuxSecurityContext(const QString& connectionName)
{ return call(QLatin1String("GetConnectionSELinuxSecurityContext.s"), connectionName).at(0).toByteArray(); }
inline void reloadConfig()
{ call(QLatin1String("ReloadConfig")); }
};
namespace org {
namespace freedesktop {
namespace DBus {
typedef ::QDBusPeerInterface Peer;
typedef ::QDBusIntrospectableInterface Introspectable;
typedef ::QDBusPropertiesInterface Properties;
}
}
}
#endif
--- NEW FILE: qdbusthread.cpp ---
/* qdbusintegrator.cpp QDBusConnection private implementation
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <QtCore/qmutex.h>
#include <QtCore/qwaitcondition.h>
#include <dbus/dbus.h>
struct DBusMutex: public QMutex
{
inline DBusMutex()
: QMutex( QMutex::NonRecursive )
{ }
static DBusMutex* mutex_new()
{
return new DBusMutex;
}
static void mutex_free(DBusMutex *mutex)
{
delete mutex;
}
static dbus_bool_t mutex_lock(DBusMutex *mutex)
{
mutex->lock();
return true;
}
static dbus_bool_t mutex_unlock(DBusMutex *mutex)
{
mutex->unlock();
return true;
}
};
struct DBusCondVar: public QWaitCondition
{
inline DBusCondVar()
{ }
static DBusCondVar* condvar_new()
{
return new DBusCondVar;
}
static void condvar_free(DBusCondVar *cond)
{
delete cond;
}
static void condvar_wait(DBusCondVar *cond, DBusMutex *mutex)
{
cond->wait(mutex);
}
static dbus_bool_t condvar_wait_timeout(DBusCondVar *cond, DBusMutex *mutex, int msec)
{
return cond->wait(mutex, msec);
}
static void condvar_wake_one(DBusCondVar *cond)
{
cond->wakeOne();
}
static void condvar_wake_all(DBusCondVar *cond)
{
cond->wakeAll();
}
};
bool qDBusInitThreads()
{
static DBusThreadFunctions fcn = {
DBUS_THREAD_FUNCTIONS_ALL_MASK,
DBusMutex::mutex_new,
DBusMutex::mutex_free,
DBusMutex::mutex_lock,
DBusMutex::mutex_unlock,
DBusCondVar::condvar_new,
DBusCondVar::condvar_free,
DBusCondVar::condvar_wait,
DBusCondVar::condvar_wait_timeout,
DBusCondVar::condvar_wake_one,
DBusCondVar::condvar_wake_all,
0, 0, 0, 0, 0, 0, 0, 0
};
dbus_threads_init(&fcn);
return true;
}
--- NEW FILE: qdbustype.cpp ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbustype.h"
#include "qdbusvariant.h"
#include <dbus/dbus.h>
#include <QtCore/qstringlist.h>
/// \internal
class QDBusPrettyTypeBase
{
public:
struct Entry
{
const char* prettyName;
char signature;
};
enum Direction
{
In,
Out
};
enum Access
{
Read,
Write,
ReadWrite
};
// so that the compiler doesn't complain
virtual ~QDBusPrettyTypeBase() { }
virtual QString addElementsToArray(const QString& subType) = 0;
virtual QString addElementsToMap(const QString& key, const QString& value) = 0;
virtual QString addElementsToStruct(const QStringList& subTypes) = 0;
virtual const Entry* entryMap() = 0;
QString toString(const QDBusType& type);
QString toString(const QDBusTypeList& list);
};
/// \internal
class QDBusConventionalNames: public QDBusPrettyTypeBase
{
public:
virtual QString addElementsToArray(const QString& subType);
virtual QString addElementsToMap(const QString& key, const QString& value);
virtual QString addElementsToStruct(const QStringList& subTypes) ;
virtual const Entry* entryMap();
};
/// \internal
class QDBusQtNames: public QDBusPrettyTypeBase
{
public:
virtual QString addElementsToArray(const QString& subType);
virtual QString addElementsToMap(const QString& key, const QString& value);
virtual QString addElementsToStruct(const QStringList& subTypes) ;
virtual const Entry* entryMap();
};
//! \internal
class QDBusQVariantNames: public QDBusQtNames
{
public:
virtual QString addElementsToArray(const QString& subType);
virtual QString addElementsToMap(const QString& key, const QString& value);
virtual QString addElementsToStruct(const QStringList& subTypes) ;
};
#if 0
/*
* Parse the signature and return the max length that is valid
*/
static int parse(const char* signature)
{
if (!signature || !*signature)
return 0; // not valid
switch (signature[0]) {
case DBUS_TYPE_BOOLEAN:
case DBUS_TYPE_BYTE:
case DBUS_TYPE_INT16:
case DBUS_TYPE_INT32:
case DBUS_TYPE_UINT16:
case DBUS_TYPE_UINT32:
case DBUS_TYPE_INT64:
case DBUS_TYPE_UINT64:
case DBUS_TYPE_DOUBLE:
case DBUS_TYPE_STRING:
case DBUS_TYPE_OBJECT_PATH:
case DBUS_TYPE_SIGNATURE:
case DBUS_TYPE_VARIANT:
return 1;
case DBUS_TYPE_ARRAY: {
// check if it's a dict-entry array
if (signature[1] == DBUS_DICT_ENTRY_BEGIN_CHAR) {
// the first type must be ok and primitive (length 1)
char c[2] = { signature[2], 0 };
if (parse(c) != 1)
return 0; // not valid
// the rest must be a valid type too
int len = parse(signature + 3);
if (len == 0)
return 0; // not valid
// check the closing brace
if (signature[len + 3] != DBUS_DICT_ENTRY_END_CHAR)
return 0; // not valid
// it's valid
return len + 4;
}
// it's not a dict-entry, so it's ok as long as the internal type is ok too
int len = parse(signature + 1);
return len ? len + 1 : 0;
}
case DBUS_STRUCT_BEGIN_CHAR: {
// check that each entry is valid
int i = 1;
while (i) {
if (i > 1 && signature[i] == DBUS_STRUCT_END_CHAR)
break; // this is valid
int len = parse(signature + i);
if (len)
i += len;
else
i = 0;
}
return i;
}
default:
return 0; // not valid
}
}
#endif
static QString findInMap(char type, const QDBusPrettyTypeBase::Entry* map)
{
for ( ; map->signature; ++map)
if (type == map->signature)
return QLatin1String(map->prettyName);
return QString();
}
//
// Input MUST be valid
//
inline QString QDBusPrettyTypeBase::toString(const QDBusType& type)
{
const Entry* map = entryMap();
const QDBusTypeList subTypes = type.subTypes();
switch (type.dbusType()) {
case DBUS_TYPE_STRUCT: {
// handle a struct
// find its sub-types
QStringList subStrings;
QDBusTypeList subTypes = type.subTypes();
foreach (QDBusType t, subTypes)
subStrings << toString( t );
return addElementsToStruct(subStrings);
}
case DBUS_TYPE_DICT_ENTRY: {
Q_ASSERT_X(subTypes.size() == 2, "QDBusType::toString",
"maps must have exactly two elements");
QString key = findInMap( subTypes.at(0).dbusType(), map );
QString value = toString( subTypes.at(1) );
Q_ASSERT(!key.isNull());
return addElementsToMap( key, value );
}
case DBUS_TYPE_ARRAY: {
Q_ASSERT_X(subTypes.size() == 1, "QDBusType::toString",
"more than one element in array");
if (type.qvariantType() == QVariant::Map)
return toString( subTypes.first() );
return addElementsToArray( toString( subTypes.at(0) ) );
}
default: {
// normal, non-compound type
QString name = findInMap(type.dbusType(), map);
Q_ASSERT(!name.isNull());
return name;
}
}
}
const QDBusPrettyTypeBase::Entry* QDBusConventionalNames::entryMap()
{
static QDBusPrettyTypeBase::Entry translation[] = {
{ "BYTE", DBUS_TYPE_BYTE },
{ "BOOLEAN", DBUS_TYPE_BOOLEAN },
{ "INT16", DBUS_TYPE_INT16 },
{ "UINT16", DBUS_TYPE_UINT16 },
{ "INT32", DBUS_TYPE_INT32 },
{ "UINT32", DBUS_TYPE_UINT32 },
{ "INT64", DBUS_TYPE_INT64 },
{ "UINT64", DBUS_TYPE_UINT64 },
{ "DOUBLE", DBUS_TYPE_DOUBLE },
{ "STRING", DBUS_TYPE_STRING },
{ "OBJECT_PATH", DBUS_TYPE_OBJECT_PATH },
{ "SIGNATURE", DBUS_TYPE_SIGNATURE },
{ "VARIANT", DBUS_TYPE_VARIANT }
};
return translation;
}
QString QDBusConventionalNames::addElementsToStruct(const QStringList& subTypes)
{
return QString( QLatin1String("STRUCT of (%1)") )
.arg( subTypes.join( QLatin1String(",") ) );
}
QString QDBusConventionalNames::addElementsToMap(const QString& key, const QString& value)
{
return QString( QLatin1String("ARRAY of DICT_ENTRY of (%1,%2)") )
.arg(key).arg(value);
}
QString QDBusConventionalNames::addElementsToArray(const QString& subType)
{
return QString( QLatin1String("ARRAY of %1") )
.arg(subType);
}
const QDBusPrettyTypeBase::Entry* QDBusQtNames::entryMap()
{
static QDBusPrettyTypeBase::Entry translation[] = {
{ "quint8", DBUS_TYPE_BYTE },
{ "bool", DBUS_TYPE_BOOLEAN },
{ "qint16", DBUS_TYPE_INT16 },
{ "quint16", DBUS_TYPE_UINT16 },
{ "qint32", DBUS_TYPE_INT32 },
{ "quint32", DBUS_TYPE_UINT32 },
{ "qint64", DBUS_TYPE_INT64 },
{ "quint64", DBUS_TYPE_UINT64 },
{ "double", DBUS_TYPE_DOUBLE },
{ "QString", DBUS_TYPE_STRING },
{ "QString", DBUS_TYPE_OBJECT_PATH },
{ "QString", DBUS_TYPE_SIGNATURE },
{ "QDBusVariant", DBUS_TYPE_VARIANT }
};
return translation;
}
static inline QString templateArg(const QString& input)
{
if (input.endsWith('>'))
return input + ' ';
return input;
}
QString QDBusQtNames::addElementsToStruct(const QStringList& subTypes)
{
Q_UNUSED(subTypes);
return QLatin1String("QList"); // CHANGEME in the future
}
QString QDBusQtNames::addElementsToMap(const QString& key, const QString& value)
{
return QString( QLatin1String("QMap<%1, %2>") )
.arg(key)
.arg( templateArg(value) );
}
QString QDBusQtNames::addElementsToArray(const QString& subType)
{
if (subType == QLatin1String("quint8"))
// special case
return QLatin1String("QByteArray");
return QString( QLatin1String("QList<%1>") )
.arg( templateArg(subType) );
}
QString QDBusQVariantNames::addElementsToStruct(const QStringList& subTypes)
{
Q_UNUSED(subTypes);
return QLatin1String("QVariantList");
}
QString QDBusQVariantNames::addElementsToMap(const QString& key, const QString& value)
{
Q_UNUSED(key);
Q_UNUSED(value);
return QLatin1String("QVariantMap");
}
QString QDBusQVariantNames::addElementsToArray(const QString& subType)
{
if (subType == QLatin1String("quint8"))
// special case
return QLatin1String("QByteArray");
return QLatin1String("QVariantList");
}
/*!
\internal
*/
class QDBusTypePrivate: public QSharedData
{
public:
int code;
mutable QVariant::Type qvariantType;
mutable QByteArray signature;
QDBusTypeList subTypes;
inline QDBusTypePrivate()
: code(0), qvariantType(QVariant::Invalid)
{ }
};
/*!
\class QDBusType
Represents one single DBus type.
*/
/*!
\enum QDBusType::StringFormat
This enum is used in QDBusType::toString to determine which type of formatting
to apply to the DBus types:
\value ConventionalNames Use the DBus conventional names, such as STRING, BOOLEAN or
ARRAY of BYTE.
\value QtNames Use the Qt type names, such as QString, bool and QList<quint32>
\value QVariantNames Same as QtNames, but for containers, use QVariantList and QVariantMap
*/
/*!
Constructs an empty (invalid) type.
*/
QDBusType::QDBusType()
: d(0)
{
}
/*!
Constructs the type based on the given DBus type.
\param type the type
*/
QDBusType::QDBusType(int type)
{
char c[2] = { type, 0 };
*this = QDBusType(c);
}
/*!
Constructs the type based on the given QVariant type.
\param type the type
\sa QVariant::Type
*/
QDBusType::QDBusType(QVariant::Type type)
{
const char *sig = dbusSignature(type);
// it never returns NULL
if (sig[0] == '\0')
return;
d = new QDBusTypePrivate;
d->qvariantType = type;
d->code = sig[0];
if (sig[1] == '\0')
// single-letter type
return;
else if (sig[2] == '\0') {
// two-letter type
// must be an array
d->code = sig[0];
QDBusType t;
t.d = new QDBusTypePrivate;
t.d->code = sig[1];
d->subTypes << t;
}
else {
// the only longer type is "a{sv}"
Q_ASSERT(sig[1] == '{' && sig[5] == '\0');
static QDBusType map("a{sv}");
d->subTypes = map.d->subTypes;
}
}
/*!
Parses the given DBus signature and constructs the type it represents.
\param signature the signature to parse. It must represent one single type, but can
a container type.
*/
QDBusType::QDBusType(const char* signature)
{
if ( !dbus_signature_validate_single(signature, 0) )
return;
DBusSignatureIter iter;
dbus_signature_iter_init(&iter, signature);
*this = QDBusType(&iter);
if (d)
d->signature = signature;
}
/*!
Parses the given DBus signature and constructs the type it represents.
\param signature the signature to parse. It must represent one single type, but can
a container type.
*/
QDBusType::QDBusType(const QString& str)
{
*this = QDBusType( str.toUtf8().constData() );
}
/*!
Parses the given DBus signature and constructs the type it represents.
\param signature the signature to parse. It must represent one single type, but can
a container type.
*/
QDBusType::QDBusType(const QByteArray& str)
{
*this = QDBusType( str.constData() );
}
/*!
Creates a QDBusType object based on the current element pointed to by \a iter.
\param iter the iterator. Can be pointing to container types.
*/
QDBusType::QDBusType(DBusSignatureIter* iter)
: d(new QDBusTypePrivate)
{
if ( dbus_type_is_container( d->code = dbus_signature_iter_get_current_type(iter) ) ) {
// we have to recurse
if ( d->code == DBUS_TYPE_VARIANT )
return; // no we don't. dbus_type_is_container lies to us
// we have to recurse
DBusSignatureIter subiter;
dbus_signature_iter_recurse(iter, &subiter);
d->subTypes = QDBusTypeList(&subiter);
// sanity checking:
if ( d->code == DBUS_TYPE_ARRAY )
Q_ASSERT_X(d->subTypes.size() == 1, "QDBusType",
"more than one element in array");
else if (d->code == DBUS_TYPE_DICT_ENTRY )
Q_ASSERT_X(d->subTypes.size() == 2, "QDBusType",
"maps must have exactly two elements");
}
}
/*!
Copies the type from the other object.
*/
QDBusType::QDBusType(const QDBusType& other)
: d(other.d)
{
}
/*!
Release the resources associated with this type.
*/
QDBusType::~QDBusType()
{
}
/*!
Copies the type from the other object.
*/
QDBusType& QDBusType::operator=(const QDBusType& other)
{
d = other.d;
return *this;
}
/*!
Returns the DBus type for this type.
*/
int QDBusType::dbusType() const
{
return d ? d->code : DBUS_TYPE_INVALID;
}
/*!
Returns the DBus signature for this type and subtypes.
*/
QByteArray QDBusType::dbusSignature() const
{
if (!d)
return QByteArray();
if (!d->signature.isEmpty())
return d->signature;
if (d->subTypes.isEmpty())
return d->signature = QByteArray(1, d->code);
QByteArray retval;
switch (d->code) {
// can only be array, map or struct
case DBUS_TYPE_ARRAY:
Q_ASSERT_X(d->subTypes.size() == 1, "QDBusType::dbusSignature",
"more than one element in array");
retval += DBUS_TYPE_ARRAY;
retval += d->subTypes.at(0).dbusSignature();
break;
case DBUS_TYPE_DICT_ENTRY: {
Q_ASSERT_X(d->subTypes.size() == 2, "QDBusType::dbusSignature",
"maps must have exactly two elements");
QByteArray value = d->subTypes.at(1).dbusSignature();
char key = d->subTypes.at(0).dbusType();
Q_ASSERT(key != DBUS_TYPE_INVALID);
Q_ASSERT(!value.isEmpty());
retval.reserve(value.length() + 3);
retval = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING;
retval += key;
retval += value;
retval += DBUS_DICT_ENTRY_END_CHAR;
break;
}
case DBUS_TYPE_STRUCT:
retval = d->subTypes.dbusSignature();
retval.prepend(DBUS_STRUCT_BEGIN_CHAR);
retval.append(DBUS_STRUCT_END_CHAR);
break;
default:
Q_ASSERT_X(false, "QDBusType::dbusSignature", "invalid container type");
}
d->signature = retval;
return retval;
}
/*!
Returns the QVariant::Type for this entry.
*/
QVariant::Type QDBusType::qvariantType() const
{
if (d && d->qvariantType != QVariant::Invalid)
return d->qvariantType;
// check the special array cases:
if (isArray()) {
QDBusType t = arrayElement();
if (t.dbusType() == DBUS_TYPE_BYTE)
return QVariant::ByteArray;
else if (t.dbusType() == DBUS_TYPE_DICT_ENTRY)
return QVariant::Map;
else if (t.isBasic() && t.qvariantType() == QVariant::String)
return QVariant::StringList;
}
return qvariantType(dbusType());
}
/*!
Returns true if this type is a valid one.
*/
bool QDBusType::isValid() const
{
return d && d->code != DBUS_TYPE_INVALID;
}
/*!
Returns true if this type is a basic one.
\sa dbus_type_is_basic
*/
bool QDBusType::isBasic() const
{
return d && dbus_type_is_basic(d->code);
}
/*!
Returns true if this type is a container.
\sa dbus_type_is_container
*/
bool QDBusType::isContainer() const
{
return d && dbus_type_is_container(d->code);
}
/*!
Returns the subtypes of this type, if this is a container.
\sa isContainer
*/
QDBusTypeList QDBusType::subTypes() const
{
if (d)
return d->subTypes;
return QDBusTypeList();
}
/*!
Returns true if this type is an array.
\sa isContainer, arrayElement
*/
bool QDBusType::isArray() const
{
return dbusType() == DBUS_TYPE_ARRAY;
}
/*!
This is a convenience function that returns the element type of an array.
If this object is not an array, it returns an invalid QDBusType.
\sa isArray
*/
QDBusType QDBusType::arrayElement() const
{
if (isArray() && d->subTypes.count() == 1)
return d->subTypes.first();
return QDBusType();
}
/*!
Returns true if this type is a map (i.e., an array of dictionary entries).
\sa isContainer, isArray, arrayElement
*/
bool QDBusType::isMap() const
{
return arrayElement().dbusType() == DBUS_TYPE_DICT_ENTRY;
}
/*!
If this object is a map, returns the (basic) type that corresponds to the key type.
If this object is not a map, returns an invalid QDBusType.
\sa isMap
*/
QDBusType QDBusType::mapKey() const
{
if (isMap())
return arrayElement().d->subTypes.first();
return QDBusType();
}
/*!
If this object is a map, returns the type that corresponds to the value type.
If this object is not a map, returns an invalid QDBusType.
\sa isMap
*/
QDBusType QDBusType::mapValue() const
{
if (isMap())
return arrayElement().d->subTypes.at(1);
return QDBusType();
}
/*!
Returns true if the two types match.
*/
bool QDBusType::operator==(const QDBusType& other) const
{
if (!d && !other.d)
return true;
if (!d || !other.d)
return false;
return d->code == other.d->code && d->subTypes == other.d->subTypes;
}
/*!
Returns a string representation of this type.
*/
QString QDBusType::toString(StringFormat sf) const
{
switch (sf) {
case ConventionalNames:
return QDBusConventionalNames().toString(*this);
case QtNames:
return QDBusQtNames().toString(*this);
case QVariantNames:
return QDBusQVariantNames().toString(*this);
}
return QString(); // invalid
}
/*!
Converts the DBus type to QVariant::Type
*/
QVariant::Type QDBusType::qvariantType(int type)
{
char c[2] = { type, 0 };
return qvariantType(c);
}
/*!
Converts the DBus type signature to QVariant::Type.
*/
QVariant::Type QDBusType::qvariantType(const char* signature)
{
if (!signature)
return QVariant::Invalid;
// three special cases that don't validate as single:
if (qstrlen(signature) == 1) {
if (signature[0] == DBUS_TYPE_STRUCT)
return QVariant::List;
else if (signature[0] == DBUS_TYPE_DICT_ENTRY)
return QVariant::Map;
else if (signature[0] == DBUS_TYPE_ARRAY)
return QVariant::List;
}
// now we can validate
if ( !dbus_signature_validate_single(signature, 0) )
return QVariant::Invalid;
switch (signature[0])
{
case DBUS_TYPE_BOOLEAN:
return QVariant::Bool;
case DBUS_TYPE_INT16:
case DBUS_TYPE_INT32:
return QVariant::Int;
case DBUS_TYPE_BYTE:
case DBUS_TYPE_UINT16:
case DBUS_TYPE_UINT32:
return QVariant::UInt;
case DBUS_TYPE_INT64:
return QVariant::LongLong;
case DBUS_TYPE_UINT64:
return QVariant::ULongLong;
case DBUS_TYPE_DOUBLE:
return QVariant::Double;
case DBUS_TYPE_STRING:
case DBUS_TYPE_OBJECT_PATH:
case DBUS_TYPE_SIGNATURE:
return QVariant::String;
case DBUS_STRUCT_BEGIN_CHAR:
return QVariant::List; // change to QDBusStruct in the future
case DBUS_TYPE_VARIANT:
return QVariant::UserType; // must set user-type too
case DBUS_TYPE_ARRAY: // special case
// check if it's a string list
if (qvariantType(signature + 1) == QVariant::String)
return QVariant::StringList;
// maybe it's a byte array
if (DBUS_TYPE_BYTE == signature[1])
return QVariant::ByteArray;
// check if it's a dict
if (DBUS_DICT_ENTRY_BEGIN_CHAR == signature[1])
return QVariant::Map;
return QVariant::List;
default:
return QVariant::Invalid;
}
}
/*!
Converts the QVariant::Type to a DBus type code.
\param t the type to convert
*/
int QDBusType::dbusType(QVariant::Type t)
{
switch (t)
{
case QVariant::Bool:
return DBUS_TYPE_BOOLEAN;
case QVariant::Int:
return DBUS_TYPE_INT32;
case QVariant::UInt:
case QVariant::Char:
return DBUS_TYPE_UINT32;
case QVariant::LongLong:
return DBUS_TYPE_INT64;
case QVariant::ULongLong:
return DBUS_TYPE_UINT64;
case QVariant::Double:
return DBUS_TYPE_DOUBLE;
// from QMetaType:
case QMetaType::Short:
return DBUS_TYPE_INT16;
case QMetaType::UShort:
return DBUS_TYPE_UINT16;
case QMetaType::UChar:
return DBUS_TYPE_BYTE;
case QVariant::String:
case QVariant::Date:
case QVariant::Time:
case QVariant::DateTime:
return DBUS_TYPE_STRING;
case QVariant::Map:
// internal type information has been lost
return DBUS_TYPE_DICT_ENTRY;
case QVariant::List:
case QVariant::StringList:
case QVariant::ByteArray:
// could also be a struct...
return DBUS_TYPE_ARRAY;
case QVariant::UserType:
return DBUS_TYPE_VARIANT;
default:
break; // avoid compiler warnings
}
if (int(t) == QMetaTypeId<QDBusVariant>::qt_metatype_id())
return DBUS_TYPE_VARIANT;
return DBUS_TYPE_INVALID;
}
/*!
Converts the QVariant::Type to a DBus type signature.
\param t the type to convert
*/
const char* QDBusType::dbusSignature(QVariant::Type t)
{
switch (t)
{
case QVariant::Bool:
return DBUS_TYPE_BOOLEAN_AS_STRING;
case QVariant::Int:
return DBUS_TYPE_INT32_AS_STRING;
case QVariant::UInt:
case QVariant::Char:
return DBUS_TYPE_UINT32_AS_STRING;
case QMetaType::Short:
return DBUS_TYPE_INT16_AS_STRING;
case QMetaType::UShort:
return DBUS_TYPE_UINT16_AS_STRING;
case QMetaType::UChar:
return DBUS_TYPE_BYTE_AS_STRING;
case QVariant::LongLong:
return DBUS_TYPE_INT64_AS_STRING;
case QVariant::ULongLong:
return DBUS_TYPE_UINT64_AS_STRING;
case QVariant::Double:
return DBUS_TYPE_DOUBLE_AS_STRING;
case QVariant::String:
case QVariant::Date:
case QVariant::Time:
case QVariant::DateTime:
return DBUS_TYPE_STRING_AS_STRING;
case QVariant::Map:
// internal type information has been lost
return DBUS_TYPE_ARRAY_AS_STRING
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING; // a{sv}
case QVariant::StringList:
return DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_STRING_AS_STRING; // as
case QVariant::ByteArray:
return DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_BYTE_AS_STRING; // ay
case QVariant::List:
// not a string list
// internal list data has been lost
// could also be a struct...
return DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_VARIANT_AS_STRING; // av
default:
if (int(t) == qMetaTypeId<QDBusVariant>())
return DBUS_TYPE_VARIANT_AS_STRING;
return DBUS_TYPE_INVALID_AS_STRING;
}
}
/*!
Guesses the DBus type from the given variant.
*/
QDBusType QDBusType::guessFromVariant(const QVariant& variant, VariantListMode mode)
{
if (variant.type() == QVariant::List) {
// investigate deeper
QDBusType t;
t.d = new QDBusTypePrivate;
if (mode == ListIsArray) {
t.d->code = DBUS_TYPE_ARRAY;
const QVariantList list = variant.toList();
if (!list.isEmpty()) {
// check if all elements have the same type
QVariant::Type type = list.first().type();
foreach (const QVariant& v, list)
if (type != v.type()) {
// at least one is different
type = QVariant::Invalid;
break;
}
if (type != QVariant::Invalid) {
// all are of the same type
t.d->subTypes << guessFromVariant(list.first());
return t;
}
}
// internal information has been lost or there are many types
QDBusType nested;
nested.d = new QDBusTypePrivate;
nested.d->code = DBUS_TYPE_VARIANT;
t.d->subTypes << nested;
return t;
}
else {
// treat it as a struct
t.d->code = DBUS_TYPE_STRUCT;
// add the elements:
const QVariantList list = variant.toList();
foreach (const QVariant& v, list)
t.d->subTypes << guessFromVariant(v, mode);
return t;
}
}
else if (variant.type() == QVariant::Map) {
// investigate deeper
QDBusType t, t2, t3;
t2.d = new QDBusTypePrivate;
t2.d->code = DBUS_TYPE_DICT_ENTRY;
// the key
t3.d = new QDBusTypePrivate;
t3.d->code = DBUS_TYPE_STRING;
t2.d->subTypes << t3;
const QVariantMap map = variant.toMap();
if (!map.isEmpty()) {
// check if all elements have the same type
QVariantMap::const_iterator it = map.constBegin(),
end = map.constEnd();
QVariant::Type type = it.value().type();
for ( ; it != end; ++it)
if (type != it.value().type()) {
// at least one is different
type = QVariant::Invalid;
break;
}
if (type != QVariant::Invalid)
t2.d->subTypes << guessFromVariant(map.constBegin().value());
else {
// multiple types
t3.d->code = DBUS_TYPE_VARIANT;
t2.d->subTypes << t3;
}
}
else {
// information lost
t3.d->code = DBUS_TYPE_VARIANT;
t2.d->subTypes << t3;
}
t.d = new QDBusTypePrivate;
t.d->code = DBUS_TYPE_ARRAY;
t.d->subTypes << t2;
return t;
}
else
return QDBusType(variant.type());
}
/*!
\class QDBusTypeList
\brief A list of DBus types.
Represents zero or more DBus types in sequence, such as those used in argument lists
or in subtypes of structs and maps.
*/
/*!
\fn QDBusTypeList::QDBusTypeList()
Default constructor.
*/
/*!
\fn QDBusTypeList::QDBusTypeList(const QDBusTypeList& other)
Copy constructor.
\param other the list to copy
*/
/*!
\fn QDBusTypeList::QDBusTypeList(const QList<QDBusType>& other)
Copy constructor.
\param other the list to copy
*/
/*!
Constructs a type list by parsing the signature given.
\param signature the signature to be parsed
*/
QDBusTypeList::QDBusTypeList(const char* signature)
{
if (!signature || !*signature)
return; // empty
// validate it first
if ( !dbus_signature_validate(signature, 0) )
return;
// split it into components
DBusSignatureIter iter;
dbus_signature_iter_init(&iter, signature);
do {
*this << QDBusType(&iter);
} while (dbus_signature_iter_next(&iter));
}
/*!
Constructs a type list by parsing the elements on this iterator level.
\param iter the iterator containing the elements on this level
*/
QDBusTypeList::QDBusTypeList(DBusSignatureIter* iter)
{
do {
QDBusType item(iter);
if (!item.isValid()) {
clear();
return;
}
*this << item;
} while (dbus_signature_iter_next(iter));
}
/*!
Returns true if this type list can represent the inner components of a map.
*/
bool QDBusTypeList::canBeMap() const
{
return size() == 2 && at(0).isBasic();
}
/*!
Reconstructs the type signature that this type list represents.
*/
QByteArray QDBusTypeList::dbusSignature() const
{
QByteArray retval;
foreach (QDBusType t, *this)
retval += t.dbusSignature();
return retval;
}
--- NEW FILE: qdbustype.h ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSTYPE_H
#define QDBUSTYPE_H
#include <QtCore/qvariant.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qlist.h>
#include "qdbusmacros.h"
#include <dbus/dbus.h>
// forward declaration
class QDBusTypeList;
class QDBusTypePrivate;
class QDBUS_EXPORT QDBusType
{
public:
enum StringFormat
{
ConventionalNames,
QtNames,
QVariantNames
};
QDBusType();
explicit QDBusType(int type);
explicit QDBusType(QVariant::Type type);
explicit QDBusType(const char* signature);
explicit QDBusType(DBusSignatureIter*);
explicit QDBusType(const QString& str);
explicit QDBusType(const QByteArray& str);
QDBusType(const QDBusType& other);
~QDBusType();
QDBusType& operator=(const QDBusType& other);
QVariant::Type qvariantType() const;
int dbusType() const;
QByteArray dbusSignature() const;
bool isValid() const;
bool isBasic() const;
bool isContainer() const;
QDBusTypeList subTypes() const;
bool isArray() const;
QDBusType arrayElement() const;
bool isMap() const;
QDBusType mapKey() const;
QDBusType mapValue() const;
bool operator==(const QDBusType& other) const;
QString toString(StringFormat = QtNames) const;
static QVariant::Type qvariantType(int type);
static QVariant::Type qvariantType(const char* signature);
static int dbusType(QVariant::Type);
static const char* dbusSignature(QVariant::Type);
enum VariantListMode {
ListIsArray,
ListIsStruct
};
static QDBusType guessFromVariant(const QVariant &variant, VariantListMode = ListIsArray);
private:
QSharedDataPointer<QDBusTypePrivate> d;
};
class QDBUS_EXPORT QDBusTypeList: public QList<QDBusType>
{
public:
inline QDBusTypeList() { }
inline QDBusTypeList(const QDBusTypeList& other)
: QList<QDBusType>(other)
{ }
inline QDBusTypeList(const QList<QDBusType>& other)
: QList<QDBusType>(other)
{ }
QDBusTypeList(const char* signature);
QDBusTypeList(DBusSignatureIter*);
bool canBeMap() const;
inline QDBusTypeList& operator<<(const QDBusType& item)
{ QList<QDBusType>::operator<<(item); return *this; }
QByteArray dbusSignature() const;
};
#endif // QDBUSTYPE_H
--- NEW FILE: qdbusutil.cpp ---
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbusutil.h"
#include <dbus/dbus.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qregexp.h>
namespace QDBusUtil
{
bool isValidInterfaceName(const QString& ifaceName)
{
if (ifaceName.isEmpty() || ifaceName.length() > DBUS_MAXIMUM_NAME_LENGTH)
return false;
QStringList parts = ifaceName.split('.');
if (parts.count() < 2)
return false; // at least two parts
foreach (QString part, parts)
if (!isValidMemberName(part))
return false;
return true;
}
bool isValidUniqueConnectionName(const QString &connName)
{
if (connName.isEmpty() || connName.length() > DBUS_MAXIMUM_NAME_LENGTH ||
!connName.startsWith(':'))
return false;
QStringList parts = connName.mid(1).split('.');
if (parts.count() < 1)
return false;
QRegExp regex("[a-zA-Z0-9_-]+");
foreach (QString part, parts)
if (!regex.exactMatch(part))
return false;
return true;
}
bool isValidBusName(const QString &busName)
{
if (busName.isEmpty() || busName.length() > DBUS_MAXIMUM_NAME_LENGTH)
return false;
if (busName.startsWith(':'))
return isValidUniqueConnectionName(busName);
QStringList parts = busName.split('.');
if (parts.count() < 1)
return false;
QRegExp regex("[a-zA-Z_-][a-zA-Z0-9_-]*");
foreach (QString part, parts)
if (!regex.exactMatch(part))
return false;
return true;
}
bool isValidMemberName(const QString &memberName)
{
if (memberName.isEmpty() || memberName.length() > DBUS_MAXIMUM_NAME_LENGTH)
return false;
QRegExp regex("[a-zA-Z0-9_]+");
return regex.exactMatch(memberName);
}
bool isValidErrorName(const QString &errorName)
{
return isValidInterfaceName(errorName);
}
bool isValidObjectPath(const QString &path)
{
if (path == QLatin1String("/"))
return true;
if (!path.startsWith('/') || path.indexOf(QLatin1String("//")) != -1 ||
path.endsWith('/'))
return false;
QStringList parts = path.split('/');
Q_ASSERT(parts.count() >= 1);
parts.removeFirst(); // it starts with /, so we get an empty first part
QRegExp regex("[a-zA-Z0-9_]+");
foreach (QString part, parts)
if (!regex.exactMatch(part))
return false;
return true;
}
bool isValidSignature(const QString &signature)
{
return dbus_signature_validate(signature.toUtf8(), 0);
}
bool isValidSingleSignature(const QString &signature)
{
return dbus_signature_validate_single(signature.toUtf8(), 0);
}
} // namespace QDBusUtil
--- NEW FILE: qdbusutil.h ---
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSUTIL_H
#define QDBUSUTIL_H
#include <QtCore/qstring.h>
#include "qdbusmacros.h"
namespace QDBusUtil
{
bool isValidInterfaceName(const QString &ifaceName) QDBUS_EXPORT;
bool isValidUniqueConnectionName(const QString &busName) QDBUS_EXPORT;
bool isValidBusName(const QString &busName) QDBUS_EXPORT;
bool isValidMemberName(const QString &memberName) QDBUS_EXPORT;
bool isValidErrorName(const QString &errorName) QDBUS_EXPORT;
bool isValidObjectPath(const QString &path) QDBUS_EXPORT;
bool isValidSignature(const QString &signature) QDBUS_EXPORT;
bool isValidSingleSignature(const QString &signature) QDBUS_EXPORT;
}
#endif
Index: qdbusvariant.h
===================================================================
RCS file: /cvs/dbus/dbus/qt/qdbusvariant.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- qdbusvariant.h 23 Sep 2005 16:24:36 -0000 1.2
+++ qdbusvariant.h 15 Feb 2006 16:25:12 -0000 1.3
@@ -1,6 +1,8 @@
/* qdbusvariant.h DBUS variant struct
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
@@ -15,23 +17,21 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program; if not, write to the Free Software Foundation
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSVARIANT_H
#define QDBUSVARIANT_H
-#include "dbus/qdbus.h"
-
-#include <QtCore/qmetatype.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qvariant.h>
+#include "qdbusmacros.h"
+#include "qdbustype.h"
+#include <qvariant.h>
struct QDBUS_EXPORT QDBusVariant
{
- QString signature;
+ QDBusType type;
QVariant value;
};
Q_DECLARE_METATYPE(QDBusVariant)
--- NEW FILE: qdbusxmlparser.cpp ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbusxmlparser_p.h"
#include "qdbusinterface.h"
#include "qdbusinterface_p.h"
#include "qdbusconnection_p.h"
#include "qdbusobject_p.h"
#include <QtXml/qdom.h>
#include <QtCore/qmap.h>
#include <QtCore/qvariant.h>
#include <QtCore/qtextstream.h>
static QDBusIntrospection::Annotations
parseAnnotations(const QDomElement& elem)
{
QDBusIntrospection::Annotations retval;
QDomNodeList list = elem.elementsByTagName("annotation");
for (int i = 0; i < list.count(); ++i)
{
QDomElement ann = list.item(i).toElement();
if (ann.isNull())
continue;
QString name = ann.attribute("name"),
value = ann.attribute("value");
if (name.isEmpty())
continue;
retval.insert(name, value);
}
return retval;
}
static QDBusType
parseType(const QString& type)
{
if (type.isEmpty())
return QDBusType();
return QDBusType(type);
}
static QDBusIntrospection::Arguments
parseArgs(const QDomElement& elem, const QLatin1String& direction, bool acceptEmpty = false)
{
QDBusIntrospection::Arguments retval;
QDomNodeList list = elem.elementsByTagName("arg");
for (int i = 0; i < list.count(); ++i)
{
QDomElement arg = list.item(i).toElement();
if (arg.isNull())
continue;
if ((acceptEmpty && !arg.hasAttribute("direction")) ||
arg.attribute("direction") == direction) {
QDBusIntrospection::Argument argData;
if (arg.hasAttribute("name"))
argData.name = arg.attribute("name"); // can be empty
argData.type = parseType(arg.attribute("type"));
if (!argData.type.isValid())
continue;
retval << argData;
}
}
return retval;
}
QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
const QString& xmlData, QDBusConnectionPrivate* store)
: m_service(service), m_path(path), m_store(store)
{
QDomDocument doc;
doc.setContent(xmlData);
m_node = doc.firstChildElement("node");
}
QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
const QDomElement& node, QDBusConnectionPrivate* store)
: m_service(service), m_path(path), m_node(node), m_store(store)
{
}
void QDBusXmlParser::parse(const QDBusObjectPrivate* d, const QString &xml)
{
QDBusXmlParser parser(d->data->service, d->data->path, xml, d->parent);
parser.object();
parser.interfaces();
}
QDBusIntrospection::Interfaces
QDBusXmlParser::interfaces() const
{
QDBusIntrospection::Interfaces retval;
if (m_node.isNull())
return retval;
QDomNodeList interfaces = m_node.elementsByTagName("interface");
for (int i = 0; i < interfaces.count(); ++i)
{
QDomElement iface = interfaces.item(i).toElement();
QString ifaceName = iface.attribute("name");
if (iface.isNull() || ifaceName.isEmpty())
continue; // for whatever reason
QDBusIntrospection::Interface *ifaceData;
if (m_store) {
QSharedDataPointer<QDBusIntrospection::Interface> knownData =
m_store->findInterface(ifaceName);
if (!knownData.constData()->introspection.isEmpty()) {
// it's already known
// we don't have to re-parse
retval.insert(ifaceName, knownData);
continue;
}
// ugly, but ok
// we don't want to detach
// we *WANT* to modify the shared data
ifaceData = const_cast<QDBusIntrospection::Interface*>( knownData.constData() );
}
else {
ifaceData = new QDBusIntrospection::Interface;
ifaceData->name = ifaceName;
}
{
// save the data
QTextStream ts(&ifaceData->introspection);
iface.save(ts,2);
}
// parse annotations
ifaceData->annotations = parseAnnotations(iface);
// parse methods
QDomNodeList list = iface.elementsByTagName("method");
for (int j = 0; j < list.count(); ++j)
{
QDomElement method = list.item(j).toElement();
QString methodName = method.attribute("name");
if (method.isNull() || methodName.isEmpty())
continue;
QDBusIntrospection::Method methodData;
methodData.name = methodName;
// parse arguments
methodData.inputArgs = parseArgs(method, QLatin1String("in"));
methodData.outputArgs = parseArgs(method, QLatin1String("out"));
methodData.annotations = parseAnnotations(method);
// add it
ifaceData->methods.insert(methodName, methodData);
}
// parse signals
list = iface.elementsByTagName("signal");
for (int j = 0; j < list.count(); ++j)
{
QDomElement signal = list.item(j).toElement();
QString signalName = signal.attribute("name");
if (signal.isNull() || signalName.isEmpty())
continue;
QDBusIntrospection::Signal signalData;
signalData.name = signalName;
// parse data
signalData.outputArgs = parseArgs(signal, QLatin1String("out"), true);
signalData.annotations = parseAnnotations(signal);
// add it
ifaceData->signals_.insert(signalName, signalData);
}
// parse properties
list = iface.elementsByTagName("property");
for (int j = 0; j < list.count(); ++j)
{
QDomElement property = list.item(j).toElement();
QString propertyName = property.attribute("name");
if (property.isNull() || propertyName.isEmpty())
continue;
QDBusIntrospection::Property propertyData;
// parse data
propertyData.name = propertyName;
propertyData.type = parseType(property.attribute("type"));
propertyData.annotations = parseAnnotations(property);
if (!propertyData.type.isValid())
// cannot be!
continue;
QString access = property.attribute("access");
if (access.isEmpty())
// can't be empty either!
continue;
else if (access == QLatin1String("read"))
propertyData.access = QDBusIntrospection::Property::Read;
else if (access == QLatin1String("write"))
propertyData.access = QDBusIntrospection::Property::Write;
else if (access == QLatin1String("readwrite"))
propertyData.access = QDBusIntrospection::Property::ReadWrite;
else
continue; // invalid one!
// add it
ifaceData->properties.insert(propertyName, propertyData);
}
// add it
retval.insert(ifaceName, QSharedDataPointer<QDBusIntrospection::Interface>(ifaceData));
}
return retval;
}
QSharedDataPointer<QDBusIntrospection::Object>
QDBusXmlParser::object() const
{
QSharedDataPointer<QDBusIntrospection::Object> retval;
if (m_node.isNull())
return retval;
// check if the store knows about this one
QDBusIntrospection::Object* objData;
if (m_store) {
retval = objData = m_store->findObject(m_service, m_path);
}
else {
objData = new QDBusIntrospection::Object;
objData->service = m_service;
objData->path = m_path;
}
// check if we have anything to process
if (objData->introspection.isNull() && !m_node.firstChild().isNull()) {
// yes, introspect this object
QTextStream ts(&objData->introspection);
m_node.save(ts,2);
QDomNodeList objects = m_node.elementsByTagName("node");
for (int i = 0; i < objects.count(); ++i) {
QDomElement obj = objects.item(i).toElement();
QString objName = obj.attribute("name");
if (obj.isNull() || objName.isEmpty())
continue; // for whatever reason
objData->childObjects.append(objName);
}
QDomNodeList interfaces = m_node.elementsByTagName("interface");
for (int i = 0; i < interfaces.count(); ++i) {
QDomElement iface = interfaces.item(i).toElement();
QString ifaceName = iface.attribute("name");
if (iface.isNull() || ifaceName.isEmpty())
continue;
objData->interfaces.append(ifaceName);
}
}
return retval;
}
QSharedDataPointer<QDBusIntrospection::ObjectTree>
QDBusXmlParser::objectTree() const
{
QSharedDataPointer<QDBusIntrospection::ObjectTree> retval;
if (m_node.isNull())
return retval;
retval = new QDBusIntrospection::ObjectTree;
retval->service = m_service;
retval->path = m_path;
QTextStream ts(&retval->introspection);
m_node.save(ts,2);
// interfaces are easy:
retval->interfaceData = interfaces();
retval->interfaces = retval->interfaceData.keys();
// sub-objects are slightly more difficult:
QDomNodeList objects = m_node.elementsByTagName("node");
for (int i = 0; i < objects.count(); ++i) {
QDomElement obj = objects.item(i).toElement();
QString objName = obj.attribute("name");
if (obj.isNull() || objName.isEmpty())
continue; // for whatever reason
// check if we have anything to process
if (!obj.firstChild().isNull()) {
// yes, introspect this object
QString xml;
QTextStream ts(&xml);
obj.save(ts,0);
// parse it
QString objAbsName = m_path;
if (!objAbsName.endsWith('/'))
objAbsName.append('/');
objAbsName += objName;
QDBusXmlParser parser(m_service, objAbsName, obj, m_store);
retval->childObjectData.insert(objName, parser.objectTree());
}
retval->childObjects << objName;
}
return QSharedDataPointer<QDBusIntrospection::ObjectTree>( retval );
}
--- NEW FILE: qdbusxmlparser_p.h ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSXMLPARSER_H
#define QDBUSXMLPARSER_H
#include <QtCore/qmap.h>
#include <QtXml/qdom.h>
#include "qdbusmacros.h"
#include "qdbusintrospection.h"
class QDBusConnectionPrivate;
class QDBusObjectPrivate;
/**
* @internal
*/
class QDBusXmlParser
{
QString m_service;
QString m_path;
QDomElement m_node;
QDBusConnectionPrivate* m_store;
public:
QDBusXmlParser(const QString& service, const QString& path,
const QString& xmlData, QDBusConnectionPrivate* store = 0);
QDBusXmlParser(const QString& service, const QString& path,
const QDomElement& node, QDBusConnectionPrivate* store = 0);
QDBusIntrospection::Interfaces interfaces() const;
QSharedDataPointer<QDBusIntrospection::Object> object() const;
QSharedDataPointer<QDBusIntrospection::ObjectTree> objectTree() const;
static void parse(const QDBusObjectPrivate* d, const QString &xml);
};
#endif
More information about the dbus-commit
mailing list