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.
This commit is contained in:
Thiago Macieira 2006-02-15 16:25:12 +00:00
parent 120d4ae484
commit c2432800b1
36 changed files with 5769 additions and 491 deletions

View file

@ -6,11 +6,19 @@ dbusincludedir=$(includedir)/dbus-1.0/dbus
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 @@ libdbus_qt4_1_la_SOURCES = \
$(top_srcdir)/qt/qdbusmarshall.cpp \
$(top_srcdir)/qt/qdbusmessage.cpp \
$(top_srcdir)/qt/qdbusserver.cpp \
$(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)/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/qdbusconnection_p.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

10
qt/README Normal file
View file

@ -0,0 +1,10 @@
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@trolltech.com>

View file

@ -0,0 +1,64 @@
/* -*- mode: C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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"

44
qt/qdbusabstractadaptor.h Normal file
View file

@ -0,0 +1,44 @@
/* -*- mode: C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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

View file

@ -1,6 +1,8 @@
/* qdbusconnection.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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 @@ bool QDBusConnection::send(const QDBusMessage &message) const
{
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 @@ QDBusMessage QDBusConnection::sendWithReply(const QDBusMessage &message) const
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, const QString &interface,
QObject *object)
bool QDBusConnection::registerObject(const QString &path, QObject *object, RegisterOptions options)
{
if (!d || !d->connection || !object || path.isEmpty() || interface.isEmpty())
return registerObject(path, QString(), object, options);
}
bool QDBusConnection::registerObject(const QString &path, const QString &interface,
QObject *object, RegisterOptions options)
{
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 @@ void QDBusConnection::unregisterObject(const QString &path)
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 @@ QString QDBusConnection::baseService() const
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);
return false;
}
return true;
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;
}
#include "qdbusconnection.moc"
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 retval == DBUS_RELEASE_NAME_REPLY_RELEASED;
}
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"

View file

@ -1,6 +1,8 @@
/* qdbusconnection.h QDBusConnection object
*
* Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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 @@ public:
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 @@ public:
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 @@ public:
QT_STATIC_CONST char *default_connection_name;
private:
friend class QDBusObject;
QDBusConnectionPrivate *d;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QDBusConnection::RegisterOptions)
#endif

View file

@ -1,6 +1,8 @@
/* qdbusconnection_p.h QDBusConnection private object
*
* Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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 @@ class QDBusConnectionPrivate: public QObject
{
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 @@ public:
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

View file

@ -1,6 +1,8 @@
/* qdbuserror.h QDBusError object
*
* Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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 @@ QDBusError::QDBusError(const DBusError *error)
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)
{

View file

@ -1,6 +1,8 @@
/* qdbuserror.h QDBusError object
*
* Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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; }

File diff suppressed because it is too large Load diff

256
qt/qdbusinterface.cpp Normal file
View file

@ -0,0 +1,256 @@
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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);
}

310
qt/qdbusinterface.h Normal file
View file

@ -0,0 +1,310 @@
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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

67
qt/qdbusinterface_p.h Normal file
View file

@ -0,0 +1,67 @@
/*
*
* Copyright (C) 2006 Thiago José Macieira <thiago@kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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

380
qt/qdbusintrospection.cpp Normal file
View file

@ -0,0 +1,380 @@
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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;
}

148
qt/qdbusintrospection.h Normal file
View file

@ -0,0 +1,148 @@
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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

36
qt/qdbusmacros.h Normal file
View file

@ -0,0 +1,36 @@
/* qdbusmessage.h QDBusMessage object
*
* Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef QDBUSMACROS_H
#define QDBUSMACROS_H
#include <QtCore/qglobal.h>
#ifndef QDBUS_EXPORT
#ifdef QDBUS_MAKEDLL
# define QDBUS_EXPORT Q_DECL_EXPORT
#else
# define QDBUS_EXPORT Q_DECL_IMPORT
#endif
#endif
#endif

View file

@ -1,6 +1,8 @@
/* qdbusmarshall.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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 @@ static QVariant qFetchParameter(DBusMessageIter *it)
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 @@ static QVariant qFetchParameter(DBusMessageIter *it)
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 @@ static QVariant qFetchParameter(DBusMessageIter *it)
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 @@ void QDBusMarshall::messageToList(QList<QVariant> &list, DBusMessage *message)
} 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);
}
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;
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;
if (!type.isValid()) {
// guess it from the variant
type = QDBusType::guessFromVariant(var);
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 };
// 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
return DBusArgs[qVariantListType(list)];
}
// 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;
}
static void qListToIterator(DBusMessageIter *it, const QList<QVariant> &list);
static void qVariantToIterator(DBusMessageIter *it, const QVariant &var)
{
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 };
// these really are static asserts
Q_ASSERT(QVariant::Invalid == 0);
Q_ASSERT(QVariant::Int == 2);
Q_ASSERT(QVariant::Double == 6);
switch (var.type()) {
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:
dbus_message_iter_append_basic(it, Variant2DBus[var.type()],
var.constData());
break;
case QVariant::String:
qAppendToMessage(it, var.toString());
break;
if (type.isBasic())
// QVariant can handle this on its own
return true;
// 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 qVariantToIteratorInternal(DBusMessageIter *it, const QVariant &var,
const QDBusType &type);
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)
{
dbus_message_iter_append_basic(it, type.dbusType(), &arg);
}
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::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);
}
static void qAppendStructToMessage(DBusMessageIter *it, const QDBusTypeList &typeList,
const QVariantList &list)
{
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)
{
if (list.isEmpty())
return;
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()));
}

View file

@ -1,6 +1,8 @@
/* qdbusmarshall.h QDBusMarshall object
*
* Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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);
};

View file

@ -1,6 +1,8 @@
/* qdbusmessage.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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 @@ QDBusMessagePrivate::~QDBusMessagePrivate()
}
///////////////
/*!
\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 @@ QDBusMessage QDBusMessage::signal(const QString &path, const QString &interface,
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 @@ QDBusMessage QDBusMessage::methodReply(const QDBusMessage &other)
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 @@ QDBusMessage::QDBusMessage(const QDBusMessage &other)
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 @@ QDBusMessage &QDBusMessage::operator=(const QDBusMessage &other)
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 @@ DBusMessage *QDBusMessage::toDBusMessage() const
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 @@ QDBusMessage QDBusMessage::fromDBusMessage(DBusMessage *dmsg)
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 @@ int QDBusMessage::replySerialNumber() const
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 @@ QDBusMessage::MessageType QDBusMessage::type() const
}
#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

View file

@ -1,6 +1,8 @@
/* qdbusmessage.h QDBusMessage object
*
* Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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 @@ public:
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;

View file

@ -1,6 +1,8 @@
/* qdbusmessage.h QDBusMessage private object
*
* Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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 @@ public:
QDBusMessagePrivate(QDBusMessage *qq);
~QDBusMessagePrivate();
QString path, interface, name, service, method, sender;
QString service, path, interface, name, message, signature;
DBusMessage *msg;
DBusMessage *reply;
QDBusMessage *q;

173
qt/qdbusobject.cpp Normal file
View file

@ -0,0 +1,173 @@
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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

161
qt/qdbusobject.h Normal file
View file

@ -0,0 +1,161 @@
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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

69
qt/qdbusobject_p.h Normal file
View file

@ -0,0 +1,69 @@
/*
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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

View file

@ -1,6 +1,8 @@
/* qdbusserver.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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.
*
*/

View file

@ -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>

View file

@ -0,0 +1,114 @@
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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>";
}

View file

@ -0,0 +1,218 @@
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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

116
qt/qdbusthread.cpp Normal file
View file

@ -0,0 +1,116 @@
/* qdbusintegrator.cpp QDBusConnection private implementation
*
* Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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;
}

1151
qt/qdbustype.cpp Normal file

File diff suppressed because it is too large Load diff

119
qt/qdbustype.h Normal file
View file

@ -0,0 +1,119 @@
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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

133
qt/qdbusutil.cpp Normal file
View file

@ -0,0 +1,133 @@
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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

50
qt/qdbusutil.h Normal file
View file

@ -0,0 +1,50 @@
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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

View file

@ -1,6 +1,8 @@
/* qdbusvariant.h DBUS variant struct
*
* Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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)

347
qt/qdbusxmlparser.cpp Normal file
View file

@ -0,0 +1,347 @@
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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 );
}

59
qt/qdbusxmlparser_p.h Normal file
View file

@ -0,0 +1,59 @@
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira@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