summaryrefslogtreecommitdiffstats
path: root/qt/src
diff options
context:
space:
mode:
authorThiago Macieira <thiago@kde.org>2006-06-04 15:52:05 +0000
committerThiago Macieira <thiago@kde.org>2006-06-04 15:52:05 +0000
commitedbf2bfc109ce94b2604ea20328fda25542e4383 (patch)
tree3281d191fa9dde9f1f26b947b145d02373f031b0 /qt/src
parent435c7af9b605c3ffc8641142b6d7add18bf7080b (diff)
* qt/: Update to Subversion r548032.
This includes a big reorganisation of the files inside the subdir. We really need a version control system that supports moving of files. I'm not bothering with history anyways anymore, since the bindings will be moved out to git. The history should be restored from Subversion when that happens.
Diffstat (limited to 'qt/src')
-rw-r--r--qt/src/.cvsignore11
-rw-r--r--qt/src/Makefile.am70
-rw-r--r--qt/src/qdbus.h52
-rw-r--r--qt/src/qdbusabstractadaptor.cpp336
-rw-r--r--qt/src/qdbusabstractadaptor.h50
-rw-r--r--qt/src/qdbusabstractadaptor_p.h127
-rw-r--r--qt/src/qdbusabstractinterface.cpp389
-rw-r--r--qt/src/qdbusabstractinterface.h257
-rw-r--r--qt/src/qdbusabstractinterface_p.h72
-rw-r--r--qt/src/qdbusbus.cpp302
-rw-r--r--qt/src/qdbusbus.h158
-rw-r--r--qt/src/qdbusconnection.cpp753
-rw-r--r--qt/src/qdbusconnection.h124
-rw-r--r--qt/src/qdbusconnection_p.h245
-rw-r--r--qt/src/qdbuserror.cpp244
-rw-r--r--qt/src/qdbuserror.h93
-rw-r--r--qt/src/qdbusintegrator.cpp1552
-rw-r--r--qt/src/qdbusinterface.cpp203
-rw-r--r--qt/src/qdbusinterface.h63
-rw-r--r--qt/src/qdbusinterface_p.h65
-rw-r--r--qt/src/qdbusinternalfilters.cpp235
-rw-r--r--qt/src/qdbusintrospection.cpp403
-rw-r--r--qt/src/qdbusintrospection_p.h147
-rw-r--r--qt/src/qdbusmacros.h60
-rw-r--r--qt/src/qdbusmarshall.cpp554
-rw-r--r--qt/src/qdbusmarshall_p.h57
-rw-r--r--qt/src/qdbusmessage.cpp706
-rw-r--r--qt/src/qdbusmessage.h99
-rw-r--r--qt/src/qdbusmessage_p.h50
-rw-r--r--qt/src/qdbusmetaobject.cpp689
-rw-r--r--qt/src/qdbusmetaobject_p.h96
-rw-r--r--qt/src/qdbusmisc.cpp156
-rw-r--r--qt/src/qdbusreply.h132
-rw-r--r--qt/src/qdbusserver.cpp61
-rw-r--r--qt/src/qdbusserver.h48
-rw-r--r--qt/src/qdbusthread.cpp116
-rw-r--r--qt/src/qdbustype.cpp847
-rw-r--r--qt/src/qdbustype_p.h109
-rw-r--r--qt/src/qdbustypehelper_p.h231
-rw-r--r--qt/src/qdbusutil.cpp235
-rw-r--r--qt/src/qdbusutil.h55
-rw-r--r--qt/src/qdbusxmlgenerator.cpp194
-rw-r--r--qt/src/qdbusxmlparser.cpp308
-rw-r--r--qt/src/qdbusxmlparser_p.h53
44 files changed, 10807 insertions, 0 deletions
diff --git a/qt/src/.cvsignore b/qt/src/.cvsignore
new file mode 100644
index 00000000..f6454f28
--- /dev/null
+++ b/qt/src/.cvsignore
@@ -0,0 +1,11 @@
+.deps
+.libs
+Makefile
+Makefile.in
+*.lo
+*.la
+*.bb
+*.bbg
+*.da
+*.gcov
+*.moc
diff --git a/qt/src/Makefile.am b/qt/src/Makefile.am
new file mode 100644
index 00000000..41e3c5eb
--- /dev/null
+++ b/qt/src/Makefile.am
@@ -0,0 +1,70 @@
+INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_QT_CFLAGS) -DDBUS_COMPILATION
+
+lib_LTLIBRARIES=libdbus-qt4-1.la
+
+dbusincludedir=$(includedir)/dbus-1.0/dbus
+dbusinclude_HEADERS= \
+ qdbusbus.h \
+ qdbusmacros.h \
+ qdbuserror.h \
+ qdbusmessage.h \
+ qdbusserver.h \
+ qdbusconnection.h \
+ qdbusabstractinterface.h \
+ qdbusinterface.h \
+ qdbusutil.h \
+ qdbusabstractadaptor.h \
+ qdbusreply.h \
+ qdbustypehelper_p.h
+
+noinst_HEADERS= \
+ qdbusabstractadaptor_p.h \
+ qdbusabstractinterface_p.h \
+ qdbusconnection_p.h \
+ qdbusinterface_p.h \
+ qdbusintrospection_p.h \
+ qdbusmarshall_p.h \
+ qdbusmessage_p.h \
+ qdbusmetaobject_p.h \
+ qdbustype_p.h \
+ qdbusxmlparser_p.h
+
+MOCS = qdbusabstractadaptor.moc qdbusserver.moc qdbusconnection_p.moc qdbusconnection_p.moc qdbusabstractadaptor_p.moc qdbusbus.moc qdbusabstractinterface.moc
+CLEANFILES = $(MOCS)
+BUILT_SOURCES = $(MOCS)
+
+libdbus_qt4_1_la_SOURCES = \
+ qdbusbus.cpp \
+ qdbusconnection.cpp \
+ qdbuserror.cpp \
+ qdbusintegrator.cpp \
+ qdbusmarshall.cpp \
+ qdbusmessage.cpp \
+ qdbusserver.cpp \
+ qdbustype.cpp \
+ qdbusabstractinterface.cpp \
+ qdbusinterface.cpp \
+ qdbusxmlparser.cpp \
+ qdbusutil.cpp \
+ qdbusintrospection.cpp \
+ qdbusabstractadaptor.cpp \
+ qdbusthread.cpp \
+ qdbusinternalfilters.cpp \
+ qdbusmetaobject.cpp \
+ qdbusmisc.cpp \
+ qdbusxmlgenerator.cpp
+
+qdbusabstractadaptor.lo: qdbusabstractadaptor.moc qdbusabstractadaptor_p.moc
+qdbusabstractinterface.lo: qdbusabstractinterface.moc
+qdbusbus.lo: qdbusbus.moc
+qdbusserver.lo: qdbusserver.moc
+qdbusintegrator.lo: qdbusconnection_p.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
+libdbus_qt4_1_la_CPPFLAGS= -DQDBUS_MAKEDLL
+
+EXTRA_DIST = qt-dbus.qdocconf
+
+%.moc: %.h
+ $(QT_MOC) $< > $@
diff --git a/qt/src/qdbus.h b/qt/src/qdbus.h
new file mode 100644
index 00000000..60c35825
--- /dev/null
+++ b/qt/src/qdbus.h
@@ -0,0 +1,52 @@
+/* qdbus.h precompiled header
+ *
+ * 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 QDBUS_H
+#define QDBUS_H
+
+#include <QtCore/qglobal.h>
+
+#if !defined(DBUS_COMPILATION)
+# include <dbus/qdbusabstractadaptor.h>
+# include <dbus/qdbusabstractinterface.h>
+# include <dbus/qdbusbus.h>
+# include <dbus/qdbusconnection.h>
+# include <dbus/qdbuserror.h>
+# include <dbus/qdbusinterface.h>
+# include <dbus/qdbusmessage.h>
+# include <dbus/qdbusreply.h>
+# include <dbus/qdbusserver.h>
+# include <dbus/qdbusutil.h>
+#else
+# include "qdbusabstractadaptor.h"
+# include "qdbusabstractinterface.h"
+# include "qdbusbus.h"
+# include "qdbusconnection.h"
+# include "qdbuserror.h"
+# include "qdbusinterface.h"
+# include "qdbusmessage.h"
+# include "qdbusreply.h"
+# include "qdbusserver.h"
+# include "qdbusutil.h"
+#endif
+
+#endif
diff --git a/qt/src/qdbusabstractadaptor.cpp b/qt/src/qdbusabstractadaptor.cpp
new file mode 100644
index 00000000..b7c41888
--- /dev/null
+++ b/qt/src/qdbusabstractadaptor.cpp
@@ -0,0 +1,336 @@
+/* -*- 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>
+
+#include "qdbusconnection.h"
+
+#include "qdbusconnection_p.h" // for qDBusParametersForMethod
+#include "qdbusabstractadaptor_p.h"
+
+struct QDBusAdaptorInit
+{
+ QSignalSpyCallbackSet callbacks;
+ QDBusAdaptorInit()
+ {
+ extern void qt_register_signal_spy_callbacks(const QSignalSpyCallbackSet &callback_set);
+ callbacks.signal_begin_callback = QDBusAdaptorConnector::signalBeginCallback;
+ callbacks.signal_end_callback = QDBusAdaptorConnector::signalEndCallback;
+ callbacks.slot_begin_callback = 0;
+ callbacks.slot_end_callback = 0;
+ qt_register_signal_spy_callbacks(callbacks);
+
+ //QDBusAdaptorConnector::id = QObject::registerUserData();
+ }
+};
+
+Q_GLOBAL_STATIC(QDBusAdaptorInit, qAdaptorInit)
+
+QDBusAdaptorConnector *qDBusFindAdaptorConnector(QObject *obj)
+{
+ (void)qAdaptorInit();
+
+ if (!obj)
+ return 0;
+ QDBusAdaptorConnector *connector = qFindChild<QDBusAdaptorConnector *>(obj);
+ if (connector)
+ connector->polish();
+ return connector;
+}
+
+QDBusAdaptorConnector *qDBusFindAdaptorConnector(QDBusAbstractAdaptor *adaptor)
+{
+ return qDBusFindAdaptorConnector(adaptor->parent());
+}
+
+QDBusAdaptorConnector *qDBusCreateAdaptorConnector(QObject *obj)
+{
+ (void)qAdaptorInit();
+
+ QDBusAdaptorConnector *connector = qDBusFindAdaptorConnector(obj);
+ if (connector)
+ return connector;
+ return new QDBusAdaptorConnector(obj);
+}
+
+QString QDBusAbstractAdaptorPrivate::retrieveIntrospectionXml(QDBusAbstractAdaptor *adaptor)
+{
+ return adaptor->d->xml;
+}
+
+void QDBusAbstractAdaptorPrivate::saveIntrospectionXml(QDBusAbstractAdaptor *adaptor,
+ const QString &xml)
+{
+ adaptor->d->xml = xml;
+}
+
+/*!
+ \page usingannotations.html
+ \title Using annotations in adaptors
+
+ It is currently not possible to specify arbitrary annotations in adaptors.
+*/
+
+/*!
+ \class QDBusAbstractAdaptor
+ \brief Abstract adaptor for D-Bus adaptor classes.
+
+ The QDBusAbstractAdaptor class is the starting point for all objects intending to provide
+ interfaces to the external world using D-Bus. This is accomplished by attaching a one or more
+ classes derived from QDBusAbstractAdaptor to a normal QObject and then registering that QObject
+ with QDBusConnection::registerObject. QDBusAbstractAdaptor objects are intended to be
+ light-weight wrappers, mostly just relaying calls into the real object (see object()) and the
+ signals from it.
+
+ Each QDBusAbstractAdaptor-derived class should define the D-Bus interface it is implementing
+ using the Q_CLASSINFO macro in the class definition.
+
+ QDBusAbstractAdaptor uses the standard QObject mechanism of signals, slots and properties to
+ determine what signals, methods and properties to export to the bus. Any signal emitted by
+ QDBusAbstractAdaptor-derived classes will be automatically be relayed through any D-Bus
+ connections the object is registered on.
+
+ Classes derived from QDBusAbstractAdaptor must be created on the heap using the \a new operator
+ and must not be deleted by the user (they will be deleted automatically when the object they are
+ connected to is also deleted).
+
+ \sa {usingadaptors.html}{Using adaptors}, QDBusConnection
+*/
+
+/*!
+ Constructs a QDBusAbstractAdaptor with \a parent as the object we refer to.
+*/
+QDBusAbstractAdaptor::QDBusAbstractAdaptor(QObject* parent)
+ : QObject(parent), d(new QDBusAbstractAdaptorPrivate)
+{
+ QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(parent);
+
+ connector->waitingForPolish = true;
+ QTimer::singleShot(0, connector, SLOT(polish()));
+}
+
+/*!
+ Destroys the adaptor.
+
+ \warning Adaptors are destroyed automatically when the real object they refer to is
+ destroyed. Do not delete the adaptors yourself.
+*/
+QDBusAbstractAdaptor::~QDBusAbstractAdaptor()
+{
+ delete d;
+}
+
+/*!
+ Returns the QObject that we're the adaptor for. This is the same object that was passed as an
+ argument to the QDBusAbstractAdaptor constructor.
+*/
+QObject* QDBusAbstractAdaptor::object() const
+{
+ return parent();
+}
+
+/*!
+ Toggles automatic signal relaying from the real object (see object()).
+
+ Automatic signal relaying consists of signal-to-signal connection of the signals on the parent
+ that have the exact same method signatue in both classes.
+
+ If \a enable is set to true, connect the signals; if set to false, disconnect all signals.
+*/
+void QDBusAbstractAdaptor::setAutoRelaySignals(bool enable)
+{
+ const QMetaObject *us = metaObject();
+ const QMetaObject *them = parent()->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 = QMetaObject::normalizedSignature(mm.signature());
+ if (them->indexOfSignal(sig) == -1)
+ continue;
+ sig.prepend(QSIGNAL_CODE + '0');
+ parent()->disconnect(sig, this, sig);
+ if (enable)
+ connect(parent(), sig, sig);
+ }
+}
+
+QDBusAdaptorConnector::QDBusAdaptorConnector(QObject *parent)
+ : QObject(parent), waitingForPolish(false), lastSignalIdx(0), argv(0)
+{
+}
+
+QDBusAdaptorConnector::~QDBusAdaptorConnector()
+{
+}
+
+void QDBusAdaptorConnector::addAdaptor(QDBusAbstractAdaptor *adaptor)
+{
+ // find the interface name
+ const QMetaObject *mo = adaptor->metaObject();
+ while (mo != &QDBusAbstractAdaptor::staticMetaObject) {
+ int ciend = mo->classInfoCount();
+ for (int i = mo->classInfoOffset(); i < ciend; ++i) {
+ QMetaClassInfo mci = mo->classInfo(i);
+ if (strcmp(mci.name(), QCLASSINFO_DBUS_INTERFACE) == 0 && *mci.value()) {
+ // find out if this interface exists first
+ QString interface = QString::fromUtf8(mci.value());
+ AdaptorMap::Iterator it = qLowerBound(adaptors.begin(), adaptors.end(), interface);
+ if (it != adaptors.end() && it->interface == interface) {
+ // exists. Replace it (though it's probably the same)
+ it->adaptor = adaptor;
+ it->metaObject = mo;
+ } else {
+ // create a new one
+ AdaptorData entry;
+ entry.interface = interface;
+ entry.adaptor = adaptor;
+ entry.metaObject = mo;
+ adaptors << entry;
+ }
+ }
+ }
+
+ mo = mo->superClass();
+ }
+
+ // connect the adaptor's signals to our relaySlot slot
+ mo = adaptor->metaObject();
+ for (int i = QDBusAbstractAdaptor::staticMetaObject.methodCount();
+ i < mo->methodCount(); ++i) {
+ QMetaMethod mm = mo->method(i);
+
+ if (mm.methodType() != QMetaMethod::Signal)
+ continue;
+
+ QByteArray sig = mm.signature();
+ sig.prepend(QSIGNAL_CODE + '0');
+ disconnect(adaptor, sig, this, SLOT(relaySlot()));
+ connect(adaptor, sig, this, SLOT(relaySlot()));
+ }
+}
+
+void QDBusAdaptorConnector::polish()
+{
+ if (!waitingForPolish)
+ return; // avoid working multiple times if multiple adaptors were added
+
+ waitingForPolish = false;
+ const QObjectList &objs = parent()->children();
+ foreach (QObject *obj, objs) {
+ QDBusAbstractAdaptor *adaptor = qobject_cast<QDBusAbstractAdaptor *>(obj);
+ if (adaptor)
+ addAdaptor(adaptor);
+ }
+
+ // sort the adaptor list
+ qSort(adaptors);
+}
+
+void QDBusAdaptorConnector::relaySlot()
+{
+ relay(sender());
+}
+
+void QDBusAdaptorConnector::relay(QObject *sender)
+{
+ // we're being called because there is a signal being emitted that we must relay
+ Q_ASSERT(lastSignalIdx);
+ Q_ASSERT(argv);
+ Q_ASSERT(senderMetaObject);
+
+ if (senderMetaObject != sender->metaObject()) {
+ qWarning("Inconsistency detected: QDBusAdaptorConnector::relay got called with unexpected sender object!");
+ } else {
+ QMetaMethod mm = senderMetaObject->method(lastSignalIdx);
+ QObject *object = static_cast<QDBusAbstractAdaptor *>(sender)->parent();
+
+ // break down the parameter list
+ QList<int> types;
+ int inputCount = qDBusParametersForMethod(mm, types);
+ if (inputCount == -1)
+ // invalid signal signature
+ // qDBusParametersForMethod has already complained
+ return;
+ if (inputCount + 1 != types.count() ||
+ types.at(inputCount) == QDBusConnectionPrivate::messageMetaType) {
+ // invalid signal signature
+ // qDBusParametersForMethod has not yet complained about this one
+ qWarning("Cannot relay signal %s::%s", senderMetaObject->className(), mm.signature());
+ return;
+ }
+
+ QByteArray signature = QMetaObject::normalizedSignature(mm.signature());
+ signature.truncate(signature.indexOf('(')); // remove parameter decoration
+
+ QVariantList args;
+ for (int i = 1; i < types.count(); ++i)
+ args << QVariant(types.at(i), argv[i]);
+
+ // find all the interfaces this signal belongs to
+ for (const QMetaObject *mo = senderMetaObject; mo != &QDBusAbstractAdaptor::staticMetaObject;
+ mo = mo->superClass()) {
+ if (lastSignalIdx < mo->methodOffset())
+ break;
+
+ for (int i = mo->classInfoOffset(); i < mo->classInfoCount(); ++i) {
+ QMetaClassInfo mci = mo->classInfo(i);
+ if (qstrcmp(mci.name(), QCLASSINFO_DBUS_INTERFACE) == 0 && *mci.value())
+ // now emit the signal with all the information
+ emit relaySignal(object, mci.value(), signature.constData(), args);
+ }
+ }
+ }
+}
+
+void QDBusAdaptorConnector::signalBeginCallback(QObject *caller, int method_index, void **argv)
+{
+ QDBusAbstractAdaptor *adaptor = qobject_cast<QDBusAbstractAdaptor *>(caller);
+ if (adaptor) {
+ QDBusAdaptorConnector *data = qDBusFindAdaptorConnector(adaptor);
+ data->lastSignalIdx = method_index;
+ data->argv = argv;
+ data->senderMetaObject = caller->metaObject();
+ data->polish(); // make sure it's polished
+ }
+}
+
+void QDBusAdaptorConnector::signalEndCallback(QObject *caller, int)
+{
+ QDBusAbstractAdaptor *adaptor = qobject_cast<QDBusAbstractAdaptor *>(caller);
+ if (adaptor) {
+ QDBusAdaptorConnector *data = qDBusFindAdaptorConnector(adaptor);
+ data->lastSignalIdx = 0;
+ data->argv = 0;
+ data->senderMetaObject = 0;
+ }
+}
+
+#include "qdbusabstractadaptor.moc"
+#include "qdbusabstractadaptor_p.moc"
diff --git a/qt/src/qdbusabstractadaptor.h b/qt/src/qdbusabstractadaptor.h
new file mode 100644
index 00000000..16fbf5d9
--- /dev/null
+++ b/qt/src/qdbusabstractadaptor.h
@@ -0,0 +1,50 @@
+/* -*- 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 QDBusAbstractAdaptorPrivate;
+class QDBUS_EXPORT QDBusAbstractAdaptor: public QObject
+{
+ Q_OBJECT
+protected:
+ QDBusAbstractAdaptor(QObject *parent);
+
+public:
+ ~QDBusAbstractAdaptor();
+
+ Q_DECL_DEPRECATED QObject *object() const;
+
+protected:
+ void setAutoRelaySignals(bool enable);
+
+private:
+ friend class QDBusAbstractAdaptorPrivate;
+ QDBusAbstractAdaptorPrivate *d;
+};
+
+#endif
diff --git a/qt/src/qdbusabstractadaptor_p.h b/qt/src/qdbusabstractadaptor_p.h
new file mode 100644
index 00000000..71bfb582
--- /dev/null
+++ b/qt/src/qdbusabstractadaptor_p.h
@@ -0,0 +1,127 @@
+/* -*- mode: C++; set-fill-width: 100 -*-
+ *
+ * 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 QDBUSABSTRACTADAPTORPRIVATE_H
+#define QDBUSABSTRACTADAPTORPRIVATE_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qreadwritelock.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qvector.h>
+
+#define QCLASSINFO_DBUS_INTERFACE "D-Bus Interface"
+#define QCLASSINFO_DBUS_INTROSPECTION "D-Bus Introspection"
+
+class QDBusAbstractAdaptor;
+class QDBusAdaptorConnector;
+class QDBusAdaptorManager;
+class QDBusConnectionPrivate;
+
+#if QT_VERSION < 0x040200
+/* mirrored in qobject_p.h, DON'T CHANGE without prior warning */
+struct QSignalSpyCallbackSet
+{
+ typedef void (*BeginCallback)(QObject *caller, int method_index, void **argv);
+ typedef void (*EndCallback)(QObject *caller, int method_index);
+ BeginCallback signal_begin_callback,
+ slot_begin_callback;
+ EndCallback signal_end_callback,
+ slot_end_callback;
+};
+#else
+# error Qt 4.2.0 is supposed to have a better solution!
+ CHOKE!
+#endif // Qt 4.2.0
+
+class QDBusAbstractAdaptorPrivate
+{
+public:
+ QString xml;
+
+ static QString retrieveIntrospectionXml(QDBusAbstractAdaptor *adaptor);
+ static void saveIntrospectionXml(QDBusAbstractAdaptor *adaptor, const QString &xml);
+};
+
+class QDBusAdaptorConnector: public QObject
+{
+ Q_OBJECT
+public: // typedefs
+ struct AdaptorData
+ {
+ QString interface;
+ QDBusAbstractAdaptor *adaptor;
+ const QMetaObject *metaObject;
+
+ inline bool operator<(const AdaptorData &other) const
+ { return interface < other.interface; }
+ inline bool operator<(const QString &other) const
+ { return interface < other; }
+ };
+ typedef QVector<AdaptorData> AdaptorMap;
+
+public: // methods
+ explicit QDBusAdaptorConnector(QObject *parent);
+ ~QDBusAdaptorConnector();
+
+ void addAdaptor(QDBusAbstractAdaptor *adaptor);
+ void relay(QObject *sender);
+
+public slots:
+ void relaySlot();
+ void polish();
+
+signals:
+ void relaySignal(QObject *obj, const char *interface, const char *name, const QVariantList &args);
+
+public: // member variables
+ AdaptorMap adaptors;
+ bool waitingForPolish : 1;
+
+ int lastSignalIdx;
+ void **argv;
+ const QMetaObject *senderMetaObject;
+
+public: // static members
+ static void signalBeginCallback(QObject *caller, int method_index, void **argv);
+ static void signalEndCallback(QObject *caller, int method_index);
+ //static int id;
+};
+
+extern QDBusAdaptorConnector *qDBusFindAdaptorConnector(QObject *object);
+extern QDBusAdaptorConnector *qDBusCreateAdaptorConnector(QObject *object);
+
+#endif // QDBUSABSTRACTADAPTORPRIVATE_H
diff --git a/qt/src/qdbusabstractinterface.cpp b/qt/src/qdbusabstractinterface.cpp
new file mode 100644
index 00000000..2a6bcf04
--- /dev/null
+++ b/qt/src/qdbusabstractinterface.cpp
@@ -0,0 +1,389 @@
+/* -*- 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 "qdbusabstractinterface.h"
+
+#include "qdbusabstractinterface_p.h"
+#include "qdbusmetaobject_p.h"
+#include "qdbusconnection_p.h"
+
+QVariant QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp) const
+{
+ // try to read this property
+ QDBusMessage msg = QDBusMessage::methodCall(service, path, DBUS_INTERFACE_PROPERTIES,
+ QLatin1String("Get"));
+ msg << interface << QString::fromUtf8(mp.name());
+ QDBusMessage reply = connp->sendWithReply(msg, QDBusConnection::NoUseEventLoop);
+
+ if (reply.type() == QDBusMessage::ReplyMessage && reply.count() == 1 &&
+ reply.signature() == QLatin1String("v")) {
+ QVariant value = QDBusTypeHelper<QVariant>::fromVariant(reply.at(0));
+
+ // make sure the type is right
+ if (qstrcmp(mp.typeName(), value.typeName()) == 0) {
+ if (mp.type() == QVariant::LastType)
+ // QVariant is special in this context
+ return QDBusTypeHelper<QVariant>::fromVariant(value);
+
+ return value;
+ }
+ }
+
+ // there was an error...
+ if (reply.type() == QDBusMessage::ErrorMessage)
+ lastError = reply;
+ else if (reply.signature() != QLatin1String("v")) {
+ QString errmsg = QLatin1String("Invalid signature `%1' in return from call to "
+ DBUS_INTERFACE_PROPERTIES);
+ lastError = QDBusError(QDBusError::InvalidSignature, errmsg.arg(reply.signature()));
+ } else {
+ QString errmsg = QLatin1String("Unexpected type `%1' when retrieving property "
+ "`%2 %3.%4'");
+ lastError = QDBusError(QDBusError::InvalidSignature,
+ errmsg.arg(QLatin1String(reply.at(0).typeName()),
+ QLatin1String(mp.typeName()),
+ interface, QString::fromUtf8(mp.name())));
+ }
+
+ return QVariant();
+}
+
+void QDBusAbstractInterfacePrivate::setProperty(const QMetaProperty &mp, const QVariant &value)
+{
+ // send the value
+ QDBusMessage msg = QDBusMessage::methodCall(service, path, DBUS_INTERFACE_PROPERTIES,
+ QLatin1String("Set"));
+ msg.setSignature(QLatin1String("ssv"));
+ msg << interface << QString::fromUtf8(mp.name()) << value;
+ QDBusMessage reply = connp->sendWithReply(msg, QDBusConnection::NoUseEventLoop);
+
+ if (reply.type() != QDBusMessage::ReplyMessage)
+ lastError = reply;
+}
+
+/*!
+ \class QDBusAbstractInterface
+ \brief Base class for all D-Bus interfaces in the QtDBus binding, allowing access to remote interfaces.
+
+ Generated-code classes also derive from QDBusAbstractInterface, all methods described here are also
+ valid for generated-code classes. In addition to those described here, generated-code classes
+ provide member functions for the remote methods, which allow for compile-time checking of the
+ correct parameters and return values, as well as property type-matching and signal
+ parameter-matching.
+
+ \sa {dbusidl2cpp.html}{The dbusidl2cpp compiler}, QDBusInterface
+*/
+
+/*!
+ \enum QDBusAbstractInterface::CallMode
+
+ Specifies how a call should be placed. The valid options are:
+ \value NoWaitForReply place the call but don't wait for the reply (the reply's contents
+ will be discarded)
+ \value NoUseEventLoop don't use an event loop to wait for a reply, but instead block on
+ network operations while waiting. This option means the
+ user-interface may not be updated for the duration of the call.
+ \value UseEventLoop use the Qt event loop to wait for a reply. This option means the
+ user-interface will update, but it also means other events may
+ happen, like signal delivery and other D-Bus method calls.
+
+ When using UseEventLoop, applications must be prepared for reentrancy in any function.
+*/
+
+/*!
+ \internal
+*/
+QDBusAbstractInterface::QDBusAbstractInterface(QDBusAbstractInterfacePrivate* d)
+#if QT_VERSION < 0x040200
+ : d_ptr(d)
+{
+ d_ptr->q_ptr = this;
+}
+#endif
+
+/*!
+ Releases this object's resources.
+*/
+QDBusAbstractInterface::~QDBusAbstractInterface()
+{
+ delete d_ptr;
+}
+
+/*!
+ Returns true if this is a valid reference to a remote object. It returns false if
+ there was an error during the creation of this interface (for instance, if the remote
+ application does not exist).
+
+ Note: when dealing with remote objects, it is not always possible to determine if it
+ exists when creating a QDBusInterface or QDBusInterfacePtr object.
+*/
+bool QDBusAbstractInterface::isValid() const
+{
+ return d_func()->isValid;
+}
+
+/*!
+ Returns the connection this interface is assocated with.
+*/
+QDBusConnection QDBusAbstractInterface::connection() const
+{
+ return d_func()->conn;
+}
+
+/*!
+ Returns the name of the service this interface is associated with.
+*/
+QString QDBusAbstractInterface::service() const
+{
+ return d_func()->service;
+}
+
+/*!
+ Returns the object path that this interface is associated with.
+*/
+QString QDBusAbstractInterface::path() const
+{
+ return d_func()->path;
+}
+
+/*!
+ Returns the name of this interface.
+*/
+QString QDBusAbstractInterface::interface() const
+{
+ return d_func()->interface;
+}
+
+/*!
+ Returns the error the last operation produced, or an invalid error if the last operation did not
+ produce an error.
+*/
+QDBusError QDBusAbstractInterface::lastError() const
+{
+ return d_func()->lastError;
+}
+
+/*!
+ \threadsafe
+ Places a call to the remote method specified by \a method on this interface, using \a args as
+ arguments. This function returns the message that was received as a reply, which can be a normal
+ QDBusMessage::ReplyMessage (indicating success) or QDBusMessage::ErrorMessage (if the call
+ failed). The \a mode parameter specifies how this call should be placed.
+
+ If the call succeeds, lastError() will be cleared; otherwise, it will contain the error this
+ call produced.
+
+ Normally, you should place calls using call().
+
+ \warning If you use \c UseEventLoop, your code must be prepared to deal with any reentrancy:
+ other method calls and signals may be delivered before this function returns, as well
+ as other Qt queued signals and events.
+*/
+QDBusMessage QDBusAbstractInterface::callWithArgs(const QString& method, const QList<QVariant>& args,
+ CallMode mode)
+{
+ Q_D(QDBusAbstractInterface);
+
+ QString m = method, sig;
+ // split out the signature from the method
+ int pos = method.indexOf(QLatin1Char('.'));
+ if (pos != -1) {
+ m.truncate(pos);
+ sig = method.mid(pos + 1);
+ }
+
+ if (mode == AutoDetect) {
+ // determine if this a sync or async call
+ mode = NoUseEventLoop;
+ const QMetaObject *mo = metaObject();
+ QByteArray match = method.toLatin1() + '(';
+
+ for (int i = staticMetaObject.methodCount(); i < mo->methodCount(); ++i) {
+ QMetaMethod mm = mo->method(i);
+ if (QByteArray(mm.signature()).startsWith(match)) {
+ // found a method with the same name as what we're looking for
+ // hopefully, nobody is overloading asynchronous and synchronous methods with
+ // the same name
+
+ QList<QByteArray> tags = QByteArray(mm.tag()).split(' ');
+ if (tags.contains("async") || tags.contains("Q_ASYNC"))
+ mode = NoWaitForReply;
+
+ break;
+ }
+ }
+ }
+
+ QDBusMessage msg = QDBusMessage::methodCall(service(), path(), interface(), m);
+ msg.setSignature(sig);
+ msg.QList<QVariant>::operator=(args);
+
+ QDBusMessage reply;
+ if (mode != NoWaitForReply)
+ reply = d->conn.sendWithReply(msg, mode == UseEventLoop ?
+ QDBusConnection::UseEventLoop : QDBusConnection::NoUseEventLoop);
+ 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;
+}
+
+/*!
+ \overload
+ Places a call to the remote method specified by \a method on this interface, using \a args as
+ arguments. This function will return immediately after queueing the call. The reply from the
+ remote function or any errors emitted by it will be delivered to the \a slot slot on object \a
+ receiver.
+
+ This function returns true if the queueing succeeded: it does not indicate that the call
+ succeeded. If it failed, the slot will be called with an error message. lastError() will not be
+ set under those circumstances.
+
+ \sa QDBusError, QDBusMessage
+*/
+bool QDBusAbstractInterface::callWithArgs(const QString &method, QObject *receiver, const char *slot,
+ const QList<QVariant> &args)
+{
+ Q_D(QDBusAbstractInterface);
+
+ QString m = method, sig;
+ // split out the signature from the method
+ int pos = method.indexOf(QLatin1Char('.'));
+ if (pos != -1) {
+ m.truncate(pos);
+ sig = method.mid(pos + 1);
+ }
+
+ QDBusMessage msg = QDBusMessage::methodCall(service(), path(), interface(), m);
+ msg.setSignature(sig);
+ msg.QList<QVariant>::operator=(args);
+
+ d->lastError = 0; // clear
+ return d->conn.sendWithReplyAsync(msg, receiver, slot);
+}
+
+/*!
+ \internal
+ Catch signal connections.
+*/
+void QDBusAbstractInterface::connectNotify(const char *signal)
+{
+ // someone connecting to one of our signals
+ Q_D(QDBusAbstractInterface);
+
+ d->connp->connectRelay(d->service, d->path, d->interface, this, signal);
+}
+
+/*!
+ \internal
+ Catch signal disconnections.
+*/
+void QDBusAbstractInterface::disconnectNotify(const char *signal)
+{
+ // someone disconnecting from one of our signals
+ Q_D(QDBusAbstractInterface);
+
+ d->connp->disconnectRelay(d->service, d->path, d->interface, this, signal);
+}
+
+/*!
+ \internal
+ Get the value of the property \a propname.
+*/
+QVariant QDBusAbstractInterface::internalPropGet(const char *propname) const
+{
+ // assume this property exists and is readable
+ // we're only called from generated code anyways
+
+ int idx = metaObject()->indexOfProperty(propname);
+ if (idx != -1)
+ return d_func()->property(metaObject()->property(idx));
+ qWarning("QDBusAbstractInterface::internalPropGet called with unknown property '%s'", propname);
+ return QVariant(); // error
+}
+
+/*!
+ \internal
+ Set the value of the property \a propname to \a value.
+*/
+void QDBusAbstractInterface::internalPropSet(const char *propname, const QVariant &value)
+{
+ Q_D(QDBusAbstractInterface);
+
+ // assume this property exists and is writeable
+ // we're only called from generated code anyways
+
+ int idx = metaObject()->indexOfProperty(propname);
+ if (idx != -1)
+ d->setProperty(metaObject()->property(idx), value);
+ else
+ qWarning("QDBusAbstractInterface::internalPropGet called with unknown property '%s'", propname);
+}
+
+/*!
+ \overload
+ \fn QDBusMessage QDBusAbstractInterface::call(const QString &method)
+
+ Calls the method \a method on this interface and passes the parameters to this function to the
+ method.
+
+ The parameters to \c call are passed on to the remote function via D-Bus as input
+ arguments. Output arguments are returned in the QDBusMessage reply. If the reply is an error
+ reply, lastError() will also be set to the contents of the error message.
+
+ This function is implemented by actually 9 different function overloads called \c call, so you
+ can pass up to 8 parameters to your function call, which can be of any type accepted by QtDBus
+ (see the \l {allowedparameters.html}{allowed parameters} page for information on what types are
+ accepted).
+
+ It can be used the following way:
+
+ \code
+ QString value = retrieveValue();
+ QDBusMessage reply;
+
+ QDBusReply<int> api = interface->call(QLatin1String("GetAPIVersion"));
+ if (api >= 14)
+ reply = interface->call(QLatin1String("ProcessWorkUnicode"), value);
+ else
+ reply = interface->call(QLatin1String("ProcessWork"), QLatin1String("UTF-8"), value.toUtf8());
+ \endcode
+
+ This example illustrates function calling with 0, 1 and 2 parameters and illustrates different
+ parameter types passed in each (the first call to \c "ProcessWorkUnicode" will contain one
+ Unicode string, the second call to \c "ProcessWork" will contain one string and one byte array).
+
+ \warning This function reenters the Qt event loop in order to wait for the reply, excluding user
+ input. During the wait, it may deliver signals and other method calls to your
+ application. Therefore, it must be prepared to handle a reentrancy whenever a call is
+ placed with call().
+*/
+
+#include "qdbusabstractinterface.moc"
diff --git a/qt/src/qdbusabstractinterface.h b/qt/src/qdbusabstractinterface.h
new file mode 100644
index 00000000..aa6d00d7
--- /dev/null
+++ b/qt/src/qdbusabstractinterface.h
@@ -0,0 +1,257 @@
+/* -*- 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 QDBUSABSTRACTINTERFACE_H
+#define QDBUSABSTRACTINTERFACE_H
+
+#include <QtCore/qstring.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qobject.h>
+
+#include "qdbusmessage.h"
+#include "qdbustypehelper_p.h"
+
+class QDBusConnection;
+class QDBusError;
+
+class QDBusAbstractInterfacePrivate;
+class QDBUS_EXPORT QDBusAbstractInterface: public QObject
+{
+ Q_OBJECT
+
+public:
+ enum CallMode {
+ NoWaitForReply,
+ UseEventLoop,
+ NoUseEventLoop,
+ AutoDetect
+ };
+
+public:
+ virtual ~QDBusAbstractInterface();
+ bool isValid() const;
+
+ QDBusConnection connection() const;
+
+ QString service() const;
+ QString path() const;
+ QString interface() const;
+
+ QDBusError lastError() const;
+
+ QDBusMessage callWithArgs(const QString &method, const QList<QVariant> &args = QList<QVariant>(),
+ CallMode mode = AutoDetect);
+ bool callWithArgs(const QString &method, QObject *receiver, const char *slot,
+ const QList<QVariant> &args = QList<QVariant>());
+
+ inline QDBusMessage call(const QString &m)
+ {
+ return callWithArgs(m);
+ }
+
+ inline QDBusMessage call(CallMode mode, const QString &m)
+ {
+ return callWithArgs(m, QList<QVariant>(), mode);
+ }
+
+#ifndef Q_QDOC
+private:
+ template<typename T> inline QVariant qvfv(const T &t)
+ { return QDBusTypeHelper<T>::toVariant(t); }
+
+public:
+ template<typename T1>
+ inline QDBusMessage call(const QString &m, const T1 &t1)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1);
+ return callWithArgs(m, args);
+ }
+
+ template<typename T1, typename T2>
+ inline QDBusMessage call(const QString &m, const T1 &t1, const T2 &t2)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2);
+ return callWithArgs(m, args);
+ }
+
+ template<typename T1, typename T2, typename T3>
+ inline QDBusMessage call(const QString &m, const T1 &t1, const T2 &t2, const T3 &t3)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3);
+ return callWithArgs(m, args);
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4>
+ inline QDBusMessage call(const QString &m, const T1 &t1, const T2 &t2, const T3 &t3,
+ const T4 &t4)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3)
+ << qvfv(t4);
+ return callWithArgs(m, args);
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5>
+ inline QDBusMessage call(const QString &m, const T1 &t1, const T2 &t2, const T3 &t3,
+ const T4 &t4, const T5 &t5)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3)
+ << qvfv(t4) << qvfv(t5);
+ return callWithArgs(m, args);
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+ inline QDBusMessage call(const QString &m, const T1 &t1, const T2 &t2, const T3 &t3,
+ const T4 &t4, const T5 &t5, const T6 &t6)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3)
+ << qvfv(t4) << qvfv(t5) << qvfv(t6);
+ return callWithArgs(m, args);
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
+ inline QDBusMessage call(const QString &m, const T1 &t1, const T2 &t2, const T3 &t3,
+ const T4 &t4, const T5 &t5, const T6 &t6, const T7 &t7)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3)
+ << qvfv(t4) << qvfv(t5) << qvfv(t6)
+ << qvfv(t7);
+ return callWithArgs(m, args);
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+ inline QDBusMessage call(const QString &m, const T1 &t1, const T2 &t2, const T3 &t3,
+ const T4 &t4, const T5 &t5, const T6 &t6, const T7 &t7, const T8 &t8)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3)
+ << qvfv(t4) << qvfv(t5) << qvfv(t6)
+ << qvfv(t7) << qvfv(t8);
+ return callWithArgs(m, args);
+ }
+
+ template<typename T1>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1);
+ return callWithArgs(m, args, mode);
+ }
+
+ template<typename T1, typename T2>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1, const T2 &t2)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2);
+ return callWithArgs(m, args, mode);
+ }
+
+ template<typename T1, typename T2, typename T3>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1, const T2 &t2,
+ const T3 &t3)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3);
+ return callWithArgs(m, args, mode);
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1, const T2 &t2,
+ const T3 &t3, const T4 &t4)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3)
+ << qvfv(t4);
+ return callWithArgs(m, args, mode);
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1, const T2 &t2,
+ const T3 &t3, const T4 &t4, const T5 &t5)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3)
+ << qvfv(t4) << qvfv(t5);
+ return callWithArgs(m, args, mode);
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1, const T2 &t2,
+ const T3 &t3, const T4 &t4, const T5 &t5, const T6 &t6)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3)
+ << qvfv(t4) << qvfv(t5) << qvfv(t6);
+ return callWithArgs(m, args, mode);
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1, const T2 &t2,
+ const T3 &t3, const T4 &t4, const T5 &t5, const T6 &t6, const T7 &t7)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3)
+ << qvfv(t4) << qvfv(t5) << qvfv(t6)
+ << qvfv(t7);
+ return callWithArgs(m, args, mode);
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+ inline QDBusMessage call(CallMode mode, const QString &m, const T1 &t1, const T2 &t2,
+ const T3 &t3, const T4 &t4, const T5 &t5, const T6 &t6, const T7 &t7,
+ const T8 &t8)
+ {
+ QList<QVariant> args;
+ args << qvfv(t1) << qvfv(t2) << qvfv(t3)
+ << qvfv(t4) << qvfv(t5) << qvfv(t6)
+ << qvfv(t7) << qvfv(t8);
+ return callWithArgs(m, args, mode);
+ }
+#endif
+
+protected:
+ QDBusAbstractInterface(QDBusAbstractInterfacePrivate *);
+ void connectNotify(const char *signal);
+ void disconnectNotify(const char *signal);
+ QVariant internalPropGet(const char *propname) const;
+ void internalPropSet(const char *propname, const QVariant &value);
+
+private:
+ friend class QDBusInterface;
+ QDBusAbstractInterfacePrivate *d_ptr; // remove for Qt 4.2.0
+
+ Q_DECLARE_PRIVATE(QDBusAbstractInterface)
+ Q_DISABLE_COPY(QDBusAbstractInterface)
+};
+
+#endif
diff --git a/qt/src/qdbusabstractinterface_p.h b/qt/src/qdbusabstractinterface_p.h
new file mode 100644
index 00000000..43807071
--- /dev/null
+++ b/qt/src/qdbusabstractinterface_p.h
@@ -0,0 +1,72 @@
+/*
+ *
+ * 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 QDBUSABSTRACTINTERFACEPRIVATE_H
+#define QDBUSABSTRACTINTERFACEPRIVATE_H
+
+#include "qdbusabstractinterface.h"
+#include "qdbusconnection.h"
+#include "qdbuserror.h"
+
+#define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply"
+
+class QDBusAbstractInterfacePrivate//: public QObjectPrivate
+{
+public:
+ Q_DECLARE_PUBLIC(QDBusAbstractInterface)
+
+ QDBusAbstractInterface *q_ptr; // remove in Qt 4.2
+ QDBusConnection conn;
+ QDBusConnectionPrivate *connp;
+ QString service;
+ QString path;
+ QString interface;
+ mutable QDBusError lastError;
+ bool isValid;
+
+ inline QDBusAbstractInterfacePrivate(const QDBusConnection& con, QDBusConnectionPrivate *conp,
+ const QString &serv, const QString &p, const QString &iface)
+ : conn(con), connp(conp), service(serv), path(p), interface(iface), isValid(true)
+ { }
+ virtual ~QDBusAbstractInterfacePrivate() { }
+
+ // these functions do not check if the property is valid
+ QVariant property(const QMetaProperty &mp) const;
+ void setProperty(const QMetaProperty &mp, const QVariant &value);
+};
+
+
+#endif
diff --git a/qt/src/qdbusbus.cpp b/qt/src/qdbusbus.cpp
new file mode 100644
index 00000000..02c231eb
--- /dev/null
+++ b/qt/src/qdbusbus.cpp
@@ -0,0 +1,302 @@
+/* -*- C++ -*-
+ *
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira@trolltech.com>
+ *
+ * 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.
+ *
+ */
+
+/*
+ * This file was generated by dbusidl2cpp version 0.3
+ * when processing input file -
+ *
+ * dbusidl2cpp is Copyright (C) 2006 Trolltech AS. All rights reserved.
+ *
+ * This file has been hand-edited! Be careful when re-generating it!
+ *
+ */
+
+#include "qdbusbus.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+
+/*
+ * Implementation of interface class QDBusBusService
+ */
+
+/*!
+ \class QDBusBusService
+ \brief Provides access to the D-Bus bus daemon service.
+
+*/
+
+/*!
+ \enum QDBusBusService::RequestNameOption
+
+ Flags for requesting a name on the bus.
+
+ \value AllowReplacingName Allow another application requesting the same name to take the name
+ from this application.
+ \value ReplaceExistingName If another application already has the name and allows replacing,
+ take the name and assign it to us.
+ \value DoNotQueueName Without this flag, if an application requests a name that is already
+ owned and does not allow replacing, it will be queued until the
+ name is given up. If this flag is given, no queueing will be
+ performed and the requestName() call will simply fail.
+*/
+
+/*!
+ \enum QDBusBusService::RequestNameReply
+
+ The possible return values from requestName():
+
+ \value PrimaryOwnerReply The caller is now the primary owner of the name.
+ \value InQueueReply The caller is in queue for the name, but does not own it.
+ \value NameExistsReply The name exists and could not be replaced, or the caller did
+ specify DoNotQueueName.
+ \value AlreadyOwnerReply The caller tried to request a name that it already owns.
+*/
+
+/*!
+ \enum QDBusBusService::ReleaseNameReply
+
+ The possible return values from releaseName():
+
+ \value NameReleasedReply The caller released his claim on the name.
+ \value NameNonExistentReply The caller tried to release a name that did not exist.
+ \value NotOwnerReply The caller tried to release a name that it did not own or was not in
+ queue for.
+*/
+
+/*!
+ \enum QDBusBusService::StartServiceReply
+
+ The possible return values from startServiceByName():
+
+ \value Success The service was successfully started.
+ \value AlreadyRunning The service was already running.
+*/
+
+/*!
+ \internal
+*/
+const char *QDBusBusService::staticInterfaceName()
+{ return "org.freedesktop.DBus"; }
+
+
+/*!
+ \internal
+*/
+QDBusBusService::QDBusBusService(QDBusAbstractInterfacePrivate *p)
+ : QDBusAbstractInterface(p)
+{
+ connect(this, SIGNAL(NameAcquired(QString)), this, SIGNAL(nameAcquired(QString)));
+ connect(this, SIGNAL(NameLost(QString)), this, SIGNAL(nameLost(QString)));
+ connect(this, SIGNAL(NameOwnerChanged(QString,QString,QString)),
+ this, SIGNAL(nameOwnerChanged(QString,QString,QString)));
+}
+
+/*!
+ \internal
+*/
+QDBusBusService::~QDBusBusService()
+{
+}
+
+/*!
+ \fn QDBusBusService::hello()
+ \internal
+ Sends a "Hello" request to the bus service. You do not want to call this.
+*/
+QDBusReply<QString> QDBusBusService::Hello()
+{
+ return call(QLatin1String("Hello"));
+}
+
+/*!
+ \fn QDBusBusService::nameOwner(const QString &name)
+ Returns the unique connection name of the primary owner of the name \a name. If the requested
+ name doesn't have an owner, returns a org.freedesktop.DBus.Error.NameHasNoOwner error.
+*/
+QDBusReply<QString> QDBusBusService::GetNameOwner(const QString &name)
+{
+ return call(QLatin1String("GetNameOwner.s"), name);
+}
+
+/*!
+ \fn QDBusBusService::listNames()
+ Lists all names currently existing on the bus.
+*/
+QDBusReply<QStringList> QDBusBusService::ListNames()
+{
+ return call(QLatin1String("ListNames"));
+}
+
+/*!
+ \fn QDBusBusService::listQueuedOwners(const QString &service)
+ Returns a list of all unique connection names in queue for the service name \a service.
+*/
+QDBusReply<QStringList> QDBusBusService::ListQueuedOwners(const QString &service)
+{
+ return call(QLatin1String("ListQueuedOwners.s"), service);
+}
+
+/*!
+ \fn QDBusBusService::nameHasOwner(const QString &service)
+ Returns true if the service name \a service has an owner.
+*/
+QDBusReply<bool> QDBusBusService::NameHasOwner(const QString &service)
+{
+ return call(QLatin1String("NameHasOwner.s"), service);
+}
+
+/*!
+ \fn QDBusBusService::addMatch(const QString &rule)
+ Adds the rule \a rule for requesting messages from the bus.
+
+ \sa removeMatch()
+*/
+QDBusReply<void> QDBusBusService::AddMatch(const QString &rule)
+{
+ return call(QLatin1String("AddMatch.s"), rule);
+}
+
+/*!
+ \fn QDBusBusService::removeMatch(const QString &rule)
+ Removes the rule \a rule, that had previously been added with addMatch().
+*/
+QDBusReply<void> QDBusBusService::RemoveMatch(const QString &rule)
+{
+ return call(QLatin1String("RemoveMatch.s"), rule);
+}
+
+/*!
+ \fn QDBusBusService::connectionSELinuxSecurityContext(const QString &service)
+ Returns the SELinux security context of the process currently holding the bus service \a
+ service.
+*/
+QDBusReply<QByteArray> QDBusBusService::GetConnectionSELinuxSecurityContext(const QString &service)
+{
+ return call(QLatin1String("GetConnectionSELinuxSecurityContext.s"), service);
+}
+
+/*!
+ \fn QDBusBusService::connectionUnixProcessID(const QString &service)
+ Returns the Unix Process ID (PID) for the process currently holding the bus service \a service.
+*/
+QDBusReply<uint> QDBusBusService::GetConnectionUnixProcessID(const QString &service)
+{
+ return call(QLatin1String("GetConnectionUnixProcessID.s"), service);
+}
+
+/*!
+ \fn QDBusBusService::connectionUnixUser(const QString &service)
+ Returns the Unix User ID (UID) for the process currently holding the bus service \a service.
+*/
+QDBusReply<uint> QDBusBusService::GetConnectionUnixUser(const QString &service)
+{
+ return call(QLatin1String("GetConnectionUnixUser.s"), service);
+}
+
+/*!
+ \fn QDBusBusService::reloadConfig()
+ Asks the D-Bus server daemon to reload its configuration.
+*/
+QDBusReply<void> QDBusBusService::ReloadConfig()
+{
+ return call(QLatin1String("ReloadConfig"));
+}
+
+inline QDBUS_EXPORT int qDBusMetaTypeId(QDBusBusService::StartServiceReply *)
+{ return QVariant::Int; }
+
+/*!
+ \fn QDBusBusService::startServiceByName(const QString &name, uint flags)
+ Requests that the bus start the service given by the name \a name.
+
+ The \a flags parameter is currently not used.
+*/
+QDBusReply<QDBusBusService::StartServiceReply>
+QDBusBusService::StartServiceByName(const QString &name, uint flags)
+{
+ return call(QLatin1String("StartServiceByName.su"), name, flags);
+}
+
+inline QDBUS_EXPORT int qDBusMetaTypeId(QDBusBusService::RequestNameReply *)
+{ return QVariant::Int; }
+
+/*!
+ \fn QDBusBusService::requestName(const QString &service, RequestNameOptions flags)
+ Requests the bus service name \a service from the bus. The \a flags parameter specifies how the
+ bus server daemon should act when the same name is requested by two different applications.
+
+ \sa releaseName()
+*/
+QDBusReply<QDBusBusService::RequestNameReply>
+QDBusBusService::RequestName(const QString &service, RequestNameOptions flags)
+{
+ return call(QLatin1String("RequestName.su"), service, uint(int(flags)));
+}
+
+inline QDBUS_EXPORT int qDBusMetaTypeId(QDBusBusService::ReleaseNameReply *)
+{ return QVariant::Int; }
+
+/*!
+ \fn QDBusBusService::releaseName(const QString &service)
+ Releases the claim on the bus service name \a service, that had been previously requested with
+ requestName(). If this application had ownership of the name, it will be released for other
+ applications to claim. If it only had the name queued, it gives up its position in the queue.
+*/
+QDBusReply<QDBusBusService::ReleaseNameReply>
+QDBusBusService::ReleaseName(const QString &service)
+{
+ return call(QLatin1String("ReleaseName.s"), service);
+}
+
+// signals
+/*!
+ \fn QDBusBusService::nameAcquired(const QString &service)
+
+ This signal is emitted by the D-Bus bus server when the bus service name (unique connection name
+ or well-known service name) given by \a service is acquired by this application.
+
+ Name acquisition happens after the application requested a name using requestName().
+*/
+
+/*!
+ \fn QDBusBusService::nameLost(const QString &service)
+
+ This signal is emitted by the D-Bus bus server when the application loses ownership of the bus
+ service name given by \a service.
+*/
+
+/*!
+ \fn QDBusBusService::nameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
+
+ This signal is emitted by the D-Bus bus server whenever a name ownership change happens in the
+ bus, including apparition and disparition of names.
+
+ This signal means the application \a oldOwner lost ownership of bus name \a name to application
+ \a newOwner. If \a oldOwner is an empty string, it means the name \a name has just been created;
+ if \a newOwner is empty, the name \a name has no current owner.
+*/
+
+#include "qdbusbus.moc"
diff --git a/qt/src/qdbusbus.h b/qt/src/qdbusbus.h
new file mode 100644
index 00000000..22606852
--- /dev/null
+++ b/qt/src/qdbusbus.h
@@ -0,0 +1,158 @@
+/* -*- C++ -*-
+ *
+ * Copyright (C) 2006 Trolltech AS. All rights reserved.
+ * Author: Thiago Macieira <thiago.macieira@trolltech.com>
+ *
+ * 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.
+ *
+ */
+
+/*
+ * This file was generated by dbusidl2cpp version 0.3
+ * when processing input file -
+ *
+ * dbusidl2cpp is Copyright (C) 2006 Trolltech AS. All rights reserved.
+ *
+ * This file has been hand-edited! Be careful when re-generating it!
+ *
+ */
+
+#ifndef QDBUSBUS_H
+#define QDBUSBUS_H
+
+#include <QtCore/qstringlist.h>
+
+#include "qdbusabstractinterface.h"
+#include "qdbusreply.h"
+
+class QDBusConnection;
+class QString;
+class QByteArray;
+
+/*
+ * Proxy class for interface org.freedesktop.DBus
+ */
+class QDBUS_EXPORT QDBusBusService: public QDBusAbstractInterface
+{
+ Q_OBJECT
+ friend class QDBusConnection;
+ static inline const char *staticInterfaceName();
+
+ explicit QDBusBusService(QDBusAbstractInterfacePrivate *p);
+
+ ~QDBusBusService();
+
+public:
+ // taken out of http://dbus.freedesktop.org/doc/dbus-specification.html
+ // update if the standard updates
+ enum RequestNameOption {
+ AllowReplacingName = 0x1,
+ ReplaceExistingName = 0x2,
+ DoNotQueueName = 0x4
+ };
+ Q_DECLARE_FLAGS(RequestNameOptions, RequestNameOption)
+
+ enum RequestNameReply {
+ PrimaryOwnerReply = 1,
+ InQueueReply = 2,
+ NameExistsReply = 3,
+ AlreadyOwnerReply = 4
+ };
+
+ enum ReleaseNameReply {
+ NameReleasedReply = 1,
+ NameNonExistentReply = 2,
+ NotOwnerReply = 3
+ };
+
+ enum StartServiceReply {
+ Success = 1,
+ AlreadyRunning = 2
+ };
+
+#ifndef Q_QDOC
+ // D-Bus names
+public: // METHODS
+ QDBusReply<QString> Hello();
+ QDBusReply<void> ReloadConfig();
+
+ QDBusReply<QStringList> ListNames();
+
+ QDBusReply<bool> NameHasOwner(const QString &service);
+ QDBusReply<QString> GetNameOwner(const QString &name);
+ QDBusReply<ReleaseNameReply> ReleaseName(const QString &service);
+ QDBusReply<RequestNameReply> RequestName(const QString &service, RequestNameOptions flags);
+ QDBusReply<QStringList> ListQueuedOwners(const QString &service);
+
+ QDBusReply<void> AddMatch(const QString &rule);
+ QDBusReply<void> RemoveMatch(const QString &rule);
+
+ QDBusReply<QByteArray> GetConnectionSELinuxSecurityContext(const QString &service);
+ QDBusReply<uint> GetConnectionUnixProcessID(const QString &service);
+ QDBusReply<uint> GetConnectionUnixUser(const QString &service);
+
+ QDBusReply<StartServiceReply> StartServiceByName(const QString &name, uint flags);
+
+signals: // SIGNALS
+ void NameAcquired(const QString &service);
+ void NameLost(const QString &service);
+ void NameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
+#endif
+
+ // Qt-style naming
+public slots:
+ QDBusReply<QString> hello()
+ { return Hello(); }
+ QDBusReply<void> reloadConfig()
+ { return ReloadConfig(); }
+
+ QDBusReply<QStringList> listNames()
+ { return ListNames(); }
+
+ QDBusReply<bool> nameHasOwner(const QString &service)
+ { return NameHasOwner(service); }
+ QDBusReply<QString> nameOwner(const QString &name)
+ { return GetNameOwner(name); }
+ QDBusReply<ReleaseNameReply> releaseName(const QString &service)
+ { return ReleaseName(service); }
+ QDBusReply<RequestNameReply> requestName(const QString &service, RequestNameOptions flags)
+ { return RequestName(service, flags); }
+ QDBusReply<QStringList> listQueuedOwners(const QString &service)
+ { return ListQueuedOwners(service); }
+
+ QDBusReply<void> addMatch(const QString &rule)
+ { return AddMatch(rule); }
+ QDBusReply<void> removeMatch(const QString &rule)
+ { return RemoveMatch(rule); }
+
+ QDBusReply<QByteArray> connectionSELinuxSecurityContext(const QString &service)
+ { return GetConnectionSELinuxSecurityContext(service); }
+ QDBusReply<uint> connectionUnixProcessID(const QString &service)
+ { return GetConnectionUnixProcessID(service); }
+ QDBusReply<uint> connectionUnixUser(const QString &service)
+ { return GetConnectionUnixUser(service); }
+
+ QDBusReply<StartServiceReply> startServiceByName(const QString &name, uint flags)
+ { return StartServiceByName(name, flags); }
+
+signals:
+ void nameAcquired(const QString &service);
+ void nameLost(const QString &service);
+ void nameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDBusBusService::RequestNameOptions)
+
+#endif
diff --git a/qt/src/qdbusconnection.cpp b/qt/src/qdbusconnection.cpp
new file mode 100644
index 00000000..6cd733cb
--- /dev/null
+++ b/qt/src/qdbusconnection.cpp
@@ -0,0 +1,753 @@
+/* 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
+ *
+ * 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 <qdebug.h>
+#include <qcoreapplication.h>
+#include <qstringlist.h>
+
+#include "qdbusbus.h"
+#include "qdbusconnection.h"
+#include "qdbuserror.h"
+#include "qdbusmessage.h"
+#include "qdbusconnection_p.h"
+#include "qdbusinterface_p.h"
+#include "qdbusutil.h"
+
+class QDBusConnectionManager
+{
+public:
+ QDBusConnectionManager() {}
+ ~QDBusConnectionManager();
+ void bindToApplication();
+ QDBusConnectionPrivate *connection(const QString &name) const;
+ void removeConnection(const QString &name);
+ void setConnection(const QString &name, QDBusConnectionPrivate *c);
+
+private:
+ mutable QMutex mutex;
+ QHash<QString, QDBusConnectionPrivate *> connectionHash;
+};
+
+Q_GLOBAL_STATIC(QDBusConnectionManager, manager)
+
+QDBusConnectionPrivate *QDBusConnectionManager::connection(const QString &name) const
+{
+ QMutexLocker locker(&mutex);
+ return connectionHash.value(name, 0);
+}
+
+void QDBusConnectionManager::removeConnection(const QString &name)
+{
+ QMutexLocker locker(&mutex);
+
+ QDBusConnectionPrivate *d = 0;
+ d = connectionHash.take(name);
+ if (d && !d->ref.deref())
+ delete d;
+}
+
+QDBusConnectionManager::~QDBusConnectionManager()
+{
+ for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin();
+ it != connectionHash.constEnd(); ++it) {
+ delete it.value();
+ }
+ connectionHash.clear();
+}
+
+void QDBusConnectionManager::bindToApplication()
+{
+ QMutexLocker locker(&mutex);
+ for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin();
+ it != connectionHash.constEnd(); ++it) {
+ (*it)->bindToApplication();
+ }
+}
+
+QDBUS_EXPORT void qDBusBindToApplication();
+void qDBusBindToApplication()
+{
+ manager()->bindToApplication();
+}
+
+void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionPrivate *c)
+{
+ connectionHash[name] = c;
+ c->name = name;
+}
+
+/*!
+ \fn QDBusConnection QDBus::sessionBus()
+ \relates QDBusConnection
+
+ Returns a QDBusConnection object opened with the session bus. The object reference returned
+ by this function is valid until the QCoreApplication's destructor is run, when the
+ connection will be closed and the object, deleted.
+*/
+/*!
+ \fn QDBusConnection QDBus::systemBus()
+ \relates QDBusConnection
+
+ Returns a QDBusConnection object opened with the system bus. The object reference returned
+ by this function is valid until the QCoreApplication's destructor is run, when the
+ connection will be closed and the object, deleted.
+*/
+
+/*!
+ \class QDBusConnection
+ \brief A connection to the D-Bus bus daemon.
+
+ This class is the initial point in a D-Bus session. Using it, you can get access to remote
+ objects, interfaces; connect remote signals to your object's slots; register objects, etc.
+
+ D-Bus connections are created using the QDBusConnection::addConnection() function, which opens a
+ connection to the server daemon and does the initial handshaking, associating that connection
+ with a name. Further attempts to connect using the same name will return the same
+ connection.
+
+ The connection is then torn down using the QDBusConnection::closeConnection() function.
+
+ As a convenience for the two most common connection types, the QDBus::sessionBus() and
+ QDBus::systemBus() functions return open connections to the session server daemon and the system
+ server daemon, respectively. Those connections are opened when first used and are closed when
+ the QCoreApplication destructor is run.
+
+ D-Bus also supports peer-to-peer connections, without the need for a bus server daemon. Using
+ this facility, two applications can talk to each other and exchange messages. This can be
+ achieved by passing an address to QDBusConnection::addConnection()
+ function, which was opened by another D-Bus application using QDBusServer.
+*/
+
+/*!
+ \enum QDBusConnection::BusType
+ Specifies the type of the bus connection. The valid bus types are:
+
+ \value SessionBus the session bus, associated with the running desktop session
+ \value SystemBus the system bus, used to communicate with system-wide processes
+ \value ActivationBus the activation bus, whose purpose I have no idea...
+
+ On the Session Bus, one can find other applications by the same user that are sharing the same
+ desktop session (hence the name). On the System Bus, however, processes shared for the whole
+ system are usually found.
+*/
+
+/*!
+ \enum QDBusConnection::WaitMode
+ Specifies the call waiting mode.
+
+ \value UseEventLoop use the Qt Event Loop to wait for the reply
+ \value NoUseEventLoop don't use the event loop
+
+ The \c UseEventLoop option allows for the application to continue to update its UI while the
+ call is performed, but it also opens up the possibility for reentrancy: socket notifiers may
+ fire, signals may be delivered and other D-Bus calls may be processed. The \c NoUseEventLoop
+ does not use the event loop, thus being safe from those problems, but it may block the
+ application for a noticeable period of time, in case the remote application fails to respond.
+
+ Also note that calls that go back to the local application can only be placed in \c UseEventLoop
+ mode.
+*/
+
+/*!
+ \enum QDBusConnection::RegisterOption
+ Specifies the options for registering objects with the connection. The possible values are:
+
+ \value ExportAdaptors export the contents of adaptors found in this object
+
+ \value ExportSlots export this object's scriptable slots
+ \value ExportSignals export this object's scriptable signals
+ \value ExportProperties export this object's scriptable properties
+ \value ExportContents shorthand form for ExportSlots | ExportSignals |
+ ExportProperties
+
+ \value ExportAllSlots export all of this object's slots, including
+ non-scriptable ones
+ \value ExportAllSignals export all of this object's signals, including
+ non-scriptable ones
+ \value ExportAllProperties export all of this object's properties, including
+ non-scriptable ones
+ \value ExportAllContents export all of this object's slots, signals and
+ properties, including non-scriptable ones
+
+ \value ExportChildObjects export this object's child objects
+
+ \warning It is currently not possible to export signals from objects. If you pass the flag
+ ExportSignals or ExportAllSignals, the registerObject() function will print a warning.
+
+ \sa registerObject(), QDBusAbstractAdaptor, {usingadaptors.html}{Using adaptors}
+*/
+
+/*!
+ \enum QDBusConnection::UnregisterMode
+ The mode for unregistering an object path:
+
+ \value UnregisterNode unregister this node only: do not unregister child objects
+ \value UnregisterTree unregister this node and all its sub-tree
+
+ Note, however, if this object was registered with the ExportChildObjects option, UnregisterNode
+ will unregister the child objects too.
+*/
+
+/*!
+ Creates a QDBusConnection object attached to the connection with name \a name.
+
+ This does not open the connection. You have to call QDBusConnection::addConnection to open it.
+*/
+QDBusConnection::QDBusConnection(const QString &name)
+{
+ d = manager()->connection(name);
+ if (d)
+ d->ref.ref();
+}
+
+/*!
+ Creates a copy of the \a other connection.
+*/
+QDBusConnection::QDBusConnection(const QDBusConnection &other)
+{
+ d = other.d;
+ if (d)
+ d->ref.ref();
+}
+
+/*!
+ Disposes of this object. This does not close the connection: you have to call
+ QDBusConnection::closeConnection to do that.
+*/
+QDBusConnection::~QDBusConnection()
+{
+ if (d && !d->ref.deref())
+ delete d;
+}
+
+/*!
+ Creates a copy of the connection \a other in this object. The connection this object referenced
+ before the copy is not spontaneously disconnected. See QDBusConnection::closeConnection for more
+ information.
+*/
+QDBusConnection &QDBusConnection::operator=(const QDBusConnection &other)
+{
+ if (other.d)
+ other.d->ref.ref();
+ QDBusConnectionPrivate *old = static_cast<QDBusConnectionPrivate *>(
+ q_atomic_set_ptr(&d, other.d));
+ if (old && !old->ref.deref())
+ delete old;
+
+ return *this;
+}
+
+/*!
+ Opens a connection of type \a type to one of the known busses and associate with it the
+ connection name \a name. Returns a QDBusConnection object associated with that connection.
+*/
+QDBusConnection QDBusConnection::addConnection(BusType type, const QString &name)
+{
+// Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection",
+// "Cannot create connection without a Q[Core]Application instance");
+
+ QDBusConnectionPrivate *d = manager()->connection(name);
+ if (d || name.isEmpty())
+ return QDBusConnection(name);
+
+ d = new QDBusConnectionPrivate;
+ DBusConnection *c = 0;
+ switch (type) {
+ case SystemBus:
+ c = dbus_bus_get_private(DBUS_BUS_SYSTEM, &d->error);
+ break;
+ case SessionBus:
+ c = dbus_bus_get_private(DBUS_BUS_SESSION, &d->error);
+ break;
+ case ActivationBus:
+ c = dbus_bus_get_private(DBUS_BUS_STARTER, &d->error);
+ break;
+ }
+ d->setConnection(c); //setConnection does the error handling for us
+
+ manager()->setConnection(name, d);
+
+ QDBusConnection retval(name);
+
+ // create the bus service
+ QDBusAbstractInterfacePrivate *p;
+ p = retval.findInterface_helper(QLatin1String(DBUS_SERVICE_DBUS),
+ QLatin1String(DBUS_PATH_DBUS),
+ QLatin1String(DBUS_INTERFACE_DBUS));
+ if (p) {
+ d->busService = new QDBusBusService(p);
+ d->busService->setParent(d); // auto-deletion
+ d->ref.deref(); // busService has a increased the refcounting to us
+ }
+
+ return retval;
+}
+
+/*!
+ Opens a peer-to-peer connection on address \a address and associate with it the
+ connection name \a name. Returns a QDBusConnection object associated with that connection.
+*/
+QDBusConnection QDBusConnection::addConnection(const QString &address,
+ const QString &name)
+{
+// Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection",
+// "Cannot create connection without a Q[Core]Application instance");
+
+ QDBusConnectionPrivate *d = manager()->connection(name);
+ if (d || name.isEmpty())
+ return QDBusConnection(name);
+
+ d = new QDBusConnectionPrivate;
+ // setConnection does the error handling for us
+ d->setConnection(dbus_connection_open(address.toUtf8().constData(), &d->error));
+
+ manager()->setConnection(name, d);
+
+ QDBusConnection retval(name);
+
+ // create the bus service
+ QDBusAbstractInterfacePrivate *p;
+ p = retval.findInterface_helper(QLatin1String(DBUS_SERVICE_DBUS),
+ QLatin1String(DBUS_PATH_DBUS),
+ QLatin1String(DBUS_INTERFACE_DBUS));
+ if (p) {
+ d->busService = new QDBusBusService(p);
+ d->busService->setParent(d); // auto-deletion
+ d->ref.deref(); // busService has a increased the refcounting to us
+ }
+
+ return retval;
+}
+
+/*!
+ Closes the connection of name \a name.
+
+ Note that if there are still QDBusConnection objects associated with the same connection, the
+ connection will not be closed until all references are dropped. However, no further references
+ can be created using the QDBusConnection::QDBusConnection constructor.
+*/
+void QDBusConnection::closeConnection(const QString &name)
+{
+ manager()->removeConnection(name);
+}
+
+/*!
+ Sends the \a message over this connection, without waiting for a reply. This is suitable for
+ errors, signals, and return values as well as calls whose return values are not necessary.
+
+ Returns true if the message was queued successfully, false otherwise.
+*/
+bool QDBusConnection::send(const QDBusMessage &message) const
+{
+ if (!d || !d->connection)
+ return false;
+ return d->send(message) != 0;
+}
+
+/*!
+ Sends the \a message over this connection and returns immediately after queueing it. When the
+ reply is received, the slot \a method is called in the object \a receiver. This function is
+ suitable for method calls only.
+
+ This function guarantees that the slot will be called exactly once with the reply, as long as
+ the parameter types match. If they don't, the reply cannot be delivered.
+
+ Returns the identification of the message that was sent or 0 if nothing was sent.
+*/
+int QDBusConnection::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
+ const char *method) const
+{
+ if (!d || !d->connection)
+ return 0;
+
+ return d->sendWithReplyAsync(message, receiver, method);
+}
+
+/*!
+ Sends the \a message over this connection and blocks, waiting for a reply. This function is
+ suitable for method calls only. It returns the reply message as its return value, which will be
+ either of type QDBusMessage::ReplyMessage or QDBusMessage::ErrorMessage.
+
+ See the QDBusInterface::call function for a more friendly way of placing calls.
+
+ \warning If \a mode is \c UseEventLoop, this function will reenter the Qt event loop in order to
+ wait for the reply. During the wait, it may deliver signals and other method calls to
+ your application. Therefore, it must be prepared to handle a reentrancy whenever a call
+ is placed with sendWithReply.
+*/
+QDBusMessage QDBusConnection::sendWithReply(const QDBusMessage &message, WaitMode mode) const
+{
+ if (!d || !d->connection)
+ return QDBusMessage();
+ return d->sendWithReply(message, mode);
+}
+
+/*!
+ Connects the signal specified by the \a service, \a path, \a interface and \a name parameters to
+ the slot \a slot in object \a receiver. The arguments \a service and \a path can be empty,
+ denoting a connection to any signal of the \a interface - \a name pair, from any remote
+ application.
+
+ Returns true if the connection was successful.
+
+ \warning The signal will only be delivered to the slot if the parameters match. This verification
+ can be done only when the signal is received, not at connection time.
+*/
+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);
+}
+
+/*!
+ \overload
+ Connects the signal to the slot \a slot in object \a receiver. Unlike the other
+ QDBusConnection::connect overload, this function allows one to specify the parameter signature
+ to be connected using the \a signature variable. The function will then verify that this
+ signature can be delivered to the slot specified by \a slot and return false otherwise.
+*/
+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 || !QDBusUtil::isValidInterfaceName(interface))
+ return false;
+
+ QString source;
+ if (!service.isEmpty()) {
+ source = d->getNameOwner(service);
+ if (source.isEmpty())
+ return false;
+ }
+
+ // check the slot
+ QDBusConnectionPrivate::SignalHook hook;
+ QString key;
+ hook.signature = signature;
+ if (!d->prepareHook(hook, key, source, path, interface, name, receiver, slot, 0, false))
+ return false; // don't connect
+
+ // avoid duplicating:
+ QWriteLocker locker(&d->lock);
+ QDBusConnectionPrivate::SignalHookHash::ConstIterator it = d->signalHooks.find(key);
+ for ( ; it != d->signalHooks.end() && it.key() == key; ++it) {
+ const QDBusConnectionPrivate::SignalHook &entry = it.value();
+ if (entry.sender == hook.sender &&
+ entry.path == hook.path &&
+ entry.signature == hook.signature &&
+ entry.obj == hook.obj &&
+ entry.midx == hook.midx) {
+ // no need to compare the parameters if it's the same slot
+ return true; // already there
+ }
+ }
+
+
+ d->connectSignal(key, hook);
+ return true;
+}
+
+/*!
+ Registers the object \a object at path \a path and returns true if the registration was
+ successful. The \a options parameter specifies how much of the object \a object will be exposed
+ through D-Bus.
+
+ This function does not replace existing objects: if there is already an object registered at
+ path \a path, this function will return false. Use unregisterObject() to unregister it first.
+
+ You cannot register an object as a child object of an object that was registered with
+ QDBusConnection::ExportChildObjects.
+*/
+bool QDBusConnection::registerObject(const QString &path, QObject *object, RegisterOptions options)
+{
+ if (!d || !d->connection || !object || !options || !QDBusUtil::isValidObjectPath(path))
+ return false;
+
+ if (options & ExportSignals) {
+ qWarning("Cannot export signals from objects. Use an adaptor for that purpose.");
+ return false;
+ }
+
+ QStringList pathComponents = path.split(QLatin1Char('/'));
+ if (pathComponents.last().isEmpty())
+ pathComponents.removeLast();
+ QWriteLocker locker(&d->lock);
+
+ // lower-bound search for where this object should enter in the tree
+ QDBusConnectionPrivate::ObjectTreeNode *node = &d->rootNode;
+ int i = 1;
+ while (node) {
+ if (pathComponents.count() == i) {
+ // this node exists
+ // consider it free if there's no object here and the user is not trying to
+ // replace the object sub-tree
+ if ((options & ExportChildObjects && !node->children.isEmpty()) || node->obj)
+ return false;
+
+ // we can add the object here
+ node->obj = object;
+ node->flags = options;
+
+ d->registerObject(node);
+ qDebug("REGISTERED FOR %s", path.toLocal8Bit().constData());
+ return true;
+ }
+
+ // find the position where we'd insert the node
+ QVector<QDBusConnectionPrivate::ObjectTreeNode::Data>::Iterator it =
+ qLowerBound(node->children.begin(), node->children.end(), pathComponents.at(i));
+ if (it != node->children.constEnd() && it->name == pathComponents.at(i)) {
+ // match: this node exists
+ node = it->node;
+
+ // are we allowed to go deeper?
+ if (node->flags & ExportChildObjects) {
+ // we're not
+ qDebug("Cannot register object at %s because %s exports its own child objects",
+ qPrintable(path), qPrintable(pathComponents.at(i)));
+ return false;
+ }
+ } else {
+ // add entry
+ QDBusConnectionPrivate::ObjectTreeNode::Data entry;
+ entry.name = pathComponents.at(i);
+ entry.node = new QDBusConnectionPrivate::ObjectTreeNode;
+ node->children.insert(it, entry);
+
+ node = entry.node;
+ }
+
+ // iterate
+ ++i;
+ }
+
+ Q_ASSERT_X(false, "QDBusConnection::registerObject", "The impossible happened");
+ return false;
+}
+
+/*!
+ Unregisters an object that was registered with the registerObject() at the object path given by
+ \a path and, if \a mode is QDBusConnection::UnregisterTree, all of its sub-objects too.
+
+ Note that you cannot unregister objects that were not registered with registerObject().
+*/
+void QDBusConnection::unregisterObject(const QString &path, UnregisterMode mode)
+{
+ if (!d || !d->connection || !QDBusUtil::isValidObjectPath(path))
+ return;
+
+ QStringList pathComponents = path.split(QLatin1Char('/'));
+ QWriteLocker locker(&d->lock);
+ QDBusConnectionPrivate::ObjectTreeNode *node = &d->rootNode;
+ int i = 1;
+
+ // find the object
+ while (node) {
+ if (pathComponents.count() == i) {
+ // found it
+ node->obj = 0;
+ node->flags = 0;
+
+ if (mode == UnregisterTree) {
+ // clear the sub-tree as well
+ node->clear(); // can't disconnect the objects because we really don't know if they can
+ // be found somewhere else in the path too
+ }
+
+ return;
+ }
+
+ QVector<QDBusConnectionPrivate::ObjectTreeNode::Data>::ConstIterator it =
+ qLowerBound(node->children.constBegin(), node->children.constEnd(), pathComponents.at(i));
+ if (it == node->children.constEnd() || it->name != pathComponents.at(i))
+ break; // node not found
+
+ node = it->node;
+ ++i;
+ }
+}
+
+/*!
+ Returns a dynamic QDBusInterface associated with the interface \a interface on object at path \a
+ path on service \a service.
+
+ This function creates a new object. It is your resposibility to ensure it is properly deleted
+ (you can use all normal QObject deletion mechanisms, including the QObject::deleteLater() slot
+ and QObject::setParent()).
+
+ If the searching for this interface on the remote object failed, this function returns 0.
+*/
+QDBusInterface *QDBusConnection::findInterface(const QString& service, const QString& path,
+ const QString& interface)
+{
+ if (!d)
+ return 0;
+
+ QDBusInterfacePrivate *p = d->findInterface(service, path, interface);
+ QDBusInterface *retval = new QDBusInterface(p);
+ retval->setParent(d);
+ return retval;
+}
+
+/*!
+ \fn QDBusConnection::findInterface(const QString &service, const QString &path)
+ Returns an interface of type \c Interface associated with the object on path \a path at service
+ \a service.
+
+ \c Interface must be a class generated by \l {dbusidl2cpp.html}.
+
+ This function creates a new object. It is your resposibility to ensure it is properly deleted
+ (you can use all normal QObject deletion mechanisms, including the QObject::deleteLater() slot
+ and QObject::setParent()).
+*/
+
+/*!
+ Returns a QDBusBusService object that represents the D-Bus bus service on this connection.
+
+ This function returns 0 for peer-to-peer connections.
+*/
+QDBusBusService *QDBusConnection::busService() const
+{
+ if (!d)
+ return 0;
+ return d->busService;
+}
+
+QDBusAbstractInterfacePrivate *
+QDBusConnection::findInterface_helper(const QString &service, const QString &path,
+ const QString &interface)
+{
+ if (!d)
+ return 0;
+ if (!interface.isEmpty() && !QDBusUtil::isValidInterfaceName(interface))
+ return 0;
+
+ QString owner;
+ if (!service.isEmpty()) {
+ if (!QDBusUtil::isValidObjectPath(path))
+ return 0;
+
+ // check if it's there first -- FIXME: add binding mode
+ owner = d->getNameOwner(service);
+ if (owner.isEmpty())
+ return 0;
+ } else if (!path.isEmpty())
+ return 0;
+
+ return new QDBusAbstractInterfacePrivate(*this, d, owner, path, interface);
+}
+
+/*!
+ Returns true if this QDBusConnection object is connected.
+
+ If it isn't connected, calling QDBusConnection::addConnection on the same connection name
+ will not make be connected. You need to call the QDBusConnection constructor again.
+*/
+bool QDBusConnection::isConnected( ) const
+{
+ return d && d->connection && dbus_connection_get_is_connected(d->connection);
+}
+
+/*!
+ Returns the last error that happened in this connection.
+
+ This function is provided for low-level code. If you're using QDBusInterface::call, error codes are
+ reported by its return value.
+
+ \sa QDBusInterface, QDBusMessage
+*/
+QDBusError QDBusConnection::lastError() const
+{
+ return d ? d->lastError : QDBusError();
+}
+
+/*!
+ Returns the unique connection name for this connection, if this QDBusConnection object is
+ connected, or an empty QString otherwise.
+
+ A Unique Connection Name is a string in the form ":x.xxx" (where x are decimal digits) that is
+ assigned by the D-Bus server daemon upon connection. It uniquely identifies this client in the
+ bus.
+
+ This function returns an empty QString for peer-to-peer connections.
+*/
+QString QDBusConnection::baseService() const
+{
+ return d && d->connection ?
+ QString::fromUtf8(dbus_bus_get_unique_name(d->connection))
+ : QString();
+}
+
+Q_GLOBAL_STATIC(QMutex, defaultBussesMutex)
+static const char sessionBusName[] = "qt_default_session_bus";
+static const char systemBusName[] = "qt_default_system_bus";
+static QDBusConnection *sessionBus = 0;
+static QDBusConnection *systemBus = 0;
+
+static void closeConnections()
+{
+ QMutexLocker locker(defaultBussesMutex());
+ delete sessionBus;
+ delete systemBus;
+ QDBusConnection::closeConnection(QLatin1String(sessionBusName));
+ QDBusConnection::closeConnection(QLatin1String(systemBusName));
+ sessionBus = systemBus = 0;
+}
+
+static QDBusConnection *openConnection(QDBusConnection::BusType type)
+{
+ QMutexLocker locker(defaultBussesMutex());
+ qAddPostRoutine(closeConnections);
+
+ if (type == QDBusConnection::SystemBus) {
+ if (systemBus)
+ // maybe it got created before we locked the mutex
+ return systemBus;
+ systemBus = new QDBusConnection(QDBusConnection::addConnection(QDBusConnection::SystemBus,
+ QLatin1String(systemBusName)));
+ return systemBus;
+ } else {
+ if (sessionBus)
+ // maybe it got created before we locked the mutex
+ return sessionBus;
+ sessionBus = new QDBusConnection(QDBusConnection::addConnection(QDBusConnection::SessionBus,
+ QLatin1String(sessionBusName)));
+ return sessionBus;
+ }
+}
+
+namespace QDBus {
+ QDBusConnection &sessionBus()
+ {
+ if (::sessionBus) return *::sessionBus;
+ return *openConnection(QDBusConnection::SessionBus);
+ }
+
+ QDBusConnection &systemBus()
+ {
+ if (::systemBus) return *::systemBus;
+ return *openConnection(QDBusConnection::SystemBus);
+ }
+}
+
diff --git a/qt/src/qdbusconnection.h b/qt/src/qdbusconnection.h
new file mode 100644
index 00000000..c1c420a6
--- /dev/null
+++ b/qt/src/qdbusconnection.h
@@ -0,0 +1,124 @@
+/* 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
+ *
+ * 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 QDBUSCONNECTION_H
+#define QDBUSCONNECTION_H
+
+#include "qdbusmacros.h"
+#include <QtCore/qstring.h>
+
+class QDBusAbstractInterfacePrivate;
+class QDBusInterface;
+class QDBusError;
+class QDBusMessage;
+class QDBusBusService;
+class QObject;
+
+class QDBusConnectionPrivate;
+class QDBUS_EXPORT QDBusConnection
+{
+public:
+ enum BusType { SessionBus, SystemBus, ActivationBus };
+ enum WaitMode { UseEventLoop, NoUseEventLoop };
+ enum RegisterOption {
+ ExportAdaptors = 0x01,
+
+ ExportSlots = 0x10,
+ ExportSignals = 0x20,
+ ExportProperties = 0x40,
+ ExportContents = 0xf0,
+
+ ExportAllSlots = 0x110,
+ ExportAllSignals = 0x220,
+ ExportAllProperties = 0x440,
+ ExportAllContents = 0xff0,
+
+ ExportChildObjects = 0x1000
+ };
+ enum UnregisterMode {
+ UnregisterNode,
+ UnregisterTree
+ };
+
+ Q_DECLARE_FLAGS(RegisterOptions, RegisterOption)
+
+ QDBusConnection(const QString &name);
+ QDBusConnection(const QDBusConnection &other);
+ ~QDBusConnection();
+
+ QDBusConnection &operator=(const QDBusConnection &other);
+
+ bool isConnected() const;
+ QString baseService() const;
+ QDBusError lastError() const;
+
+ bool send(const QDBusMessage &message) const;
+ QDBusMessage sendWithReply(const QDBusMessage &message, WaitMode mode = NoUseEventLoop) const;
+ int sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
+ const char *slot) const;
+
+ 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, QObject *object,
+ RegisterOptions options = ExportAdaptors);
+ void unregisterObject(const QString &path, UnregisterMode mode = UnregisterNode);
+
+ template<class Interface>
+ inline Interface *findInterface(const QString &service, const QString &path);
+ QDBusInterface *findInterface(const QString& service, const QString& path,
+ const QString& interface = QString());
+
+ QDBusBusService *busService() const;
+
+ static QDBusConnection addConnection(BusType type, const QString &name);
+ static QDBusConnection addConnection(const QString &address, const QString &name);
+ static void closeConnection(const QString &name);
+
+private:
+ QDBusAbstractInterfacePrivate *findInterface_helper(const QString &, const QString &,
+ const QString&);
+ QDBusConnectionPrivate *d;
+};
+
+template<class Interface>
+inline Interface *QDBusConnection::findInterface(const QString &service, const QString &path)
+{
+ register QDBusAbstractInterfacePrivate *d;
+ d = findInterface_helper(service, path, Interface::staticInterfaceName());
+ if (d)
+ return new Interface(d);
+ return 0;
+}
+
+namespace QDBus {
+ QDBUS_EXPORT QDBusConnection &sessionBus();
+ QDBUS_EXPORT QDBusConnection &systemBus();
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDBusConnection::RegisterOptions)
+#endif
diff --git a/qt/src/qdbusconnection_p.h b/qt/src/qdbusconnection_p.h
new file mode 100644
index 00000000..bab0b65d
--- /dev/null
+++ b/qt/src/qdbusconnection_p.h
@@ -0,0 +1,245 @@
+/* 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
+ *
+ * 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 QDBUSCONNECTION_P_H
+#define QDBUSCONNECTION_P_H
+
+#include "qdbuserror.h"
+
+#include <QtCore/qatomic.h>
+#include <QtCore/qeventloop.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qreadwritelock.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qvector.h>
+
+#include <dbus/dbus.h>
+
+#include "qdbusmessage.h"
+
+class QDBusMessage;
+class QSocketNotifier;
+class QTimerEvent;
+class QDBusObjectPrivate;
+class CallDeliveryEvent;
+class QMetaMethod;
+class QDBusInterfacePrivate;
+struct QDBusMetaObject;
+class QDBusAbstractInterface;
+class QDBusBusService;
+
+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
+ {
+ inline SignalHook() : obj(0), midx(-1) { }
+ QString sender, path, signature;
+ QObject* obj;
+ int midx;
+ QList<int> params;
+ };
+
+ struct ObjectTreeNode
+ {
+ struct Data
+ {
+ QString name;
+ ObjectTreeNode *node;
+
+ inline bool operator<(const QString &other) const
+ { return name < other; }
+ };
+
+ inline ObjectTreeNode() : obj(0), flags(0) { }
+ inline ~ObjectTreeNode() { clear(); }
+ inline void clear()
+ {
+ foreach (const Data &entry, children) {
+ entry.node->clear();
+ delete entry.node;
+ }
+ children.clear();
+ }
+
+ QObject* obj;
+ int flags;
+ QVector<Data> children;
+ };
+
+public:
+ // typedefs
+ typedef QMultiHash<int, Watcher> WatcherHash;
+ typedef QHash<int, DBusTimeout *> TimeoutHash;
+ typedef QMultiHash<QString, SignalHook> SignalHookHash;
+ typedef QHash<QString, QDBusMetaObject* > MetaObjectHash;
+
+public:
+ // public methods
+ QDBusConnectionPrivate(QObject *parent = 0);
+ ~QDBusConnectionPrivate();
+
+ void bindToApplication();
+
+ void setConnection(DBusConnection *connection);
+ void setServer(DBusServer *server);
+ void closeConnection();
+ void timerEvent(QTimerEvent *e);
+
+ QString getNameOwner(const QString &service);
+
+ int send(const QDBusMessage &message) const;
+ QDBusMessage sendWithReply(const QDBusMessage &message, int mode);
+ int sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
+ const char *method);
+ void connectSignal(const QString &key, const SignalHook &hook);
+ void registerObject(const ObjectTreeNode *node);
+ void connectRelay(const QString &service, const QString &path, const QString &interface,
+ QDBusAbstractInterface *receiver, const char *signal);
+ void disconnectRelay(const QString &service, const QString &path, const QString &interface,
+ QDBusAbstractInterface *receiver, const char *signal);
+
+ bool handleSignal(const QString &key, const QDBusMessage &msg);
+ bool handleSignal(const QDBusMessage &msg);
+ bool handleObjectCall(const QDBusMessage &message);
+ bool handleError();
+
+ bool activateSignal(const SignalHook& hook, const QDBusMessage &msg);
+ bool activateCall(QObject* object, int flags, const QDBusMessage &msg);
+ bool activateObject(const ObjectTreeNode *node, const QDBusMessage &msg);
+ bool activateInternalFilters(const ObjectTreeNode *node, const QDBusMessage &msg);
+
+ void postCallDeliveryEvent(CallDeliveryEvent *data);
+ CallDeliveryEvent *postedCallDeliveryEvent();
+ void deliverCall(const CallDeliveryEvent &data) const;
+
+ QDBusInterfacePrivate *findInterface(const QString &service, const QString &path,
+ const QString &interface);
+
+protected:
+ virtual void customEvent(QEvent *event);
+
+private:
+ QDBusMetaObject *findMetaObject(const QString &service, const QString &path,
+ const QString &interface);
+
+public slots:
+ // public slots
+ void doDispatch();
+ void socketRead(int);
+ void socketWrite(int);
+ void objectDestroyed(QObject *o);
+ void relaySignal(QObject *obj, const char *interface, const char *name, const QVariantList &args);
+
+public:
+ // public member variables
+ QString name; // this connection's name
+
+ DBusError error;
+ QDBusError lastError;
+
+ QAtomic ref;
+ QReadWriteLock lock;
+ ConnectionMode mode;
+ DBusConnection *connection;
+ DBusServer *server;
+ QDBusBusService *busService;
+
+ WatcherHash watchers;
+ TimeoutHash timeouts;
+ SignalHookHash signalHooks;
+ QList<DBusTimeout *> pendingTimeouts;
+
+ ObjectTreeNode rootNode;
+ MetaObjectHash cachedMetaObjects;
+
+ QMutex callDeliveryMutex;
+ CallDeliveryEvent *callDeliveryState; // protected by the callDeliveryMutex mutex
+
+public:
+ // static methods
+ static int messageMetaType;
+ static int registerMessageMetaType();
+ static int findSlot(QObject *obj, const QByteArray &normalizedName, QList<int>& params);
+ static bool prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
+ const QString &service, const QString &path,
+ const QString &interface, const QString &name,
+ QObject *receiver, const char *signal, int minMIdx,
+ bool buildSignature);
+ static DBusHandlerResult messageFilter(DBusConnection *, DBusMessage *, void *);
+ static void messageResultReceived(DBusPendingCall *, void *);
+};
+
+class QDBusReplyWaiter: public QEventLoop
+{
+ Q_OBJECT
+public:
+ QDBusMessage replyMsg;
+
+public slots:
+ void reply(const QDBusMessage &msg);
+};
+
+// in qdbusmisc.cpp
+extern int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes);
+extern int qDBusNameToTypeId(const char *name);
+extern bool qDBusCheckAsyncTag(const char *tag);
+
+// in qdbusinternalfilters.cpp
+extern QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node);
+extern void qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node,
+ const QDBusMessage &msg);
+extern void qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode *node,
+ const QDBusMessage &msg);
+extern void qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode *node,
+ const QDBusMessage &msg);
+
+#endif
diff --git a/qt/src/qdbuserror.cpp b/qt/src/qdbuserror.cpp
new file mode 100644
index 00000000..d5cd6758
--- /dev/null
+++ b/qt/src/qdbuserror.cpp
@@ -0,0 +1,244 @@
+/* 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
+ *
+ * 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 "qdbuserror.h"
+
+#include <qdebug.h>
+#include <qvarlengtharray.h>
+
+#include <dbus/dbus.h>
+#include "qdbusmessage.h"
+
+struct ErrorMessageMapping
+{
+ ErrorMessageMapping();
+ QVarLengthArray<const char*, QDBusError::qKnownErrorsMax> messages;
+
+ inline const char *get(QDBusError::KnownErrors code) const
+ {
+ if (code <= QDBusError::Other || code > QDBusError::qKnownErrorsMax)
+ return messages[int(QDBusError::Other) - 1];
+ return messages[int(code) - 1];
+ }
+
+ inline QDBusError::KnownErrors get(const char *name) const
+ {
+ if (!name || !*name)
+ return QDBusError::NoError;
+ for (int i = QDBusError::Other; i <= QDBusError::qKnownErrorsMax; ++i)
+ if (strcmp(name, messages[i - 1]) == 0)
+ return QDBusError::KnownErrors(i);
+ return QDBusError::Other;
+ }
+};
+
+static const char errorMessages_string[] =
+ // in the same order as KnownErrors!
+ "other\0" // Other -- shouldn't happen
+ DBUS_ERROR_FAILED "\0" // Failed
+ DBUS_ERROR_NO_MEMORY "\0" // NoMemory
+ DBUS_ERROR_SERVICE_UNKNOWN "\0" // ServiceUnknown
+ DBUS_ERROR_NO_REPLY "\0" // NoReply
+ DBUS_ERROR_BAD_ADDRESS "\0" // BadAddress
+ DBUS_ERROR_NOT_SUPPORTED "\0" // NotSupported
+ DBUS_ERROR_LIMITS_EXCEEDED "\0" // LimitsExceeded
+ DBUS_ERROR_ACCESS_DENIED "\0" // AccessDenied
+ DBUS_ERROR_NO_SERVER "\0" // NoServer
+ DBUS_ERROR_TIMEOUT "\0" // Timeout
+ DBUS_ERROR_NO_NETWORK "\0" // NoNetwork
+ DBUS_ERROR_ADDRESS_IN_USE "\0" // AddressInUse
+ DBUS_ERROR_DISCONNECTED "\0" // Disconnected
+ DBUS_ERROR_INVALID_ARGS "\0" // InvalidArgs
+ DBUS_ERROR_UNKNOWN_METHOD "\0" // UnknownMethod
+ DBUS_ERROR_TIMED_OUT "\0" // TimedOut
+ DBUS_ERROR_INVALID_SIGNATURE "\0" // InvalidSignature
+ "com.trolltech.QtDBus.Error.UnknownInterface\0" // UnknownInterface
+ "com.trolltech.QtDBus.Error.InternalError\0" // InternalError
+ "\0";
+
+ErrorMessageMapping::ErrorMessageMapping()
+ : messages(int(QDBusError::qKnownErrorsMax))
+{
+ // create the list:
+ const char *p = errorMessages_string;
+ int i = 0;
+ while (*p) {
+ messages[i] = p;
+ p += strlen(p) + 1;
+ ++i;
+ }
+}
+
+Q_GLOBAL_STATIC(ErrorMessageMapping, errorMessages)
+
+/*!
+ \class QDBusError
+ \brief Represents an error received from the D-Bus bus or from remote applications found in the bus.
+
+ When dealing with the D-Bus bus service or with remote applications over D-Bus, a number of
+ error conditions can happen. This error conditions are sometimes signalled by a returned error
+ value or by a QDBusError.
+
+ C++ and Java exceptions are a valid analogy for D-Bus errors: instead of returning normally with
+ a return value, remote applications and the bus may decide to throw an error condition. However,
+ the QtDBus implementation does not use the C++ exception-throwing mechanism, so you will receive
+ QDBusErrors in the return reply (see QDBusReply::error()).
+
+ QDBusError objects are used to inspect the error name and message as received from the bus and
+ remote applications. You should not create such objects yourself to signal error conditions when
+ called from D-Bus: instead, use QDBusMessage::error and QDBusConnection::send.
+
+ \sa QDBusConnection::send(), QDBusMessage, QDBusReply
+*/
+
+/*!
+ \enum QDBusError::KnownErrors
+
+ In order to facilitate verification of the most common D-Bus errors generated by the D-Bus
+ implementation and by the bus daemon itself, QDBusError can be compared to a set of pre-defined
+ values:
+
+ \value NoError QDBusError is invalid (i.e., the call succeeded)
+ \value Other QDBusError contains an error that is one of the well-known ones
+ \value Failed The call failed (\c org.freedesktop.DBus.Error.Failed)
+ \value NoMemory Out of memory (\c org.freedesktop.DBus.Error.NoMemory)
+ \value ServiceUnknown The called service is not known
+ (\c org.freedesktop.DBus.Error.ServiceUnknown)
+ \value NoReply The called method did not reply within the specified timeout
+ (\c org.freedesktop.DBus.Error.NoReply)
+ \value BadAddress The address given is not valid
+ (\c org.freedesktop.DBus.Error.BadAddress)
+ \value NotSupported The call/operation is not supported
+ (\c org.freedesktop.DBus.Error.NotSupported)
+ \value LimitsExceeded The limits allocated to this process/call/connection exceeded the
+ pre-defined values (\c org.freedesktop.DBus.Error.LimitsExceeded)
+ \value AccessDenied The call/operation tried to access a resource it isn't allowed to
+ (\c org.freedesktop.DBus.Error.AccessDenied)
+ \value NoServer \i{Documentation doesn't say what this is for}
+ (\c org.freedesktop.DBus.Error.NoServer)
+ \value Timeout \i{Documentation doesn't say what this is for or how it's used}
+ (\c org.freedesktop.DBus.Error.Timeout)
+ \value NoNetwork \i{Documentation doesn't say what this is for}
+ (\c org.freedesktop.DBus.Error.NoNetwork)
+ \value AddressInUse QDBusServer tried to bind to an address that is already in use
+ (\c org.freedesktop.DBus.Error.AddressInUse)
+ \value Disconnected The call/process/message was sent after QDBusConnection disconnected
+ (\c org.freedesktop.DBus.Error.Disconnected)
+ \value InvalidArgs The arguments passed to this call/operation are not valid
+ (\c org.freedesktop.DBus.Error.InvalidArgs)
+ \value UnknownMethod The method called was not found in this object/interface with the
+ given parameters (\c org.freedesktop.DBus.Error.UnknownMethod)
+ \value TimedOut \i{Documentation doesn't say...}
+ (\c org.freedesktop.DBus.Error.TimedOut)
+ \value InvalidSignature The type signature is not valid or compatible
+ (\c org.freedesktop.DBus.Error.InvalidSignature)
+ \value UnknownInterface The interface is not known
+ \value InternalError An internal error occurred
+ (\c com.trolltech.QtDBus.Error.InternalError)
+
+*/
+
+/*!
+ \internal
+ Constructs a QDBusError from a DBusError structure.
+*/
+QDBusError::QDBusError(const DBusError *error)
+ : code(NoError)
+{
+ if (!error || !dbus_error_is_set(error))
+ return;
+
+ code = errorMessages()->get(error->name);
+ nm = QString::fromUtf8(error->name);
+ msg = QString::fromUtf8(error->message);
+}
+
+/*!
+ \internal
+ Constructs a QDBusError from a QDBusMessage.
+*/
+QDBusError::QDBusError(const QDBusMessage &qdmsg)
+ : code(Other)
+{
+ if (qdmsg.type() != QDBusMessage::ErrorMessage)
+ return;
+
+ nm = qdmsg.name();
+ if (qdmsg.count())
+ msg = qdmsg[0].toString();
+ code = errorMessages()->get(nm.toUtf8().constData());
+}
+
+/*!
+ \internal
+ Constructs a QDBusError from a well-known error code
+*/
+QDBusError::QDBusError(KnownErrors error, const QString &message)
+ : code(error)
+{
+ nm = errorMessages()->get(error);
+ msg = message;
+}
+
+/*!
+ \fn QDBusError::name() const
+ Returns this error's name. Error names are similar to D-Bus Interface names, like
+ "org.freedesktop.DBus.InvalidArgs".
+*/
+
+/*!
+ \fn QDBusError::message() const
+ Returns the message that the callee associated with this error. Error messages are
+ implementation defined and usually contain a human-readable error code, though this does not
+ mean it is suitable for your end-users.
+*/
+
+/*!
+ \fn QDBusError::isValid() const
+ Returns true if this is a valid error condition (i.e., if there was an error), false otherwise.
+*/
+
+/*!
+ \fn QDBusError::operator==(KnownErrors error) const
+ Compares this QDBusError against the well-known error code \a error and returns true if they
+ match.
+*/
+
+/*!
+ \fn operator==(QDBusError::KnownErrors p1, const QDBusError &p2)
+ \relates QDBusError
+
+ Compares the QDBusError \a p2 against the well-known error code \a p1 and returns true if they
+ match.
+*/
+
+#ifndef QT_NO_DEBUG
+QDebug operator<<(QDebug dbg, const QDBusError &msg)
+{
+ dbg.nospace() << "QDBusError(" << msg.name() << ", " << msg.message() << ")";
+ return dbg.space();
+}
+#endif
+
+
diff --git a/qt/src/qdbuserror.h b/qt/src/qdbuserror.h
new file mode 100644
index 00000000..71c636df
--- /dev/null
+++ b/qt/src/qdbuserror.h
@@ -0,0 +1,93 @@
+/* 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
+ *
+ * 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 QDBUSERROR_H
+#define QDBUSERROR_H
+
+#include "qdbusmacros.h"
+#include <QtCore/qstring.h>
+
+struct DBusError;
+class QDBusMessage;
+
+class QDBUS_EXPORT QDBusError
+{
+public:
+ enum KnownErrors {
+ NoError = 0,
+ Other = 1,
+ Failed,
+ NoMemory,
+ ServiceUnknown,
+ NoReply,
+ BadAddress,
+ NotSupported,
+ LimitsExceeded,
+ AccessDenied,
+ NoServer,
+ Timeout,
+ NoNetwork,
+ AddressInUse,
+ Disconnected,
+ InvalidArgs,
+ UnknownMethod,
+ TimedOut,
+ InvalidSignature,
+ UnknownInterface,
+ InternalError,
+
+#ifndef Q_QDOC
+ // don't use this one!
+ qKnownErrorsMax = InternalError
+#endif
+ };
+
+ QDBusError(const DBusError *error = 0);
+ QDBusError(const QDBusMessage& msg);
+ QDBusError(KnownErrors error, const QString &message);
+
+ inline QString name() const { return nm; }
+ inline QString message() const { return msg; }
+ inline bool isValid() const { return !nm.isNull() && !msg.isNull(); }
+
+ inline bool operator==(KnownErrors error) const
+ { return code == error; }
+
+private:
+ KnownErrors code;
+ QString nm, msg;
+};
+
+inline bool operator==(QDBusError::KnownErrors p1, const QDBusError &p2)
+{ return p2 == p1; }
+inline bool operator!=(QDBusError::KnownErrors p1, const QDBusError &p2)
+{ return !(p2 == p1); }
+inline bool operator!=(const QDBusError &p1, QDBusError::KnownErrors p2)
+{ return !(p1 == p2); }
+
+#ifndef QT_NO_DEBUG
+QDebug operator<<(QDebug, const QDBusError &);
+#endif
+
+#endif
diff --git a/qt/src/qdbusintegrator.cpp b/qt/src/qdbusintegrator.cpp
new file mode 100644
index 00000000..07921cf9
--- /dev/null
+++ b/qt/src/qdbusintegrator.cpp
@@ -0,0 +1,1552 @@
+/* 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 <qcoreapplication.h>
+#include <qcoreevent.h>
+#include <qdebug.h>
+#include <qmetaobject.h>
+#include <qobject.h>
+#include <qsocketnotifier.h>
+#include <qstringlist.h>
+#include <qtimer.h>
+
+#include "qdbusconnection_p.h"
+#include "qdbusinterface_p.h"
+#include "qdbusmessage.h"
+#include "qdbusabstractadaptor.h"
+#include "qdbusabstractadaptor_p.h"
+#include "qdbustypehelper_p.h"
+#include "qdbusutil.h"
+#include "qdbustype_p.h"
+
+#ifndef USE_OUTSIDE_DISPATCH
+# define USE_OUTSIDE_DISPATCH 0
+#endif
+
+int QDBusConnectionPrivate::messageMetaType = 0;
+
+typedef void (*QDBusSpyHook)(const QDBusMessage&);
+typedef QVarLengthArray<QDBusSpyHook, 4> QDBusSpyHookList;
+Q_GLOBAL_STATIC(QDBusSpyHookList, qDBusSpyHookList)
+
+struct QDBusPendingCall
+{
+ QPointer<QObject> receiver;
+ QList<int> metaTypes;
+ int methodIdx;
+ DBusPendingCall *pending;
+ const QDBusConnectionPrivate *connection;
+};
+
+class CallDeliveryEvent: public QEvent
+{
+public:
+ CallDeliveryEvent()
+ : QEvent(QEvent::User), object(0), flags(0), slotIdx(-1)
+ { }
+
+ const QDBusConnectionPrivate *conn;
+ QPointer<QObject> object;
+ QDBusMessage message;
+ QList<int> metaTypes;
+
+ int flags;
+ int slotIdx;
+};
+
+static dbus_bool_t qDBusAddTimeout(DBusTimeout *timeout, void *data)
+{
+ Q_ASSERT(timeout);
+ Q_ASSERT(data);
+
+ // qDebug("addTimeout %d", dbus_timeout_get_interval(timeout));
+
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+
+ if (!dbus_timeout_get_enabled(timeout))
+ return true;
+
+ if (!QCoreApplication::instance()) {
+ d->pendingTimeouts.append(timeout);
+ return true;
+ }
+ int timerId = d->startTimer(dbus_timeout_get_interval(timeout));
+ if (!timerId)
+ return false;
+
+ d->timeouts[timerId] = timeout;
+ return true;
+}
+
+static void qDBusRemoveTimeout(DBusTimeout *timeout, void *data)
+{
+ Q_ASSERT(timeout);
+ Q_ASSERT(data);
+
+ // qDebug("removeTimeout");
+
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+ d->pendingTimeouts.removeAll(timeout);
+
+ QDBusConnectionPrivate::TimeoutHash::iterator it = d->timeouts.begin();
+ while (it != d->timeouts.end()) {
+ if (it.value() == timeout) {
+ d->killTimer(it.key());
+ it = d->timeouts.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+static void qDBusToggleTimeout(DBusTimeout *timeout, void *data)
+{
+ Q_ASSERT(timeout);
+ Q_ASSERT(data);
+
+ //qDebug("ToggleTimeout");
+
+ qDBusRemoveTimeout(timeout, data);
+ qDBusAddTimeout(timeout, data);
+}
+
+static dbus_bool_t qDBusAddWatch(DBusWatch *watch, void *data)
+{
+ Q_ASSERT(watch);
+ Q_ASSERT(data);
+
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+
+ int flags = dbus_watch_get_flags(watch);
+ int fd = dbus_watch_get_fd(watch);
+
+ QDBusConnectionPrivate::Watcher watcher;
+ if (flags & DBUS_WATCH_READABLE) {
+ //qDebug("addReadWatch %d", fd);
+ watcher.watch = watch;
+ if (QCoreApplication::instance()) {
+ watcher.read = new QSocketNotifier(fd, QSocketNotifier::Read, d);
+ watcher.read->setEnabled(dbus_watch_get_enabled(watch));
+ d->connect(watcher.read, SIGNAL(activated(int)), SLOT(socketRead(int)));
+ }
+ }
+ if (flags & DBUS_WATCH_WRITABLE) {
+ //qDebug("addWriteWatch %d", fd);
+ watcher.watch = watch;
+ if (QCoreApplication::instance()) {
+ watcher.write = new QSocketNotifier(fd, QSocketNotifier::Write, d);
+ watcher.write->setEnabled(dbus_watch_get_enabled(watch));
+ d->connect(watcher.write, SIGNAL(activated(int)), SLOT(socketWrite(int)));
+ }
+ }
+ d->watchers.insertMulti(fd, watcher);
+
+ return true;
+}
+
+static void qDBusRemoveWatch(DBusWatch *watch, void *data)
+{
+ Q_ASSERT(watch);
+ Q_ASSERT(data);
+
+ //qDebug("remove watch");
+
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+ int fd = dbus_watch_get_fd(watch);
+
+ QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd);
+ while (i != d->watchers.end() && i.key() == fd) {
+ if (i.value().watch == watch) {
+ delete i.value().read;
+ delete i.value().write;
+ d->watchers.erase(i);
+ return;
+ }
+ ++i;
+ }
+}
+
+static void qDBusToggleWatch(DBusWatch *watch, void *data)
+{
+ Q_ASSERT(watch);
+ Q_ASSERT(data);
+
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+ int fd = dbus_watch_get_fd(watch);
+
+ QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd);
+ while (i != d->watchers.end() && i.key() == fd) {
+ if (i.value().watch == watch) {
+ bool enabled = dbus_watch_get_enabled(watch);
+ int flags = dbus_watch_get_flags(watch);
+
+ //qDebug("toggle watch %d to %d (write: %d, read: %d)", dbus_watch_get_fd(watch), enabled, flags & DBUS_WATCH_WRITABLE, flags & DBUS_WATCH_READABLE);
+
+ if (flags & DBUS_WATCH_READABLE && i.value().read)
+ i.value().read->setEnabled(enabled);
+ if (flags & DBUS_WATCH_WRITABLE && i.value().write)
+ i.value().write->setEnabled(enabled);
+ return;
+ }
+ ++i;
+ }
+}
+
+static void qDBusNewConnection(DBusServer *server, DBusConnection *c, void *data)
+{
+ Q_ASSERT(data); Q_ASSERT(server); Q_ASSERT(c);
+ Q_UNUSED(data); Q_UNUSED(server); Q_UNUSED(c);
+
+ qDebug("SERVER: GOT A NEW CONNECTION"); // TODO
+}
+
+extern QDBUS_EXPORT void qDBusAddSpyHook(QDBusSpyHook);
+void qDBusAddSpyHook(QDBusSpyHook hook)
+{
+ qDBusSpyHookList()->append(hook);
+}
+
+#if USE_OUTSIDE_DISPATCH
+# define HANDLED DBUS_HANDLER_RESULT_HANDLED_OUTSIDE_DISPATCH
+static DBusHandlerResult qDBusSignalFilterOutside(DBusConnection *connection,
+ DBusMessage *message, void *data)
+{
+ Q_ASSERT(data);
+ Q_UNUSED(connection);
+ Q_UNUSED(message);
+
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+ if (d->mode == QDBusConnectionPrivate::InvalidMode)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; // internal error, actually
+
+ CallDeliveryEvent *e = d->postedCallDeliveryEvent();
+
+ d->deliverCall(*e);
+ delete e;
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+#else
+# define HANDLED DBUS_HANDLER_RESULT_HANDLED
+#endif
+
+extern "C" {
+static DBusHandlerResult
+qDBusSignalFilter(DBusConnection *connection, DBusMessage *message, void *data)
+{
+ return QDBusConnectionPrivate::messageFilter(connection, message, data);
+}
+}
+
+DBusHandlerResult QDBusConnectionPrivate::messageFilter(DBusConnection *connection,
+ DBusMessage *message, void *data)
+{
+ Q_ASSERT(data);
+ Q_UNUSED(connection);
+
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+ if (d->mode == QDBusConnectionPrivate::InvalidMode)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ QDBusMessage amsg = QDBusMessage::fromDBusMessage(message, QDBusConnection(d->name));
+ qDebug() << "got message:" << amsg;
+
+ const QDBusSpyHookList *list = qDBusSpyHookList();
+ for (int i = 0; i < list->size(); ++i) {
+ qDebug() << "calling the message spy hook";
+ (*(*list)[i])(amsg);
+ }
+
+ bool handled = false;
+ int msgType = dbus_message_get_type(message);
+ if (msgType == DBUS_MESSAGE_TYPE_SIGNAL) {
+ handled = d->handleSignal(amsg);
+ } else if (msgType == DBUS_MESSAGE_TYPE_METHOD_CALL) {
+ handled = d->handleObjectCall(amsg);
+ }
+
+ return handled ? HANDLED :
+ DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void huntAndDestroy(QObject *needle, QDBusConnectionPrivate::ObjectTreeNode *haystack)
+{
+ foreach (const QDBusConnectionPrivate::ObjectTreeNode::Data &entry, haystack->children)
+ huntAndDestroy(needle, entry.node);
+
+ if (needle == haystack->obj) {
+ haystack->obj = 0;
+ haystack->flags = 0;
+ }
+}
+
+static void huntAndEmit(DBusConnection *connection, DBusMessage *msg,
+ QObject *needle, QDBusConnectionPrivate::ObjectTreeNode *haystack,
+ const QString &path = QString())
+{
+ foreach (const QDBusConnectionPrivate::ObjectTreeNode::Data &entry, haystack->children)
+ huntAndEmit(connection, msg, needle, entry.node, path + QLatin1String("/") + entry.name);
+
+ if (needle == haystack->obj && haystack->flags & QDBusConnection::ExportAdaptors) {
+ QByteArray p = path.toLatin1();
+ if (p.isEmpty())
+ p = "/";
+ //qDebug() << p;
+ DBusMessage *msg2 = dbus_message_copy(msg);
+ dbus_message_set_path(msg2, p);
+ dbus_connection_send(connection, msg2, 0);
+ dbus_message_unref(msg2);
+ }
+}
+
+static bool typesMatch(int metaId, int variantType)
+{
+ if (metaId == int(variantType))
+ return true;
+
+ if (variantType == QVariant::Int && metaId == QMetaType::Short)
+ return true;
+
+ if (variantType == QVariant::UInt && (metaId == QMetaType::UShort ||
+ metaId == QMetaType::UChar))
+ return true;
+
+ if (variantType == QVariant::List) {
+ if (metaId == QDBusTypeHelper<bool>::listId() ||
+ metaId == QDBusTypeHelper<short>::listId() ||
+ metaId == QDBusTypeHelper<ushort>::listId() ||
+ metaId == QDBusTypeHelper<int>::listId() ||
+ metaId == QDBusTypeHelper<uint>::listId() ||
+ metaId == QDBusTypeHelper<qlonglong>::listId() ||
+ metaId == QDBusTypeHelper<qulonglong>::listId() ||
+ metaId == QDBusTypeHelper<double>::listId())
+ return true;
+ }
+
+ return false; // no match
+}
+
+static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags,
+ const QDBusTypeList &types, QList<int>& metaTypes)
+{
+ // find the first slot
+ const QMetaObject *super = mo;
+ while (super != &QObject::staticMetaObject &&
+ super != &QDBusAbstractAdaptor::staticMetaObject)
+ super = super->superClass();
+
+ int attributeMask = (flags & QDBusConnection::ExportAllSlots) ?
+ 0 : QMetaMethod::Scriptable;
+
+ for (int idx = super->methodCount() ; idx <= mo->methodCount(); ++idx) {
+ QMetaMethod mm = mo->method(idx);
+
+ // check access:
+ if (mm.access() != QMetaMethod::Public)
+ continue;
+
+ // check type:
+ // unnecessary, since slots are never public:
+ //if (mm.methodType() != QMetaMethod::Slot)
+ // continue;
+
+ // check name:
+ QByteArray sig = QMetaObject::normalizedSignature(mm.signature());
+ int paren = sig.indexOf('(');
+ if (paren != name.length() || !sig.startsWith( name ))
+ continue;
+
+ int returnType = qDBusNameToTypeId(mm.typeName());
+ bool isAsync = qDBusCheckAsyncTag(mm.tag());
+
+ // consistency check:
+ if (isAsync && returnType != QMetaType::Void)
+ continue;
+
+ int inputCount = qDBusParametersForMethod(mm, metaTypes);
+ if (inputCount == -1)
+ continue; // problem parsing
+
+ metaTypes[0] = returnType;
+ bool hasMessage = false;
+ if (inputCount > 0 &&
+ metaTypes.at(inputCount) == QDBusConnectionPrivate::messageMetaType) {
+ // "no input parameters" is allowed as long as the message meta type is there
+ hasMessage = true;
+ --inputCount;
+ }
+
+ // try to match the parameters
+ if (inputCount != types.count())
+ continue; // not enough parameters
+
+ bool matches = true;
+ int i;
+ for (i = 0; i < types.count(); ++i)
+ if ( !typesMatch(metaTypes.at(i + 1), types.at(i).qvariantType()) ) {
+ matches = false;
+ break;
+ }
+
+ if (!matches)
+ continue; // we didn't match them all
+
+ // consistency check:
+ if (isAsync && metaTypes.count() > i + 1)
+ continue;
+
+ if (hasMessage && (mm.attributes() & attributeMask) != attributeMask)
+ continue; // not exported
+
+ // if we got here, this slot matched
+ return idx;
+ }
+
+ // no slot matched
+ return -1;
+}
+
+static CallDeliveryEvent* prepareReply(QObject *object, int idx, const QList<int> &metaTypes,
+ const QDBusMessage &msg)
+{
+ Q_ASSERT(object);
+
+ int n = metaTypes.count() - 1;
+ if (metaTypes[n] == QDBusConnectionPrivate::messageMetaType)
+ --n;
+
+ // check that types match
+ for (int i = 0; i < n; ++i)
+ if (!typesMatch(metaTypes.at(i + 1), msg.at(i).type()))
+ return 0; // no match
+
+ // we can deliver
+ // prepare for the call
+ CallDeliveryEvent *data = new CallDeliveryEvent;
+ data->object = object;
+ data->flags = 0;
+ data->message = msg;
+ data->metaTypes = metaTypes;
+ data->slotIdx = idx;
+
+ return data;
+}
+
+bool QDBusConnectionPrivate::activateSignal(const QDBusConnectionPrivate::SignalHook& hook,
+ const QDBusMessage &msg)
+{
+ // This is called by QDBusConnectionPrivate::handleSignal to deliver a signal
+ // that was received from D-Bus
+ //
+ // Signals are delivered to slots if the parameters match
+ // Slots can have less parameters than there are on the message
+ // Slots can optionally have one final parameter that is a QDBusMessage
+ // Slots receive read-only copies of the message (i.e., pass by value or by const-ref)
+ CallDeliveryEvent *call = prepareReply(hook.obj, hook.midx, hook.params, msg);
+ if (call) {
+ postCallDeliveryEvent(call);
+ return true;
+ }
+ return false;
+}
+
+bool QDBusConnectionPrivate::activateCall(QObject* object, int flags,
+ const QDBusMessage &msg)
+{
+ // This is called by QDBusConnectionPrivate::handleObjectCall to place a call
+ // to a slot on the object.
+ //
+ // The call is delivered to the first slot that matches the following conditions:
+ // - has the same name as the message's target name
+ // - ALL of the message's types are found in slot's parameter list
+ // - optionally has one more parameter of type QDBusMessage
+ // If none match, then the slot of the same name as the message target and with
+ // the first type of QDBusMessage is delivered.
+ //
+ // Because the marshalling of D-Bus data into QVariant loses the information on
+ // the original types, the message signature is used to determine the original type.
+ // Aside from that, the "int" and "unsigned" types will be tried as well.
+ //
+ // The D-Bus specification requires that all MethodCall messages be replied to, unless the
+ // caller specifically waived this requirement. This means that we inspect if the user slot
+ // generated a reply and, if it didn't, we will. Obviously, if the user slot doesn't take a
+ // QDBusMessage parameter, it cannot generate a reply.
+ //
+ // When a return message is generated, the slot's return type, if any, will be placed
+ // in the message's first position. If there are non-const reference parameters to the
+ // slot, they must appear at the end and will be placed in the subsequent message
+ // positions.
+
+ if (!object)
+ return false;
+
+ QList<int> metaTypes;
+ int idx;
+
+ {
+ const QMetaObject *mo = object->metaObject();
+ QDBusTypeList typeList(msg.signature().toUtf8());
+ QByteArray name = msg.name().toUtf8();
+
+ // find a slot that matches according to the rules above
+ idx = ::findSlot(mo, name, flags, typeList, metaTypes);
+ if (idx == -1) {
+ // try with no parameters, but with a QDBusMessage
+ idx = ::findSlot(mo, name, flags, QDBusTypeList(), metaTypes);
+ if (metaTypes.count() != 2 || metaTypes.at(1) != messageMetaType)
+ return false;
+ }
+ }
+
+ // found the slot to be called
+ // prepare for the call:
+ CallDeliveryEvent *call = new CallDeliveryEvent;
+
+ // parameters:
+ call->object = object;
+ call->flags = flags;
+ call->message = msg;
+
+ // save our state:
+ call->metaTypes = metaTypes;
+ call->slotIdx = idx;
+
+ postCallDeliveryEvent(call);
+
+ // ready
+ return true;
+}
+
+void QDBusConnectionPrivate::postCallDeliveryEvent(CallDeliveryEvent *data)
+{
+ Q_ASSERT(data);
+ data->conn = this;
+#if USE_OUTSIDE_DISPATCH
+ callDeliveryMutex.lock();
+ callDeliveryState = data;
+#else
+ QCoreApplication::postEvent( this, data );
+#endif
+}
+
+CallDeliveryEvent *QDBusConnectionPrivate::postedCallDeliveryEvent()
+{
+ CallDeliveryEvent *e = callDeliveryState;
+ Q_ASSERT(e && e->conn == this);
+
+ // release it:
+ callDeliveryState = 0;
+ callDeliveryMutex.unlock();
+
+ return e;
+}
+
+void QDBusConnectionPrivate::deliverCall(const CallDeliveryEvent& data) const
+{
+ // resume state:
+ const QList<int>& metaTypes = data.metaTypes;
+ const QDBusMessage& msg = data.message;
+
+ QVarLengthArray<void *, 10> params;
+ params.reserve(metaTypes.count());
+
+ QVariantList auxParameters;
+ // let's create the parameter list
+
+ // first one is the return type -- add it below
+ params.append(0);
+
+ // add the input parameters
+ int i;
+ for (i = 1; i <= msg.count(); ++i) {
+ int id = metaTypes[i];
+ if (id == QDBusConnectionPrivate::messageMetaType)
+ break;
+
+ if (id == int(msg.at(i - 1).userType()))
+ // no conversion needed
+ params.append(const_cast<void *>( msg.at(i - 1).constData() ));
+ else {
+ // convert to what the function expects
+ auxParameters.append(QVariant());
+
+ const QVariant &in = msg.at(i - 1);
+ QVariant &out = auxParameters[auxParameters.count() - 1];
+
+ bool error = false;
+ if (id == QVariant::List) {
+ int mid = in.userType();
+ // the only conversion possible here is from a specialised QList<T> to QVariantList
+ if (mid == QDBusTypeHelper<bool>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<bool>::toVariantList(in));
+ else if (mid == QDBusTypeHelper<short>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<short>::toVariantList(in));
+ else if (mid == QDBusTypeHelper<ushort>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<ushort>::toVariantList(in));
+ else if (mid == QDBusTypeHelper<int>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<int>::toVariantList(in));
+ else if (mid == QDBusTypeHelper<uint>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<uint>::toVariantList(in));
+ else if (mid == QDBusTypeHelper<qlonglong>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<qlonglong>::toVariantList(in));
+ else if (mid == QDBusTypeHelper<qulonglong>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<qulonglong>::toVariantList(in));
+ else if (mid == QDBusTypeHelper<double>::listId())
+ out = qVariantFromValue(QDBusTypeHelper<double>::toVariantList(in));
+ else
+ error = true;
+ } else if (in.type() == QVariant::UInt) {
+ if (id == QMetaType::UChar) {
+ uchar uc = in.toUInt();
+ out = qVariantFromValue(uc);
+ } else if (id == QMetaType::UShort) {
+ ushort us = in.toUInt();
+ out = qVariantFromValue(us);
+ } else {
+ error = true;
+ }
+ } else if (in.type() == QVariant::Int) {
+ if (id == QMetaType::Short) {
+ short s = in.toInt();
+ out = qVariantFromValue(s);
+ } else {
+ error = true;
+ }
+ } else {
+ error = true;
+ }
+
+ if (error)
+ qFatal("Internal error: got invalid meta type %d when trying to convert to meta type %d",
+ in.userType(), id);
+
+ params.append( const_cast<void *>(out.constData()) );
+ }
+ }
+
+ bool takesMessage = false;
+ if (metaTypes.count() > i && metaTypes[i] == QDBusConnectionPrivate::messageMetaType) {
+ params.append(const_cast<void*>(static_cast<const void*>(&msg)));
+ takesMessage = true;
+ ++i;
+ }
+
+ // output arguments
+ QVariantList outputArgs;
+ void *null = 0;
+ if (metaTypes[0] != QMetaType::Void) {
+ QVariant arg(metaTypes[0], null);
+ outputArgs.append( arg );
+ params[0] = const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData());
+ }
+ for ( ; i < metaTypes.count(); ++i) {
+ QVariant arg(metaTypes[i], null);
+ outputArgs.append( arg );
+ params.append( const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData()) );
+ }
+
+ // make call:
+ bool fail;
+ if (data.object.isNull())
+ fail = true;
+ else
+ fail = data.object->qt_metacall(QMetaObject::InvokeMetaMethod,
+ data.slotIdx, params.data()) >= 0;
+
+ // do we create a reply? Only if the caller is waiting for a reply and one hasn't been sent
+ // yet.
+ if (!msg.noReply() && !msg.wasRepliedTo()) {
+ if (!fail) {
+ // normal reply
+ QDBusMessage reply = QDBusMessage::methodReply(msg);
+ reply += outputArgs;
+
+ qDebug() << "Automatically sending reply:" << reply;
+ send(reply);
+ }
+ else {
+ // generate internal error
+ QDBusMessage reply = QDBusMessage::error(msg, QDBusError(QDBusError::InternalError,
+ QLatin1String("Failed to deliver message")));
+ qWarning("Internal error: Failed to deliver message");
+ send(reply);
+ }
+ }
+
+ return;
+}
+
+void QDBusConnectionPrivate::customEvent(QEvent *event)
+{
+ // nothing else should be sending custom events at us
+ CallDeliveryEvent* call = static_cast<CallDeliveryEvent *>(event);
+
+ // self check:
+ Q_ASSERT(call->conn == this);
+
+ deliverCall(*call);
+}
+
+QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *parent)
+ : QObject(parent), ref(1), mode(InvalidMode), connection(0), server(0), busService(0)
+{
+ extern bool qDBusInitThreads();
+ static const int msgType = registerMessageMetaType();
+ static const bool threads = qDBusInitThreads();
+ static const bool metatypes = QDBusMetaTypeId::innerInitialize();
+
+ Q_UNUSED(msgType);
+ Q_UNUSED(threads);
+ Q_UNUSED(metatypes);
+
+ dbus_error_init(&error);
+
+ rootNode.flags = 0;
+}
+
+QDBusConnectionPrivate::~QDBusConnectionPrivate()
+{
+ if (dbus_error_is_set(&error))
+ dbus_error_free(&error);
+
+ closeConnection();
+ rootNode.clear(); // free resources
+ qDeleteAll(cachedMetaObjects);
+}
+
+void QDBusConnectionPrivate::closeConnection()
+{
+ QWriteLocker locker(&lock);
+ ConnectionMode oldMode = mode;
+ mode = InvalidMode; // prevent reentrancy
+ if (oldMode == ServerMode) {
+ if (server) {
+ dbus_server_disconnect(server);
+ dbus_server_unref(server);
+ server = 0;
+ }
+ } else if (oldMode == ClientMode) {
+ if (connection) {
+ dbus_connection_close(connection);
+ // send the "close" message
+ while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS)
+ ;
+ dbus_connection_unref(connection);
+ connection = 0;
+ }
+ }
+}
+
+bool QDBusConnectionPrivate::handleError()
+{
+ lastError = QDBusError(&error);
+ if (dbus_error_is_set(&error))
+ dbus_error_free(&error);
+ return lastError.isValid();
+}
+
+void QDBusConnectionPrivate::bindToApplication()
+{
+ // Yay, now that we have an application we are in business
+ Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection",
+ "qDBusBindToApplication called without an application");
+ moveToThread(QCoreApplication::instance()->thread());
+
+ // Re-add all watchers
+ WatcherHash oldWatchers = watchers;
+ watchers.clear();
+ QHashIterator<int, QDBusConnectionPrivate::Watcher> it(oldWatchers);
+ while (it.hasNext()) {
+ it.next();
+ if (!it.value().read && !it.value().write) {
+ qDBusAddWatch(it.value().watch, this);
+ } else {
+ watchers.insertMulti(it.key(), it.value());
+ }
+ }
+
+ // Re-add all timeouts
+ while (!pendingTimeouts.isEmpty())
+ qDBusAddTimeout(pendingTimeouts.takeFirst(), this);
+}
+
+void QDBusConnectionPrivate::timerEvent(QTimerEvent *e)
+{
+ DBusTimeout *timeout = timeouts.value(e->timerId(), 0);
+ dbus_timeout_handle(timeout);
+}
+
+void QDBusConnectionPrivate::doDispatch()
+{
+ if (mode == ClientMode)
+ while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS);
+}
+
+void QDBusConnectionPrivate::socketRead(int fd)
+{
+ QHashIterator<int, QDBusConnectionPrivate::Watcher> it(watchers);
+ while (it.hasNext()) {
+ it.next();
+ if (it.key() == fd && it.value().read && it.value().read->isEnabled()) {
+ if (!dbus_watch_handle(it.value().watch, DBUS_WATCH_READABLE))
+ qDebug("OUT OF MEM");
+ }
+ }
+
+ doDispatch();
+}
+
+void QDBusConnectionPrivate::socketWrite(int fd)
+{
+ QHashIterator<int, QDBusConnectionPrivate::Watcher> it(watchers);
+ while (it.hasNext()) {
+ it.next();
+ if (it.key() == fd && it.value().write && it.value().write->isEnabled()) {
+ if (!dbus_watch_handle(it.value().watch, DBUS_WATCH_WRITABLE))
+ qDebug("OUT OF MEM");
+ }
+ }
+}
+
+void QDBusConnectionPrivate::objectDestroyed(QObject *obj)
+{
+ QWriteLocker locker(&lock);
+ huntAndDestroy(obj, &rootNode);
+
+ SignalHookHash::iterator sit = signalHooks.begin();
+ while (sit != signalHooks.end()) {
+ if (static_cast<QObject *>(sit.value().obj) == obj)
+ sit = signalHooks.erase(sit);
+ else
+ ++sit;
+ }
+
+ obj->disconnect(this);
+}
+
+void QDBusConnectionPrivate::relaySignal(QObject *obj, const char *interface, const char *name,
+ const QVariantList &args)
+{
+ QReadLocker locker(&lock);
+ QDBusMessage message = QDBusMessage::signal(QLatin1String("/"), QLatin1String(interface),
+ QLatin1String(name));
+ message += args;
+ DBusMessage *msg = message.toDBusMessage();
+ if (!msg) {
+ qWarning("Could not emit signal %s.%s", interface, name);
+ return;
+ }
+
+ //qDebug() << "Emitting signal" << message;
+ //qDebug() << "for paths:";
+ dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything
+ huntAndEmit(connection, msg, obj, &rootNode);
+ dbus_message_unref(msg);
+}
+
+int QDBusConnectionPrivate::registerMessageMetaType()
+{
+ int tp = messageMetaType = qRegisterMetaType<QDBusMessage>("QDBusMessage");
+ return tp;
+}
+
+int QDBusConnectionPrivate::findSlot(QObject* obj, const QByteArray &normalizedName,
+ QList<int> &params)
+{
+ int midx = obj->metaObject()->indexOfMethod(normalizedName);
+ if (midx == -1) {
+ qWarning("No such slot '%s' while connecting D-Bus", normalizedName.constData());
+ return -1;
+ }
+
+ int inputCount = qDBusParametersForMethod(obj->metaObject()->method(midx), params);
+ if ( inputCount == -1 || inputCount + 1 != params.count() )
+ return -1; // failed to parse or invalid arguments or output arguments
+
+ return midx;
+}
+
+bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
+ const QString &service, const QString &path,
+ const QString &interface, const QString &name,
+ QObject *receiver, const char *signal, int minMIdx,
+ bool buildSignature)
+{
+ QByteArray normalizedName = QMetaObject::normalizedSignature(signal + 1);
+ hook.midx = findSlot(receiver, normalizedName, hook.params);
+ if (hook.midx < minMIdx)
+ return false;
+
+ hook.sender = service;
+ hook.path = path;
+ hook.obj = receiver;
+
+ // build the D-Bus signal name and signature
+ QString mname = name;
+ if (mname.isEmpty()) {
+ normalizedName.truncate(normalizedName.indexOf('('));
+ mname = QString::fromUtf8(normalizedName);
+ }
+ key = mname;
+ key.reserve(interface.length() + 1 + mname.length());
+ key += ':';
+ key += interface;
+
+ if (buildSignature) {
+ hook.signature.clear();
+ for (int i = 1; i < hook.params.count(); ++i)
+ if (hook.params.at(i) != messageMetaType)
+ hook.signature += QLatin1String( QDBusType::dbusSignature( QVariant::Type(hook.params.at(i)) ) );
+ }
+
+ return true; // connect to this signal
+}
+
+bool QDBusConnectionPrivate::activateInternalFilters(const ObjectTreeNode *node, const QDBusMessage &msg)
+{
+ // object may be null
+
+ if (msg.interface().isEmpty() || msg.interface() == QLatin1String(DBUS_INTERFACE_INTROSPECTABLE)) {
+ if (msg.method() == QLatin1String("Introspect") && msg.signature().isEmpty())
+ qDBusIntrospectObject(node, msg);
+ if (msg.interface() == QLatin1String(DBUS_INTERFACE_INTROSPECTABLE))
+ return true;
+ }
+
+ if (node->obj && (msg.interface().isEmpty() ||
+ msg.interface() == QLatin1String(DBUS_INTERFACE_PROPERTIES))) {
+ if (msg.method() == QLatin1String("Get") && msg.signature() == QLatin1String("ss"))
+ qDBusPropertyGet(node, msg);
+ else if (msg.method() == QLatin1String("Set") && msg.signature() == QLatin1String("ssv"))
+ qDBusPropertySet(node, msg);
+
+ if (msg.interface() == QLatin1String(DBUS_INTERFACE_PROPERTIES))
+ return true;
+ }
+
+ return false;
+}
+
+bool QDBusConnectionPrivate::activateObject(const ObjectTreeNode *node, const QDBusMessage &msg)
+{
+ // This is called by QDBusConnectionPrivate::handleObjectCall to place a call to a slot
+ // on the object.
+ //
+ // The call is routed through the adaptor sub-objects if we have any
+
+ // object may be null
+
+ QDBusAdaptorConnector *connector;
+ if (node->flags & QDBusConnection::ExportAdaptors &&
+ (connector = qDBusFindAdaptorConnector(node->obj))) {
+ int newflags = node->flags | QDBusConnection::ExportAllSlots;
+
+ if (msg.interface().isEmpty()) {
+ // place the call in all interfaces
+ // let the first one that handles it to work
+ foreach (const QDBusAdaptorConnector::AdaptorData &entry, connector->adaptors)
+ if (activateCall(entry.adaptor, newflags, msg))
+ return true;
+ } else {
+ // check if we have an interface matching the name that was asked:
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
+ it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
+ msg.interface());
+ if (it != connector->adaptors.end() && it->interface == msg.interface())
+ if (activateCall(it->adaptor, newflags, msg))
+ return true;
+ }
+ }
+
+ // no adaptors matched
+ // try our standard filters
+ if (activateInternalFilters(node, msg))
+ return true;
+
+ // try the object itself:
+ if (node->flags & QDBusConnection::ExportSlots && activateCall(node->obj, node->flags, msg))
+ return true;
+#if 0
+ // nothing matched
+ qDebug("Call failed: no match for %s%s%s at %s",
+ qPrintable(msg.interface()), msg.interface().isEmpty() ? "" : ".",
+ qPrintable(msg.name()),
+ qPrintable(msg.path()));
+#endif
+ return false;
+}
+
+template<typename Func>
+static bool applyForObject(QDBusConnectionPrivate::ObjectTreeNode *root, const QString &fullpath,
+ Func& functor)
+{
+ // walk the object tree
+ QStringList path = fullpath.split(QLatin1Char('/'));
+ if (path.last().isEmpty())
+ path.removeLast(); // happens if path is "/"
+ int i = 1;
+ QDBusConnectionPrivate::ObjectTreeNode *node = root;
+
+ // try our own tree first
+ while (node && !(node->flags & QDBusConnection::ExportChildObjects) ) {
+ if (i == path.count()) {
+ // found our object
+ functor(node);
+ return true;
+ }
+
+ QVector<QDBusConnectionPrivate::ObjectTreeNode::Data>::ConstIterator it =
+ qLowerBound(node->children.constBegin(), node->children.constEnd(), path.at(i));
+ if (it != node->children.constEnd() && it->name == path.at(i))
+ // match
+ node = it->node;
+ else
+ node = 0;
+
+ ++i;
+ }
+
+ // any object in the tree can tell us to switch to its own object tree:
+ if (node && node->flags & QDBusConnection::ExportChildObjects) {
+ QObject *obj = node->obj;
+
+ while (obj) {
+ if (i == path.count()) {
+ // we're at the correct level
+ QDBusConnectionPrivate::ObjectTreeNode fakenode(*node);
+ fakenode.obj = obj;
+ functor(&fakenode);
+ return true;
+ }
+
+ const QObjectList children = obj->children();
+
+ // find a child with the proper name
+ QObject *next = 0;
+ foreach (QObject *child, children)
+ if (child->objectName() == path.at(i)) {
+ next = child;
+ break;
+ }
+
+ if (!next)
+ break;
+
+ ++i;
+ obj = next;
+ }
+ }
+
+ // object not found
+ return false;
+}
+
+struct qdbus_activateObject
+{
+ QDBusConnectionPrivate *self;
+ const QDBusMessage &msg;
+ bool returnVal;
+ inline qdbus_activateObject(QDBusConnectionPrivate *s, const QDBusMessage &m)
+ : self(s), msg(m)
+ { }
+
+ inline void operator()(QDBusConnectionPrivate::ObjectTreeNode *node)
+ { returnVal = self->activateObject(node, msg); }
+};
+
+bool QDBusConnectionPrivate::handleObjectCall(const QDBusMessage &msg)
+{
+ QReadLocker locker(&lock);
+
+ qdbus_activateObject apply(this, msg);
+ if (applyForObject(&rootNode, msg.path(), apply))
+ return apply.returnVal;
+
+ qDebug("Call failed: no object found at %s", qPrintable(msg.path()));
+ return false;
+}
+
+bool QDBusConnectionPrivate::handleSignal(const QString &key, const QDBusMessage& msg)
+{
+ bool result = false;
+ SignalHookHash::const_iterator it = signalHooks.find(key);
+ //qDebug("looking for: %s", path.toLocal8Bit().constData());
+ //qDebug() << signalHooks.keys();
+ for ( ; it != signalHooks.constEnd() && it.key() == key; ++it) {
+ const SignalHook &hook = it.value();
+ if ( !hook.sender.isEmpty() && hook.sender != msg.sender() )
+ continue;
+ if ( !hook.path.isEmpty() && hook.path != msg.path() )
+ continue;
+ if ( !hook.signature.isEmpty() && hook.signature != msg.signature() )
+ continue;
+ if ( hook.signature.isEmpty() && !hook.signature.isNull() && !msg.signature().isEmpty())
+ continue;
+
+ // yes, |=
+ result |= activateSignal(hook, msg);
+ }
+ return result;
+}
+
+bool QDBusConnectionPrivate::handleSignal(const QDBusMessage& msg)
+{
+ QString key = msg.member();
+ key.reserve(key.length() + 1 + msg.interface().length());
+ key += ':';
+ key += msg.interface();
+
+ QReadLocker locker(&lock);
+ bool result = handleSignal(key, msg); // one try
+
+ key.truncate(msg.member().length() + 1); // keep the ':'
+ result |= handleSignal(key, msg); // second try
+ return result;
+}
+
+static dbus_int32_t server_slot = -1;
+
+void QDBusConnectionPrivate::setServer(DBusServer *s)
+{
+ if (!server) {
+ handleError();
+ return;
+ }
+
+ server = s;
+ mode = ServerMode;
+
+ dbus_server_allocate_data_slot(&server_slot);
+ if (server_slot < 0)
+ return;
+
+ dbus_server_set_watch_functions(server, qDBusAddWatch, qDBusRemoveWatch,
+ qDBusToggleWatch, this, 0); // ### check return type?
+ dbus_server_set_timeout_functions(server, qDBusAddTimeout, qDBusRemoveTimeout,
+ qDBusToggleTimeout, this, 0);
+ dbus_server_set_new_connection_function(server, qDBusNewConnection, this, 0);
+
+ dbus_server_set_data(server, server_slot, this, 0);
+}
+
+void QDBusConnectionPrivate::setConnection(DBusConnection *dbc)
+{
+ if (!dbc) {
+ handleError();
+ return;
+ }
+
+ connection = dbc;
+ mode = ClientMode;
+
+ dbus_connection_set_exit_on_disconnect(connection, false);
+ dbus_connection_set_watch_functions(connection, qDBusAddWatch, qDBusRemoveWatch,
+ qDBusToggleWatch, this, 0);
+ dbus_connection_set_timeout_functions(connection, qDBusAddTimeout, qDBusRemoveTimeout,
+ qDBusToggleTimeout, this, 0);
+// dbus_bus_add_match(connection, "type='signal',interface='com.trolltech.dbus.Signal'", &error);
+// dbus_bus_add_match(connection, "type='signal'", &error);
+
+ dbus_bus_add_match(connection, "type='signal'", &error);
+ if (handleError()) {
+ closeConnection();
+ return;
+ }
+
+ const char *service = dbus_bus_get_unique_name(connection);
+ if (service) {
+ QVarLengthArray<char, 56> filter;
+ filter.append("destination='", 13);
+ filter.append(service, qstrlen(service));
+ filter.append("\'\0", 2);
+
+ dbus_bus_add_match(connection, filter.constData(), &error);
+ if (handleError()) {
+ closeConnection();
+ return;
+ }
+ } else {
+ qWarning("QDBusConnectionPrivate::SetConnection: Unable to get base service");
+ }
+
+#if USE_OUTSIDE_DISPATCH
+ dbus_connection_add_filter_outside(connection, qDBusSignalFilter, qDBusSignalFilterOutside, this, 0);
+#else
+ dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0);
+#endif
+
+ //qDebug("base service: %s", service);
+
+ // schedule a dispatch:
+ QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
+}
+
+extern "C"{
+static void qDBusResultReceived(DBusPendingCall *pending, void *user_data)
+{
+ QDBusConnectionPrivate::messageResultReceived(pending, user_data);
+}
+}
+
+void QDBusConnectionPrivate::messageResultReceived(DBusPendingCall *pending, void *user_data)
+{
+ QDBusPendingCall *call = reinterpret_cast<QDBusPendingCall *>(user_data);
+ QDBusConnectionPrivate *connection = const_cast<QDBusConnectionPrivate *>(call->connection);
+ Q_ASSERT(call->pending == pending);
+
+ if (!call->receiver.isNull() && call->methodIdx != -1) {
+ DBusMessage *reply = dbus_pending_call_steal_reply(pending);
+
+ // Deliver the return values of a remote function call.
+ //
+ // There is only one connection and it is specified by idx
+ // The slot must have the same parameter types that the message does
+ // The slot may have less parameters than the message
+ // The slot may optionally have one final parameter that is QDBusMessage
+ // The slot receives read-only copies of the message (i.e., pass by value or by const-ref)
+
+ QDBusMessage msg = QDBusMessage::fromDBusMessage(reply, QDBusConnection(connection->name));
+ qDebug() << "got message: " << msg;
+ CallDeliveryEvent *e = prepareReply(call->receiver, call->methodIdx, call->metaTypes, msg);
+ if (e)
+ connection->postCallDeliveryEvent(e);
+ else
+ qDebug() << "Deliver failed!";
+ }
+ dbus_pending_call_unref(pending);
+ delete call;
+}
+
+int QDBusConnectionPrivate::send(const QDBusMessage& message) const
+{
+ DBusMessage *msg = message.toDBusMessage();
+ if (!msg)
+ return 0;
+
+ dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything
+
+ qDebug() << "sending message:" << message;
+ bool isOk = dbus_connection_send(connection, msg, 0);
+ int serial = 0;
+ if (isOk)
+ serial = dbus_message_get_serial(msg);
+
+ dbus_message_unref(msg);
+ return serial;
+}
+
+QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
+ int mode)
+{
+ if (!QCoreApplication::instance() || mode == QDBusConnection::NoUseEventLoop) {
+ DBusMessage *msg = message.toDBusMessage();
+ if (!msg)
+ return QDBusMessage();
+
+ qDebug() << "sending message:" << message;
+ DBusMessage *reply = dbus_connection_send_with_reply_and_block(connection, msg,
+ -1, &error);
+ handleError();
+ dbus_message_unref(msg);
+
+ if (lastError.isValid())
+ return QDBusMessage::fromError(lastError);
+
+ QDBusMessage amsg = QDBusMessage::fromDBusMessage(reply, QDBusConnection(name));
+ qDebug() << "got message:" << amsg;
+
+ if (dbus_connection_get_dispatch_status(connection) == DBUS_DISPATCH_DATA_REMAINS)
+ QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
+ return amsg;
+ } else { // use the event loop
+ QDBusReplyWaiter waiter;
+ if (sendWithReplyAsync(message, &waiter, SLOT(reply(const QDBusMessage&))) > 0) {
+ // enter the event loop and wait for a reply
+ waiter.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
+
+ lastError = waiter.replyMsg; // set or clear error
+ return waiter.replyMsg;
+ }
+
+ return QDBusMessage();
+ }
+}
+
+int QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
+ const char *method)
+{
+ if (!receiver || !method || !*method)
+ // would not be able to deliver a reply
+ return send(message);
+
+ int slotIdx = -1;
+ QList<int> metaTypes;
+ QByteArray normalizedName = QMetaObject::normalizedSignature(method + 1);
+ slotIdx = findSlot(receiver, normalizedName, metaTypes);
+ if (slotIdx == -1)
+ // would not be able to deliver a reply
+ return send(message);
+
+ DBusMessage *msg = message.toDBusMessage();
+ if (!msg)
+ return 0;
+
+ qDebug() << "sending message:" << message;
+ DBusPendingCall *pending = 0;
+ if (dbus_connection_send_with_reply(connection, msg, &pending, message.timeout())) {
+ if (slotIdx != -1) {
+ QDBusPendingCall *pcall = new QDBusPendingCall;
+ pcall->receiver = receiver;
+ pcall->metaTypes = metaTypes;
+ pcall->methodIdx = slotIdx;
+ pcall->connection = this;
+ pcall->pending = dbus_pending_call_ref(pending);
+ dbus_pending_call_set_notify(pending, qDBusResultReceived, pcall, 0);
+ }
+ dbus_pending_call_unref(pending);
+ return dbus_message_get_serial(msg);
+ }
+
+ return 0;
+}
+
+void QDBusConnectionPrivate::connectSignal(const QString &key, const SignalHook &hook)
+{
+ signalHooks.insertMulti(key, hook);
+ connect(hook.obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)));
+}
+
+void QDBusConnectionPrivate::registerObject(const ObjectTreeNode *node)
+{
+ connect(node->obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)));
+
+ if (node->flags & QDBusConnection::ExportAdaptors) {
+ QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(node->obj);
+
+ // disconnect and reconnect to avoid duplicates
+ connector->disconnect(SIGNAL(relaySignal(QObject*,const char*,const char*,QVariantList)),
+ this, SLOT(relaySignal(QObject*,const char*,const char*,QVariantList)));
+ connect(connector, SIGNAL(relaySignal(QObject*,const char*,const char*,QVariantList)),
+ SLOT(relaySignal(QObject*,const char*,const char*,QVariantList)));
+ }
+}
+
+void QDBusConnectionPrivate::connectRelay(const QString &service, const QString &path,
+ const QString &interface,
+ QDBusAbstractInterface *receiver,
+ const char *signal)
+{
+ // this function is called by QDBusAbstractInterface when one of its signals is connected
+ // we set up a relay from D-Bus into it
+ SignalHook hook;
+ QString key;
+ if (!prepareHook(hook, key, service, path, interface, QString(), receiver, signal,
+ QDBusAbstractInterface::staticMetaObject.methodCount(), true))
+ return; // don't connect
+
+ // add it to our list:
+ QWriteLocker locker(&lock);
+ SignalHookHash::ConstIterator it = signalHooks.find(key);
+ SignalHookHash::ConstIterator end = signalHooks.end();
+ for ( ; it != end && it.key() == key; ++it) {
+ const SignalHook &entry = it.value();
+ if (entry.sender == hook.sender &&
+ entry.path == hook.path &&
+ entry.signature == hook.signature &&
+ entry.obj == hook.obj &&
+ entry.midx == hook.midx)
+ return; // already there, no need to re-add
+ }
+
+ connectSignal(key, hook);
+}
+
+void QDBusConnectionPrivate::disconnectRelay(const QString &service, const QString &path,
+ const QString &interface,
+ QDBusAbstractInterface *receiver,
+ const char *signal)
+{
+ // this function is called by QDBusAbstractInterface when one of its signals is disconnected
+ // we remove relay from D-Bus into it
+ SignalHook hook;
+ QString key;
+ if (!prepareHook(hook, key, service, path, interface, QString(), receiver, signal,
+ QDBusAbstractInterface::staticMetaObject.methodCount(), true))
+ return; // don't connect
+
+ // remove it from our list:
+ QWriteLocker locker(&lock);
+ SignalHookHash::Iterator it = signalHooks.find(key);
+ SignalHookHash::Iterator end = signalHooks.end();
+ for ( ; it != end && it.key() == key; ++it) {
+ const SignalHook &entry = it.value();
+ if (entry.sender == hook.sender &&
+ entry.path == hook.path &&
+ entry.signature == hook.signature &&
+ entry.obj == hook.obj &&
+ entry.midx == hook.midx) {
+ // found it
+ signalHooks.erase(it);
+ return;
+ }
+ }
+
+ qWarning("QDBusConnectionPrivate::disconnectRelay called for a signal that was not found");
+}
+
+QString QDBusConnectionPrivate::getNameOwner(const QString& name)
+{
+ if (QDBusUtil::isValidUniqueConnectionName(name))
+ return name;
+ if (!connection || !QDBusUtil::isValidBusName(name))
+ return QString();
+
+ QDBusMessage msg = QDBusMessage::methodCall(QLatin1String(DBUS_SERVICE_DBUS),
+ QLatin1String(DBUS_PATH_DBUS), QLatin1String(DBUS_INTERFACE_DBUS),
+ QLatin1String("GetNameOwner"));
+ msg << name;
+ QDBusMessage reply = sendWithReply(msg, QDBusConnection::NoUseEventLoop);
+ if (!lastError.isValid() && reply.type() == QDBusMessage::ReplyMessage)
+ return reply.first().toString();
+ return QString();
+}
+
+QDBusInterfacePrivate *
+QDBusConnectionPrivate::findInterface(const QString &service,
+ const QString &path,
+ const QString &interface)
+{
+ // check if it's there first -- FIXME: add binding mode
+ QDBusMetaObject *mo = 0;
+ QString owner = getNameOwner(service);
+ if (connection && !owner.isEmpty() && QDBusUtil::isValidObjectPath(path) &&
+ (interface.isEmpty() || QDBusUtil::isValidInterfaceName(interface)))
+ // always call here with the unique connection name
+ mo = findMetaObject(owner, path, interface);
+
+ QDBusInterfacePrivate *p = new QDBusInterfacePrivate(QDBusConnection(name), this, owner, path, interface, mo);
+
+ if (!mo) {
+ // invalid object
+ p->isValid = false;
+ p->lastError = lastError;
+ if (!lastError.isValid()) {
+ // try to determine why we couldn't get the data
+ if (!connection)
+ p->lastError = QDBusError(QDBusError::Disconnected,
+ QLatin1String("Not connected to D-Bus server"));
+ else if (owner.isEmpty())
+ p->lastError = QDBusError(QDBusError::ServiceUnknown,
+ QString(QLatin1String("Service %1 is unknown")).arg(service));
+ else if (!QDBusUtil::isValidObjectPath(path))
+ p->lastError = QDBusError(QDBusError::InvalidArgs,
+ QString(QLatin1String("Object path %1 is invalid")).arg(path));
+ else if (!interface.isEmpty() && !QDBusUtil::isValidInterfaceName(interface))
+ p->lastError = QDBusError(QDBusError::InvalidArgs,
+ QString(QLatin1String("Interface %1 is invalid")).arg(interface));
+ else
+ p->lastError = QDBusError(QDBusError::Other, QLatin1String("Unknown error"));
+ }
+ }
+
+ return p;
+}
+
+struct qdbus_Introspect
+{
+ QString xml;
+ inline void operator()(QDBusConnectionPrivate::ObjectTreeNode *node)
+ { xml = qDBusIntrospectObject(node); }
+};
+
+QDBusMetaObject *
+QDBusConnectionPrivate::findMetaObject(const QString &service, const QString &path,
+ const QString &interface)
+{
+ // service must be a unique connection name
+ if (!interface.isEmpty()) {
+ QReadLocker locker(&lock);
+ QDBusMetaObject *mo = cachedMetaObjects.value(interface, 0);
+ if (mo)
+ return mo;
+ }
+ if (service == QString::fromUtf8(dbus_bus_get_unique_name(connection))) {
+ // it's one of our own
+ QWriteLocker locker(&lock);
+ QDBusMetaObject *mo = 0;
+ if (!interface.isEmpty())
+ mo = cachedMetaObjects.value(interface, 0);
+ if (mo)
+ // maybe it got created when we switched from read to write lock
+ return mo;
+
+ qdbus_Introspect apply;
+ if (!applyForObject(&rootNode, path, apply)) {
+ lastError = QDBusError(QDBusError::InvalidArgs,
+ QString(QLatin1String("No object at %1")).arg(path));
+ return 0; // no object at path
+ }
+
+ // release the lock and return
+ return QDBusMetaObject::createMetaObject(interface, apply.xml, cachedMetaObjects, lastError);
+ }
+
+ // not local: introspect the target object:
+ QDBusMessage msg = QDBusMessage::methodCall(service, path,
+ QLatin1String(DBUS_INTERFACE_INTROSPECTABLE),
+ QLatin1String("Introspect"));
+
+
+ QDBusMessage reply = sendWithReply(msg, QDBusConnection::NoUseEventLoop);
+
+ // it doesn't exist yet, we have to create it
+ QWriteLocker locker(&lock);
+ QDBusMetaObject *mo = 0;
+ if (!interface.isEmpty())
+ mo = cachedMetaObjects.value(interface, 0);
+ if (mo)
+ // maybe it got created when we switched from read to write lock
+ return mo;
+
+ QString xml;
+ if (reply.type() == QDBusMessage::ReplyMessage)
+ // fetch the XML description
+ xml = reply.first().toString();
+ else {
+ lastError = reply;
+ if (reply.type() != QDBusMessage::ErrorMessage || lastError != QDBusError::UnknownMethod)
+ return 0; // error
+ }
+
+ // release the lock and return
+ return QDBusMetaObject::createMetaObject(interface, xml, cachedMetaObjects, lastError);
+}
+
+void QDBusReplyWaiter::reply(const QDBusMessage &msg)
+{
+ replyMsg = msg;
+ QTimer::singleShot(0, this, SLOT(quit()));
+}
+
+#include "qdbusconnection_p.moc"
diff --git a/qt/src/qdbusinterface.cpp b/qt/src/qdbusinterface.cpp
new file mode 100644
index 00000000..6367654d
--- /dev/null
+++ b/qt/src/qdbusinterface.cpp
@@ -0,0 +1,203 @@
+/* -*- 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 "qdbusinterface.h"
+
+#include <dbus/dbus.h>
+#include <QtCore/qpointer.h>
+
+#include "qdbusinterface_p.h"
+#include "qdbusconnection_p.h"
+
+/*!
+ \class QDBusInterface
+ \brief Proxy class for interfaces on remote objects.
+
+ QDBusInterface is a generic accessor class that is used to place calls to remote objects,
+ connect to signals exported by remote objects and get/set the value of remote properties. This
+ class is useful for dynamic access to remote objects: that is, when you do not have a generated
+ code that represents the remote interface.
+
+ Calls are usually placed by using the call() function, which constructs the message, sends it
+ over the bus, waits for the reply and decodes the reply. Signals are connected to by using the
+ normal QObject::connect() function. Finally, properties are accessed using the
+ QObject::property() and QObject::setProperty() functions.
+*/
+
+QDBusInterface::QDBusInterface(QDBusInterfacePrivate *p)
+ : QDBusAbstractInterface(p)
+{
+}
+
+/*!
+ Destroy the object interface and frees up any resource used.
+*/
+QDBusInterface::~QDBusInterface()
+{
+ // resources are freed in QDBusInterfacePrivate::~QDBusInterfacePrivate()
+}
+
+/*!
+ \internal
+ Overrides QObject::metaObject to return our own copy.
+*/
+const QMetaObject *QDBusInterface::metaObject() const
+{
+ return d_func()->isValid ? d_func()->metaObject : &QDBusAbstractInterface::staticMetaObject;
+}
+
+/*!
+ \internal
+ Override QObject::qt_metacast to catch the interface name too.
+*/
+void *QDBusInterface::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, "QDBusInterface"))
+ return static_cast<void*>(const_cast<QDBusInterface*>(this));
+ if (d_func()->interface == _clname)
+ return static_cast<void*>(const_cast<QDBusInterface*>(this));
+ return QDBusAbstractInterface::qt_metacast(_clname);
+}
+
+/*!
+ \internal
+ Dispatch the call through the private.
+*/
+int QDBusInterface::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QDBusAbstractInterface::qt_metacall(_c, _id, _a);
+ if (_id < 0 || !d_func()->isValid)
+ return _id;
+ return d_func()->metacall(_c, _id, _a);
+}
+
+int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv)
+{
+ Q_Q(QDBusInterface);
+
+ if (c == QMetaObject::InvokeMetaMethod) {
+ int offset = metaObject->methodOffset();
+ QMetaMethod mm = metaObject->method(id + offset);
+
+ if (mm.methodType() == QMetaMethod::Signal) {
+ // signal relay from D-Bus world to Qt world
+ QMetaObject::activate(q, metaObject, id, argv);
+
+ } else if (mm.methodType() == QMetaMethod::Slot) {
+ // method call relay from Qt world to D-Bus world
+ // get D-Bus equivalent signature
+ QString methodName = metaObject->dbusNameForMethod(id);
+ const int *inputTypes = metaObject->inputTypesForMethod(id);
+ const int *outputTypes = metaObject->outputTypesForMethod(id);
+
+ int inputTypesCount = *inputTypes;
+ int outputTypesCount = *outputTypes++;
+
+ // we will assume that the input arguments were passed correctly
+ QVariantList args;
+ for (int i = 1; i <= inputTypesCount; ++i)
+ args << QVariant(inputTypes[i], argv[i]);
+
+ // make the call
+ QPointer<QDBusInterface> qq = q;
+ QDBusMessage reply = q->callWithArgs(methodName, args);
+ args.clear();
+
+ // access to "this" or to "q" below this point must check for "qq"
+ // we may have been deleted!
+
+ // check if we got the right number of parameters back:
+ bool success = false;
+ if (reply.count() == outputTypesCount) {
+ // copy the values out
+ for (int i = 0; i < outputTypesCount; ++i) {
+ // treat the return value specially, since it may be null:
+ if (i == 0 && argv[0] == 0)
+ continue;
+
+ // ensure that the types are correct:
+ const QVariant &item = reply.at(i);
+ if (outputTypes[i] != item.userType()) {
+ success = false;
+ break;
+ }
+
+ if (i == 0)
+ QDBusMetaObject::assign(argv[0], item);
+ else
+ QDBusMetaObject::assign(argv[inputTypesCount + i], item);
+ }
+ }
+
+ // bail out, something weird happened
+ if (!success && !qq.isNull()) {
+ QString errmsg = QLatin1String("Invalid signature `%1' in return from call to %2.%3");
+ lastError = QDBusError(QDBusError::InvalidSignature,
+ errmsg.arg(reply.signature(), interface, methodName));
+ }
+
+ // done
+ return -1;
+ }
+ } else if (c == QMetaObject::ReadProperty) {
+ // Qt doesn't support non-readable properties
+ // we have to re-check
+ QMetaProperty mp = metaObject->property(id + metaObject->propertyOffset());
+ if (!mp.isReadable())
+ return -1; // don't read
+
+ QVariant value = property(mp);
+ if (value.type() == QVariant::Invalid)
+ // an error occurred -- property already set lastError
+ return -1;
+ else if (mp.type() == QVariant::LastType)
+ // QVariant is special in this context
+ *reinterpret_cast<QVariant *>(argv[0]) = value;
+ else
+ QDBusMetaObject::assign(argv[0], value);
+
+ return -1; // handled
+ } else if (c == QMetaObject::WriteProperty) {
+ // QMetaProperty::write has already checked that we're writable
+ // it has also checked that the type is right
+ QVariant value(metaObject->propertyMetaType(id), argv[0]);
+ QMetaProperty mp = metaObject->property(id + metaObject->propertyOffset());
+
+ setProperty(mp, value);
+ return -1;
+ }
+ return id;
+}
+
+QDBusInterfacePtr::QDBusInterfacePtr(QDBusConnection &conn, const QString &service, const QString &path,
+ const QString &interface)
+ : d(conn.findInterface(service, path, interface))
+{
+}
+
+QDBusInterfacePtr::QDBusInterfacePtr(const QString &service, const QString &path, const QString &interface)
+ : d(QDBus::sessionBus().findInterface(service, path, interface))
+{
+}
+
diff --git a/qt/src/qdbusinterface.h b/qt/src/qdbusinterface.h
new file mode 100644
index 00000000..0b4d1874
--- /dev/null
+++ b/qt/src/qdbusinterface.h
@@ -0,0 +1,63 @@
+/* -*- 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 QDBUSINTERFACE_H
+#define QDBUSINTERFACE_H
+
+#include "qdbusabstractinterface.h"
+
+class QDBusInterfacePrivate;
+class QDBUS_EXPORT QDBusInterface: public QDBusAbstractInterface
+{
+ friend class QDBusConnection;
+private:
+ QDBusInterface(QDBusInterfacePrivate *p);
+
+public:
+ ~QDBusInterface();
+
+ virtual const QMetaObject *metaObject() const;
+ virtual void *qt_metacast(const char *);
+ virtual int qt_metacall(QMetaObject::Call, int, void **);
+
+private:
+ Q_DECLARE_PRIVATE(QDBusInterface)
+ Q_DISABLE_COPY(QDBusInterface)
+};
+
+struct QDBUS_EXPORT QDBusInterfacePtr
+{
+ QDBusInterfacePtr(QDBusInterface *iface) : d(iface) { }
+ QDBusInterfacePtr(QDBusConnection &conn, const QString &service, const QString &path,
+ const QString &interface = QString());
+ QDBusInterfacePtr(const QString &service, const QString &path, const QString &interface = QString());
+ ~QDBusInterfacePtr() { delete d; }
+
+ QDBusInterface *interface() { return d; }
+ QDBusInterface *operator->() { return d; }
+private:
+ QDBusInterface *const d;
+ Q_DISABLE_COPY(QDBusInterfacePtr)
+};
+
+#endif
diff --git a/qt/src/qdbusinterface_p.h b/qt/src/qdbusinterface_p.h
new file mode 100644
index 00000000..25cb9ffa
--- /dev/null
+++ b/qt/src/qdbusinterface_p.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * 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 "qdbusabstractinterface_p.h"
+#include "qdbusmetaobject_p.h"
+#include "qdbusinterface.h"
+
+class QDBusInterfacePrivate: public QDBusAbstractInterfacePrivate
+{
+public:
+ Q_DECLARE_PUBLIC(QDBusInterface)
+
+ QDBusMetaObject *metaObject;
+
+ inline QDBusInterfacePrivate(const QDBusConnection &con, QDBusConnectionPrivate *conp,
+ const QString &serv, const QString &p, const QString &iface,
+ QDBusMetaObject *mo = 0)
+ : QDBusAbstractInterfacePrivate(con, conp, serv, p, iface), metaObject(mo)
+ {
+ }
+ ~QDBusInterfacePrivate()
+ {
+ if (metaObject && !metaObject->cached)
+ delete metaObject;
+ }
+
+ int metacall(QMetaObject::Call c, int id, void **argv);
+};
+
+#endif
diff --git a/qt/src/qdbusinternalfilters.cpp b/qt/src/qdbusinternalfilters.cpp
new file mode 100644
index 00000000..8886d3bf
--- /dev/null
+++ b/qt/src/qdbusinternalfilters.cpp
@@ -0,0 +1,235 @@
+/* -*- 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 "qdbusconnection_p.h"
+
+#include <dbus/dbus.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qstringlist.h>
+
+#include "qdbusabstractadaptor.h"
+#include "qdbusabstractadaptor_p.h"
+#include "qdbusconnection.h"
+#include "qdbusmessage.h"
+#include "qdbustypehelper_p.h"
+#include "qdbusutil.h"
+
+// defined in qdbusxmlgenerator.cpp
+extern QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
+ const QMetaObject *base, int flags);
+
+static const char introspectableInterfaceXml[] =
+ " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
+ " <method name=\"Introspect\">\n"
+ " <arg name=\"xml_data\" type=\"s\" direction=\"out\"/>\n"
+ " </method>\n"
+ " </interface>\n";
+
+static const char propertiesInterfaceXml[] =
+ " <interface name=\"org.freedesktop.DBus.Properties\">\n"
+ " <method name=\"Get\">\n"
+ " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
+ " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
+ " <arg name=\"value\" type=\"v\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"Set\">\n"
+ " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
+ " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
+ " <arg name=\"value\" type=\"v\" direction=\"in\"/>\n"
+ " </method>\n"
+ " </interface>\n";
+
+static QString generateSubObjectXml(QObject *object)
+{
+ QString retval;
+ foreach (QObject *child, object->children()) {
+ QString name = child->objectName();
+ if (!name.isEmpty())
+ retval += QString(QLatin1String(" <node name=\"%1\"/>\n"))
+ .arg(name);
+ }
+ return retval;
+}
+
+QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node)
+{
+ // object may be null
+
+ QString xml_data(QLatin1String(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE));
+ xml_data += QLatin1String("<node>\n");
+
+ if (node->obj) {
+ if (node->flags & QDBusConnection::ExportContents) {
+ const QMetaObject *mo = node->obj->metaObject();
+ for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass())
+ xml_data += qDBusGenerateMetaObjectXml(QString(), mo, mo->superClass(),
+ node->flags);
+ }
+
+ // does this object have adaptors?
+ QDBusAdaptorConnector *connector;
+ if (node->flags & QDBusConnection::ExportAdaptors &&
+ (connector = qDBusFindAdaptorConnector(node->obj))) {
+
+ // trasverse every adaptor in this object
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin();
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator end = connector->adaptors.constEnd();
+ for ( ; it != end; ++it) {
+ // add the interface:
+ QString ifaceXml = QDBusAbstractAdaptorPrivate::retrieveIntrospectionXml(it->adaptor);
+ if (ifaceXml.isEmpty()) {
+ // add the interface's contents:
+ ifaceXml += qDBusGenerateMetaObjectXml(it->interface, it->metaObject,
+ &QDBusAbstractAdaptor::staticMetaObject,
+ QDBusConnection::ExportAllContents);
+
+ QDBusAbstractAdaptorPrivate::saveIntrospectionXml(it->adaptor, ifaceXml);
+ }
+
+ xml_data += ifaceXml;
+ }
+ }
+
+ xml_data += QLatin1String( introspectableInterfaceXml );
+ xml_data += QLatin1String( propertiesInterfaceXml );
+ }
+
+ if (node->flags & QDBusConnection::ExportChildObjects) {
+ xml_data += generateSubObjectXml(node->obj);
+ } else {
+ // generate from the object tree
+ foreach (const QDBusConnectionPrivate::ObjectTreeNode::Data &entry, node->children) {
+ if (entry.node && (entry.node->obj || !entry.node->children.isEmpty()))
+ xml_data += QString(QLatin1String(" <node name=\"%1\"/>\n"))
+ .arg(entry.name);
+ }
+ }
+
+ xml_data += QLatin1String("</node>\n");
+ return xml_data;
+}
+
+void qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode *node,
+ const QDBusMessage &msg)
+{
+ // now send it
+ QDBusMessage reply = QDBusMessage::methodReply(msg);
+ reply << qDBusIntrospectObject(node);
+ msg.connection().send(reply);
+}
+
+// implement the D-Bus interface org.freedesktop.DBus.Properties
+
+static void sendPropertyError(const QDBusMessage &msg, const QString &interface_name)
+{
+ QDBusMessage error = QDBusMessage::error(msg, QLatin1String(DBUS_ERROR_INVALID_ARGS),
+ QString::fromLatin1("Interface %1 was not found in object %2")
+ .arg(interface_name)
+ .arg(msg.path()));
+ msg.connection().send(error);
+}
+
+void qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode *node, const QDBusMessage &msg)
+{
+ Q_ASSERT(msg.count() == 2);
+ QString interface_name = msg.at(0).toString();
+ QByteArray property_name = msg.at(1).toString().toUtf8();
+
+ QDBusAdaptorConnector *connector;
+ QVariant value;
+ if (node->flags & QDBusConnection::ExportAdaptors &&
+ (connector = qDBusFindAdaptorConnector(node->obj))) {
+
+ // find the class that implements interface_name
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
+ it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
+ interface_name);
+ if (it != connector->adaptors.end() && it->interface == interface_name)
+ value = it->adaptor->property(property_name);
+ }
+
+ if (!value.isValid() && node->flags & QDBusConnection::ExportProperties) {
+ // try the object itself
+ int pidx = node->obj->metaObject()->indexOfProperty(property_name);
+ if (pidx != -1) {
+ QMetaProperty mp = node->obj->metaObject()->property(pidx);
+ if (mp.isScriptable() || (node->flags & QDBusConnection::ExportAllProperties) ==
+ QDBusConnection::ExportAllProperties)
+ value = mp.read(node->obj);
+ }
+ }
+
+ if (!value.isValid()) {
+ // the property was not found
+ sendPropertyError(msg, interface_name);
+ return;
+ }
+
+ QDBusMessage reply = QDBusMessage::methodReply(msg);
+ reply.setSignature(QLatin1String("v"));
+ reply << value;
+ msg.connection().send(reply);
+}
+
+void qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode *node, const QDBusMessage &msg)
+{
+ Q_ASSERT(msg.count() == 3);
+ QString interface_name = msg.at(0).toString();
+ QByteArray property_name = msg.at(1).toString().toUtf8();
+ QVariant value = QDBusTypeHelper<QVariant>::fromVariant(msg.at(2));
+
+ QDBusAdaptorConnector *connector;
+ if (node->flags & QDBusConnection::ExportAdaptors &&
+ (connector = qDBusFindAdaptorConnector(node->obj))) {
+
+ // find the class that implements interface_name
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
+ it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
+ interface_name);
+ if (it != connector->adaptors.end() && it->interface == interface_name)
+ if (it->adaptor->setProperty(property_name, value)) {
+ msg.connection().send(QDBusMessage::methodReply(msg));
+ return;
+ }
+ }
+
+ if (node->flags & QDBusConnection::ExportProperties) {
+ // try the object itself
+ int pidx = node->obj->metaObject()->indexOfProperty(property_name);
+ if (pidx != -1) {
+ QMetaProperty mp = node->obj->metaObject()->property(pidx);
+ if (mp.isScriptable() || (node->flags & QDBusConnection::ExportAllProperties) ==
+ QDBusConnection::ExportAllProperties) {
+
+ if (mp.write(node->obj, value)) {
+ msg.connection().send(QDBusMessage::methodReply(msg));
+ return;
+ }
+ }
+ }
+ }
+
+ // the property was not found or not written to
+ sendPropertyError(msg, interface_name);
+}
diff --git a/qt/src/qdbusintrospection.cpp b/qt/src/qdbusintrospection.cpp
new file mode 100644
index 00000000..20acbd21
--- /dev/null
+++ b/qt/src/qdbusintrospection.cpp
@@ -0,0 +1,403 @@
+/* -*- 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_p.h"
+#include "qdbusxmlparser_p.h"
+
+/*!
+ \class QDBusIntrospection
+ \brief Information about introspected objects and interfaces on D-Bus.
+ \internal
+
+ 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).
+*/
+
+/*!
+ \class 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.
+*/
+
+/*!
+ \fn QDBusIntrospection::Argument::operator==(const Argument &other) const
+ Compares this object against \a other and return true if they are the same.
+*/
+
+/*!
+ \class 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.
+*/
+
+/*!
+ \fn QDBusIntrospection::Method::operator==(const Method &other) const
+ Compares this object against \a other and return true if they are the same.
+*/
+
+/*!
+ \class 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::name
+ The signal's name.
+*/
+
+/*!
+ \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.
+*/
+
+/*!
+ \fn QDBusIntrospection::Signal::operator==(const Signal& other) const
+ Compares this object against \a other and return true if they are the same.
+*/
+
+/*!
+ \class 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:
+ \value Read
+ \value Write
+ \value 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.
+*/
+
+/*!
+ \fn QDBusIntrospection::Property::operator==(const Property &other) const
+ Compares this object against \a other and return true if they are the same.
+*/
+
+/*!
+ \class 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.
+*/
+
+/*!
+ \fn QDBusIntrospection::Interface::operator==(const Interface &other) const
+ Compares this object against \a other and return true if they are the same.
+
+ Note that two interfaces are considered to be the same if they have the same name. The internal
+ structures in the objects are not compared.
+*/
+
+/*!
+ \class 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 \l
+ {QDBusIntrospection::Object::path}{path}.
+*/
+
+/*!
+ \class 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 (given by \a xml) 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.
+*/
+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 (given by \a xml) 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.
+*/
+QDBusIntrospection::Interfaces
+QDBusIntrospection::parseInterfaces(const QString &xml)
+{
+ QString null;
+ QDBusXmlParser parser(null, null, xml);
+ return parser.interfaces();
+}
+
+/*!
+ Parses the XML document fragment (given by \a xml) containing one object, found at the service
+ \a service and path \a path.
+
+ 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.
+*/
+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 (given by \a xml) containing one object node and returns all
+ the information about the interfaces and sub-objects, found at the service \a service and path
+ \a path.
+
+ The Objects map returned will contain the absolute path names in the key.
+*/
+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;
+}
diff --git a/qt/src/qdbusintrospection_p.h b/qt/src/qdbusintrospection_p.h
new file mode 100644
index 00000000..0e4e9015
--- /dev/null
+++ b/qt/src/qdbusintrospection_p.h
@@ -0,0 +1,147 @@
+/* -*- 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 "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
+ {
+ QString 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;
+ QString 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.isEmpty() && 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
diff --git a/qt/src/qdbusmacros.h b/qt/src/qdbusmacros.h
new file mode 100644
index 00000000..0af5b5b3
--- /dev/null
+++ b/qt/src/qdbusmacros.h
@@ -0,0 +1,60 @@
+/* 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
+ *
+ * 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.
+ *
+ */
+
+/*!
+ \file qdbusmacros.h
+*/
+
+#ifndef QDBUSMACROS_H
+#define QDBUSMACROS_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qvariant.h>
+
+#ifdef QT_NO_MEMBER_TEMPLATES
+# error Sorry, you need a compiler with support for template member functions to compile QtDBus.
+#endif
+
+#if defined(QDBUS_MAKEDLL)
+# define QDBUS_EXPORT Q_DECL_EXPORT
+#else
+# define QDBUS_EXPORT Q_DECL_IMPORT
+#endif
+
+#ifndef Q_MOC_RUN
+# define Q_ASYNC
+#endif
+
+#ifdef Q_CC_MSVC
+#include <QtCore/qlist.h>
+#include <QtCore/qset.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qvector.h>
+class QDBusType;
+inline uint qHash(const QVariant&) { Q_ASSERT(0); return 0; }
+inline uint qHash(const QDBusType&) { Q_ASSERT(0); return 0; }
+#endif
+
+#endif
diff --git a/qt/src/qdbusmarshall.cpp b/qt/src/qdbusmarshall.cpp
new file mode 100644
index 00000000..6209ffb3
--- /dev/null
+++ b/qt/src/qdbusmarshall.cpp
@@ -0,0 +1,554 @@
+/* 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
+ *
+ * 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 "qdbusmarshall_p.h"
+#include "qdbustype_p.h"
+#include "qdbustypehelper_p.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>
+
+static QVariant qFetchParameter(DBusMessageIter *it);
+
+template <typename T>
+inline T qIterGet(DBusMessageIter *it)
+{
+ T t;
+ dbus_message_iter_get_basic(it, &t);
+ return t;
+}
+
+template<>
+inline QVariant qIterGet(DBusMessageIter *it)
+{
+ DBusMessageIter sub;
+ dbus_message_iter_recurse(it, &sub);
+ return QDBusTypeHelper<QVariant>::toVariant(qFetchParameter(&sub));
+}
+
+template <typename DBusType, typename QtType>
+inline QVariant qFetchList(DBusMessageIter *arrayIt)
+{
+ QList<QtType> list;
+
+ DBusMessageIter it;
+ dbus_message_iter_recurse(arrayIt, &it);
+ if (dbus_message_iter_get_array_len(&it) == 0)
+ return QDBusTypeHelper<QList<QtType> >::toVariant(list);
+
+ do {
+ list.append( static_cast<QtType>( qIterGet<DBusType>(&it) ) );
+ } while (dbus_message_iter_next(&it));
+
+ return QDBusTypeHelper<QList<QtType> >::toVariant(list);
+}
+
+static QStringList qFetchStringList(DBusMessageIter *arrayIt)
+{
+ QStringList list;
+
+ DBusMessageIter it;
+ dbus_message_iter_recurse(arrayIt, &it);
+ if (dbus_message_iter_get_array_len(&it) == 0)
+ return list;
+
+ do {
+ list.append(QString::fromUtf8(qIterGet<char *>(&it)));
+ } while (dbus_message_iter_next(&it));
+
+ return list;
+}
+
+static QVariant qFetchParameter(DBusMessageIter *it)
+{
+ switch (dbus_message_iter_get_arg_type(it)) {
+ case DBUS_TYPE_BYTE:
+ return qVariantFromValue(qIterGet<unsigned char>(it));
+ case DBUS_TYPE_INT16:
+ return qVariantFromValue(qIterGet<dbus_int16_t>(it));
+ case DBUS_TYPE_UINT16:
+ return qVariantFromValue(qIterGet<dbus_uint16_t>(it));
+ case DBUS_TYPE_INT32:
+ return qIterGet<dbus_int32_t>(it);
+ case DBUS_TYPE_UINT32:
+ return qIterGet<dbus_uint32_t>(it);
+ case DBUS_TYPE_DOUBLE:
+ return qIterGet<double>(it);
+ case DBUS_TYPE_BOOLEAN:
+ return bool(qIterGet<dbus_bool_t>(it));
+ case DBUS_TYPE_INT64:
+ return static_cast<qlonglong>(qIterGet<dbus_int64_t>(it));
+ case DBUS_TYPE_UINT64:
+ return static_cast<qulonglong>(qIterGet<dbus_uint64_t>(it));
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ return QString::fromUtf8(qIterGet<char *>(it));
+ case DBUS_TYPE_VARIANT:
+ return qIterGet<QVariant>(it);
+ case DBUS_TYPE_ARRAY: {
+ int arrayType = dbus_message_iter_get_element_type(it);
+ switch (arrayType)
+ {
+ case DBUS_TYPE_BYTE: {
+ // QByteArray
+ 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);
+ }
+ case DBUS_TYPE_INT16:
+ return qFetchList<dbus_int16_t, short>(it);
+ case DBUS_TYPE_UINT16:
+ return qFetchList<dbus_uint16_t, ushort>(it);
+ case DBUS_TYPE_INT32:
+ return qFetchList<dbus_int32_t, int>(it);
+ case DBUS_TYPE_UINT32:
+ return qFetchList<dbus_uint32_t, uint>(it);
+ case DBUS_TYPE_BOOLEAN:
+ return qFetchList<dbus_bool_t, bool>(it);
+ case DBUS_TYPE_DOUBLE:
+ return qFetchList<double, double>(it);
+ case DBUS_TYPE_INT64:
+ return qFetchList<dbus_int64_t, qlonglong>(it);
+ case DBUS_TYPE_UINT64:
+ return qFetchList<dbus_uint64_t, qulonglong>(it);
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ return qFetchStringList(it);
+ case DBUS_TYPE_VARIANT:
+ return qFetchList<QVariant, QVariant>(it);
+ case 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_get_array_len(&sub) == 0)
+ // empty map
+ return map;
+
+ do {
+ DBusMessageIter itemIter;
+ dbus_message_iter_recurse(&sub, &itemIter);
+ Q_ASSERT(dbus_message_iter_has_next(&itemIter));
+ QString key = qFetchParameter(&itemIter).toString();
+ dbus_message_iter_next(&itemIter);
+ map.insertMulti(key, qFetchParameter(&itemIter));
+ } while (dbus_message_iter_next(&sub));
+ return map;
+ }
+ }
+ }
+ // fall through
+ // common handling for structs and lists of lists (for now)
+ case DBUS_TYPE_STRUCT: {
+ QList<QVariant> list;
+ DBusMessageIter sub;
+ dbus_message_iter_recurse(it, &sub);
+ if (dbus_message_iter_get_array_len(&sub) == 0)
+ return list;
+ do {
+ list.append(qFetchParameter(&sub));
+ } while (dbus_message_iter_next(&sub));
+ return list;
+ }
+
+ 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();
+ break;
+ }
+}
+
+void QDBusMarshall::messageToList(QList<QVariant> &list, DBusMessage *message)
+{
+ Q_ASSERT(message);
+
+ DBusMessageIter it;
+ if (!dbus_message_iter_init(message, &it))
+ return;
+
+ do {
+ list.append(qFetchParameter(&it));
+ } while (dbus_message_iter_next(&it));
+}
+
+// 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)
+{
+ if (!type.isValid()) {
+ // guess it from the variant
+ type = QDBusType::guessFromVariant(var);
+ return true;
+ }
+
+ int id = var.userType();
+
+ if (type.dbusType() == DBUS_TYPE_VARIANT) {
+ // this is a non symmetrical operation:
+ // nest a QVariant if we want variant and it isn't so
+ if (id != QDBusTypeHelper<QVariant>::id()) {
+ QVariant tmp = var;
+ var = QDBusTypeHelper<QVariant>::toVariant(tmp);
+ }
+ return true;
+ }
+
+ switch (id) {
+ case QVariant::Bool:
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ case QMetaType::UChar:
+ case QVariant::Int:
+ case QVariant::UInt:
+ case QVariant::LongLong:
+ case QVariant::ULongLong:
+ case QVariant::Double:
+ case QVariant::String:
+ if (type.isBasic())
+ // QVariant can handle this on its own
+ return true;
+
+ // 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
+ void *null = 0;
+ var = QVariant(type.qvariantType(), null);
+ break;
+ }
+
+ default:
+ if (id == QDBusTypeHelper<QVariant>::id()) {
+ // if we got here, it means the match above for DBUS_TYPE_VARIANT didn't work
+ qWarning("Invalid conversion from nested variant to '%s'",
+ type.dbusSignature().constData());
+ return false;
+ } else if (type.dbusType() == DBUS_TYPE_ARRAY) {
+ int subType = type.arrayElement().dbusType();
+ if ((id == QDBusTypeHelper<bool>::listId() && subType == DBUS_TYPE_BOOLEAN) ||
+ (id == QDBusTypeHelper<short>::listId() && subType == DBUS_TYPE_INT16) ||
+ (id == QDBusTypeHelper<ushort>::listId() && subType == DBUS_TYPE_UINT16) ||
+ (id == QDBusTypeHelper<int>::listId() && subType == DBUS_TYPE_INT32) ||
+ (id == QDBusTypeHelper<uint>::listId() && subType == DBUS_TYPE_UINT32) ||
+ (id == QDBusTypeHelper<qlonglong>::listId() && subType == DBUS_TYPE_INT64) ||
+ (id == QDBusTypeHelper<qulonglong>::listId() && subType == DBUS_TYPE_UINT64) ||
+ (id == QDBusTypeHelper<double>::listId() && subType == DBUS_TYPE_DOUBLE))
+ return true;
+ }
+
+ qWarning("Invalid conversion from %s to '%s'", var.typeName(),
+ type.dbusSignature().constData());
+ return false;
+ }
+
+ 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 &typelist);
+
+template<typename T>
+static void qIterAppend(DBusMessageIter *it, const QDBusType &type, T arg)
+{
+ dbus_message_iter_append_basic(it, type.dbusType(), &arg);
+}
+
+template<typename DBusType, typename QtType>
+static void qAppendListToMessage(DBusMessageIter *it, const QDBusType &subType,
+ const QVariant &var)
+{
+ QList<QtType> list = QDBusTypeHelper<QList<QtType> >::fromVariant(var);
+ foreach (const QtType &item, list)
+ qIterAppend(it, subType, static_cast<DBusType>(item));
+}
+
+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();
+ foreach (QString str, list)
+ qIterAppend(&sub, subType, str.toUtf8().constData());
+ break;
+ }
+
+ 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: {
+ 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);
+
+ // 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);
+ }
+ break;
+ }
+
+ case QVariant::List: {
+ const QVariantList list = var.toList();
+ foreach (QVariant v, list)
+ qVariantToIteratorInternal(&sub, v, subType);
+ break;
+ }
+
+ default: {
+ int id = var.userType();
+ if (id == QDBusTypeHelper<bool>::listId())
+ qAppendListToMessage<dbus_bool_t,bool>(&sub, subType, var);
+ else if (id == QDBusTypeHelper<short>::listId())
+ qAppendListToMessage<dbus_int16_t,short>(&sub, subType, var);
+ else if (id == QDBusTypeHelper<ushort>::listId())
+ qAppendListToMessage<dbus_uint16_t,ushort>(&sub, subType, var);
+ else if (id == QDBusTypeHelper<int>::listId())
+ qAppendListToMessage<dbus_int32_t,int>(&sub, subType, var);
+ else if (id == QDBusTypeHelper<uint>::listId())
+ qAppendListToMessage<dbus_uint32_t,uint>(&sub, subType, var);
+ else if (id == QDBusTypeHelper<qlonglong>::listId())
+ qAppendListToMessage<dbus_int64_t,qlonglong>(&sub, subType, var);
+ else if (id == QDBusTypeHelper<qulonglong>::listId())
+ qAppendListToMessage<dbus_uint64_t,qulonglong>(&sub, subType, var);
+ else if (id == QDBusTypeHelper<double>::listId())
+ qAppendListToMessage<double,double>(&sub, subType, var);
+#if 0 // never reached, since QVariant::List mached
+ else if (id == QDBusTypeHelper<QVariant>::listId())
+ qAppendListToMessage<QVariant,QVariant>(&sub, subType, var);
+#endif
+ else
+ 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)
+{
+ Q_UNUSED(type); // type is 'v'
+
+ QVariant arg = var;
+ if (var.userType() == QDBusTypeHelper<QVariant>::id())
+ arg = QDBusTypeHelper<QVariant>::fromVariant(var); // extract the inner variant
+
+ QDBusType t = QDBusType::guessFromVariant(arg);
+
+ // now add this variant
+ DBusMessageIter sub;
+ dbus_message_iter_open_container(it, DBUS_TYPE_VARIANT, t.dbusSignature(), &sub);
+ qVariantToIteratorInternal(&sub, arg, 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, QDBusTypeHelper<uchar>::fromVariant(var) );
+ break;
+ case DBUS_TYPE_BOOLEAN:
+ qIterAppend( it, type, static_cast<dbus_bool_t>(var.toBool()) );
+ break;
+ case DBUS_TYPE_INT16:
+ qIterAppend( it, type, QDBusTypeHelper<short>::fromVariant(var) );
+ break;
+ case DBUS_TYPE_UINT16:
+ qIterAppend( it, type, QDBusTypeHelper<ushort>::fromVariant(var) );
+ break;
+ case DBUS_TYPE_INT32:
+ qIterAppend( it, type, static_cast<dbus_int32_t>(var.toInt()) );
+ break;
+ case DBUS_TYPE_UINT32:
+ qIterAppend( it, type, static_cast<dbus_uint32_t>(var.toUInt()) );
+ break;
+ case DBUS_TYPE_INT64:
+ qIterAppend( it, type, static_cast<dbus_int64_t>(var.toLongLong()) );
+ break;
+ case DBUS_TYPE_UINT64:
+ qIterAppend( it, type, static_cast<dbus_uint64_t>(var.toULongLong()) );
+ break;
+ case DBUS_TYPE_DOUBLE:
+ qIterAppend( it, type, var.toDouble() );
+ break;
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ qIterAppend( it, type, var.toString().toUtf8().constData() );
+ break;
+
+ // compound types:
+ case DBUS_TYPE_ARRAY:
+ // could be many things
+ qAppendArrayToMessage( it, type.arrayElement(), var );
+ break;
+
+ case DBUS_TYPE_VARIANT:
+ qAppendVariantToMessage( it, type, var );
+ break;
+
+ case DBUS_TYPE_STRUCT:
+ qAppendStructToMessage( it, type.subTypes(), var.toList() );
+ break;
+
+ case DBUS_TYPE_DICT_ENTRY:
+ qFatal("qVariantToIterator got a DICT_ENTRY!");
+ break;
+
+ default:
+ qWarning("Found unknown DBus type '%s'", type.dbusSignature().constData());
+ break;
+ }
+}
+
+void qListToIterator(DBusMessageIter *it, const QList<QVariant> &list)
+{
+ for (int i = 0; i < list.count(); ++i)
+ qVariantToIterator(it, list.at(i), QDBusType());
+}
+
+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);
+
+ if (signature.isEmpty())
+ qListToIterator(&it, list);
+ else
+ qListToIterator(&it, list, QDBusTypeList(signature.toUtf8()));
+}
diff --git a/qt/src/qdbusmarshall_p.h b/qt/src/qdbusmarshall_p.h
new file mode 100644
index 00000000..7a2d46f5
--- /dev/null
+++ b/qt/src/qdbusmarshall_p.h
@@ -0,0 +1,57 @@
+/* qdbusmarshall_p.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
+ *
+ * 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 QDBUSMARSHALLPRIVATE_H
+#define QDBUSMARSHALLPRIVATE_H
+
+struct DBusMessage;
+
+template <typename T> class QList;
+class QVariant;
+class QString;
+
+/*!
+ \internal
+*/
+class QDBusMarshall
+{
+public:
+ static void listToMessage(const QList<QVariant> &list, DBusMessage *message,
+ const QString& signature);
+ static void messageToList(QList<QVariant> &list, DBusMessage *message);
+};
+
+#endif
diff --git a/qt/src/qdbusmessage.cpp b/qt/src/qdbusmessage.cpp
new file mode 100644
index 00000000..d0a0f1e5
--- /dev/null
+++ b/qt/src/qdbusmessage.cpp
@@ -0,0 +1,706 @@
+/* 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
+ *
+ * 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 <qdebug.h>
+#include <qstringlist.h>
+
+#include <dbus/dbus.h>
+
+#include "qdbuserror.h"
+#include "qdbusmarshall_p.h"
+#include "qdbusmessage_p.h"
+#include "qdbustypehelper_p.h"
+
+QDBusMessagePrivate::QDBusMessagePrivate()
+ : connection(QString()), msg(0), reply(0), type(DBUS_MESSAGE_TYPE_INVALID),
+ timeout(-1), ref(1), repliedTo(false)
+{
+}
+
+QDBusMessagePrivate::~QDBusMessagePrivate()
+{
+ if (msg)
+ dbus_message_unref(msg);
+ if (reply)
+ dbus_message_unref(reply);
+}
+
+///////////////
+/*!
+ \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)
+ \list
+ \o Method calls
+ \o Method return values
+ \o Signal emissions
+ \o Error codes
+ \endlist
+
+ Objects of this type are created with the four static functions signal, methodCall,
+ methodReply and error.
+*/
+
+/*!
+ \enum QDBusMessage::MessageType
+ The possible message types:
+
+ \value MethodCallMessage a message representing an outgoing or incoming method call
+ \value SignalMessage a message representing an outgoing or incoming signal emission
+ \value ReplyMessage a message representing the return values of a method call
+ \value ErrorMessage a message representing an error condition in response to a method call
+ \value InvalidMessage an invalid message: this is never set on messages received from D-Bus
+*/
+
+/*!
+ 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.
+
+ The signal will be constructed to represent a signal coming from the path \a path, interface \a
+ interface and signal name \a name.
+
+ The QDBusMessage object that is returned can be sent with QDBusConnection::send().
+*/
+QDBusMessage QDBusMessage::signal(const QString &path, const QString &interface,
+ const QString &name)
+{
+ QDBusMessage message;
+ message.d_ptr->type = DBUS_MESSAGE_TYPE_SIGNAL;
+ message.d_ptr->path = path;
+ message.d_ptr->interface = interface;
+ message.d_ptr->name = name;
+
+ return message;
+}
+
+/*!
+ Constructs a new DBus message representing a method call. A method call always informs
+ its destination address (\a service, \a path, \a interface and \a 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 \a service parameter is
+ optional.
+
+ The QDBusObject and QDBusInterface classes provide a simpler abstraction to synchronous
+ method calling.
+
+ This function 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)
+{
+ QDBusMessage message;
+ message.d_ptr->type = DBUS_MESSAGE_TYPE_METHOD_CALL;
+ message.d_ptr->service = service;
+ message.d_ptr->path = path;
+ message.d_ptr->interface = interface;
+ message.d_ptr->name = method;
+
+ return message;
+}
+
+/*!
+ Constructs a new DBus message representing the return values from a called method. The \a other
+ variable represents the method call that the reply will be for.
+
+ This function returns a QDBusMessage object that can be sent with QDBusConnection::send().
+*/
+QDBusMessage QDBusMessage::methodReply(const QDBusMessage &other)
+{
+ Q_ASSERT(other.d_ptr->msg);
+
+ QDBusMessage message;
+ message.d_ptr->connection = other.d_ptr->connection;
+ message.d_ptr->type = DBUS_MESSAGE_TYPE_METHOD_RETURN;
+ message.d_ptr->reply = dbus_message_ref(other.d_ptr->msg);
+ other.d_ptr->repliedTo = true;
+
+ return message;
+}
+
+/*!
+ Constructs a DBus message representing an error condition described by the \a name
+ parameter. The \a msg parameter is optional and may contain a human-readable description of the
+ error. The \a other variable represents the method call that this error relates to.
+
+ This function returns 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_ptr->msg);
+
+ QDBusMessage message;
+ message.d_ptr->connection = other.d_ptr->connection;
+ message.d_ptr->type = DBUS_MESSAGE_TYPE_ERROR;
+ message.d_ptr->name = name;
+ message.d_ptr->message = msg;
+ message.d_ptr->reply = dbus_message_ref(other.d_ptr->msg);
+ other.d_ptr->repliedTo = true;
+
+ return message;
+}
+
+/*!
+ \overload
+ Constructs a DBus message representing an error, where \a other is the method call that
+ generated this error and \a error is the error code.
+*/
+QDBusMessage QDBusMessage::error(const QDBusMessage &other, const QDBusError &error)
+{
+ Q_ASSERT(other.d_ptr->msg);
+
+ QDBusMessage message;
+ message.d_ptr->connection = other.d_ptr->connection;
+ message.d_ptr->type = DBUS_MESSAGE_TYPE_ERROR;
+ message.d_ptr->name = error.name();
+ message.d_ptr->message = error.message();
+ message.d_ptr->reply = dbus_message_ref(other.d_ptr->msg);
+ other.d_ptr->repliedTo = true;
+
+ return message;
+}
+
+/*!
+ Constructs an empty, invalid QDBusMessage object.
+
+ \sa methodCall(), methodReply(), signal(), error()
+*/
+QDBusMessage::QDBusMessage()
+{
+ d_ptr = new QDBusMessagePrivate;
+}
+
+/*!
+ Constructs a copy of the object given by \a other.
+*/
+QDBusMessage::QDBusMessage(const QDBusMessage &other)
+ : QList<QVariant>(other)
+{
+ d_ptr = other.d_ptr;
+ d_ptr->ref.ref();
+}
+
+/*!
+ Disposes of the object and frees any resources that were being held.
+*/
+QDBusMessage::~QDBusMessage()
+{
+ if (!d_ptr->ref.deref())
+ delete d_ptr;
+}
+
+/*!
+ Copies the contents of the object given by \a other.
+*/
+QDBusMessage &QDBusMessage::operator=(const QDBusMessage &other)
+{
+ QList<QVariant>::operator=(other);
+ qAtomicAssign(d_ptr, other.d_ptr);
+ return *this;
+}
+
+static inline const char *data(const QByteArray &arr)
+{
+ return arr.isEmpty() ? 0 : arr.constData();
+}
+
+/*!
+ \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_ptr->type) {
+ case DBUS_MESSAGE_TYPE_METHOD_CALL:
+ msg = dbus_message_new_method_call(data(d_ptr->service.toUtf8()), data(d_ptr->path.toUtf8()),
+ data(d_ptr->interface.toUtf8()), data(d_ptr->name.toUtf8()));
+ break;
+ case DBUS_MESSAGE_TYPE_SIGNAL:
+ msg = dbus_message_new_signal(data(d_ptr->path.toUtf8()), data(d_ptr->interface.toUtf8()),
+ data(d_ptr->name.toUtf8()));
+ break;
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ msg = dbus_message_new_method_return(d_ptr->reply);
+ break;
+ case DBUS_MESSAGE_TYPE_ERROR:
+ msg = dbus_message_new_error(d_ptr->reply, data(d_ptr->name.toUtf8()), data(d_ptr->message.toUtf8()));
+ break;
+ }
+ if (!msg)
+ return 0;
+
+ QDBusMarshall::listToMessage(*this, msg, d_ptr->signature);
+ return msg;
+}
+
+/*!
+ \internal
+ Constructs a QDBusMessage by parsing the given DBusMessage object.
+*/
+QDBusMessage QDBusMessage::fromDBusMessage(DBusMessage *dmsg, const QDBusConnection &connection)
+{
+ QDBusMessage message;
+ if (!dmsg)
+ return message;
+
+ message.d_ptr->connection = connection;
+ message.d_ptr->type = dbus_message_get_type(dmsg);
+ message.d_ptr->path = QString::fromUtf8(dbus_message_get_path(dmsg));
+ message.d_ptr->interface = QString::fromUtf8(dbus_message_get_interface(dmsg));
+ message.d_ptr->name = message.d_ptr->type == DBUS_MESSAGE_TYPE_ERROR ?
+ QString::fromUtf8(dbus_message_get_error_name(dmsg)) :
+ QString::fromUtf8(dbus_message_get_member(dmsg));
+ message.d_ptr->service = QString::fromUtf8(dbus_message_get_sender(dmsg));
+ message.d_ptr->signature = QString::fromUtf8(dbus_message_get_signature(dmsg));
+ message.d_ptr->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_ptr->type = DBUS_MESSAGE_TYPE_ERROR;
+ message.d_ptr->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_ptr->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_ptr->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_ptr->name;
+}
+
+/*!
+ \fn QDBusMessage::member() const
+ Returns the name of the method being called.
+*/
+
+/*!
+ \fn QDBusMessage::method() const
+ \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_ptr->service;
+}
+
+/*!
+ \fn QDBusMessage::sender() const
+ 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_ptr->timeout;
+}
+
+/*!
+ Sets the timeout for this message to be processed, given by \a ms, in milliseconds.
+*/
+void QDBusMessage::setTimeout(int ms)
+{
+ qAtomicDetach(d_ptr);
+ d_ptr->timeout = ms;
+}
+
+/*!
+ Returns the flag that indicates if this message should see a reply or not. This is only
+ meaningful for MethodCall messages: any other kind of message cannot have replies and this
+ function will always return false for them.
+*/
+bool QDBusMessage::noReply() const
+{
+ if (!d_ptr->msg)
+ return false;
+ return dbus_message_get_no_reply(d_ptr->msg);
+}
+
+/*!
+ Returns the unique serial number assigned to this message
+ or 0 if the message was not sent yet.
+ */
+int QDBusMessage::serialNumber() const
+{
+ if (!d_ptr->msg)
+ return 0;
+ return dbus_message_get_serial(d_ptr->msg);
+}
+
+/*!
+ Returns the unique serial number assigned to the message
+ that triggered this reply message.
+
+ If this message is not a reply to another message, 0
+ is returned.
+
+ */
+int QDBusMessage::replySerialNumber() const
+{
+ if (!d_ptr->msg)
+ return 0;
+ return dbus_message_get_reply_serial(d_ptr->msg);
+}
+
+/*!
+ Returns true if this is a MethodCall message and a reply for it has been generated using
+ QDBusMessage::methodReply or QDBusMessage::error.
+*/
+bool QDBusMessage::wasRepliedTo() const
+{
+ return d_ptr->repliedTo;
+}
+
+/*!
+ Returns the signature of the signal that was received or for the output arguments
+ of a method call.
+*/
+QString QDBusMessage::signature() const
+{
+ return d_ptr->signature;
+}
+
+/*!
+ Sets the signature for the output arguments of this method call to be the value of \a
+ signature. This function has no meaning in other types of messages or when dealing with received
+ method calls.
+
+ A message's signature indicate the type of the parameters to
+ be marshalled over the bus. If there are more arguments than entries 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).
+
+*/
+void QDBusMessage::setSignature(const QString &signature)
+{
+ qAtomicDetach(d_ptr);
+ d_ptr->signature = signature;
+}
+
+/*!
+ Returns the connection this message was received on or an unconnected QDBusConnection object if
+ this isn't a message that has been received.
+*/
+QDBusConnection QDBusMessage::connection() const
+{
+ return d_ptr->connection;
+}
+
+/*!
+ Returns the message type.
+*/
+QDBusMessage::MessageType QDBusMessage::type() const
+{
+ switch (d_ptr->type) {
+ case DBUS_MESSAGE_TYPE_METHOD_CALL:
+ return MethodCallMessage;
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ return ReplyMessage;
+ case DBUS_MESSAGE_TYPE_ERROR:
+ return ErrorMessage;
+ case DBUS_MESSAGE_TYPE_SIGNAL:
+ return SignalMessage;
+ default:
+ return InvalidMessage;
+ }
+}
+
+// Document QDBusReply here
+/*!
+ \class QDBusReply
+ \brief The reply for a method call to a remote object.
+
+ A QDBusReply object is a subset of the QDBusMessage object that represents a method call's
+ reply. It contains only the first output argument or the error code and is used by
+ QDBusInterface-derived classes to allow returning the error code as the function's return
+ argument.
+
+ It can be used in the following manner:
+ \code
+ QDBusReply<QString> reply = interface->call("RemoteMethod");
+ if (reply.isSuccess())
+ // use the returned value
+ useValue(reply.value());
+ else
+ // call failed. Show an error condition.
+ showError(reply.error());
+ \endcode
+
+ If the remote method call cannot fail, you can skip the error checking:
+ \code
+ QString reply = interface->call("RemoteMethod");
+ \endcode
+
+ However, if it does fail under those conditions, the value returned by QDBusReply::value() is
+ undefined. It may be undistinguishable from a valid return value.
+
+ QDBusReply objects are used for remote calls that have no output arguments or return values
+ (i.e., they have a "void" return type). In this case, you can only test if the reply succeeded
+ or not, by calling isError() and isSuccess(), and inspecting the error condition by calling
+ error(). You cannot call value().
+
+ \sa QDBusMessage, QDBusInterface
+*/
+
+/*!
+ \fn QDBusReply::QDBusReply(const QDBusMessage &reply)
+ Automatically construct a QDBusReply object from the reply message \a reply, extracting the
+ first return value from it if it is a success reply.
+*/
+
+/*!
+ \fn QDBusReply::QDBusReply(const QDBusError &error)
+ Constructs an error reply from the D-Bus error code given by \a error.
+*/
+
+/*!
+ \fn QDBusReply::isError() const
+ Returns true if this reply is an error reply. You can extract the error contents using the
+ error() function.
+*/
+
+/*!
+ \fn QDBusReply::isSuccess() const
+ Returns true if this reply is a normal error reply (not an error). You can extract the returned
+ value with value()
+*/
+
+/*!
+ \fn QDBusReply::error()
+ Returns the error code that was returned from the remote function call. If the remote call did
+ not return an error (i.e., if it succeeded), then the QDBusError object that is returned will
+ not be a valid error code (QDBusError::isValid() will return false).
+*/
+
+/*!
+ \fn QDBusReply::value()
+ Returns the remote function's calls return value. If the remote call returned with an error,
+ the return value of this function is undefined and may be undistinguishable from a valid return
+ value.
+
+ This function is not available if the remote call returns \c void.
+*/
+
+/*!
+ \fn QDBusReply::operator Type()
+ Returns the same as value().
+
+ This function is not available if the remote call returns \c void.
+*/
+
+/*!
+ \internal
+ \fn QDBusReply::fromVariant(const QDBusReply<QVariant> &variantReply)
+ Converts the QDBusReply<QVariant> object to this type by converting the variant contained in
+ \a variantReply to the template's type and copying the error condition.
+
+ If the QVariant in variantReply is not convertible to this type, it will assume an undefined
+ value.
+*/
+
+#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";
+ }
+}
+
+static void debugVariantList(QDebug dbg, const QVariantList &list);
+static void debugVariantMap(QDebug dbg, const QVariantMap &map);
+
+static void debugVariant(QDebug dbg, const QVariant &v)
+{
+ dbg.nospace() << v.typeName() << "(";
+ switch (v.userType())
+ {
+ case QVariant::Bool:
+ dbg.nospace() << v.toBool();
+ break;
+ case QMetaType::UChar:
+ dbg.nospace() << qvariant_cast<uchar>(v);
+ break;
+ case QMetaType::Short:
+ dbg.nospace() << qvariant_cast<short>(v);
+ break;
+ case QMetaType::UShort:
+ dbg.nospace() << qvariant_cast<ushort>(v);
+ break;
+ case QVariant::Int:
+ dbg.nospace() << v.toInt();
+ break;
+ case QVariant::UInt:
+ dbg.nospace() << v.toUInt();
+ break;
+ case QVariant::LongLong:
+ dbg.nospace() << v.toLongLong();
+ break;
+ case QVariant::ULongLong:
+ dbg.nospace() << v.toULongLong();
+ break;
+ case QVariant::Double:
+ dbg.nospace() << v.toDouble();
+ break;
+ case QVariant::String:
+ dbg.nospace() << v.toString();
+ break;
+ case QVariant::ByteArray:
+ dbg.nospace() << v.toByteArray();
+ break;
+ case QVariant::StringList:
+ dbg.nospace() << v.toStringList();
+ break;
+ case QVariant::List:
+ debugVariantList(dbg, v.toList());
+ break;
+ case QVariant::Map:
+ debugVariantMap(dbg, v.toMap());
+ break;
+
+ default: {
+ int id = v.userType();
+ if (id == QDBusTypeHelper<QVariant>::id())
+ debugVariant(dbg, QDBusTypeHelper<QVariant>::fromVariant(v));
+ else if (id == QDBusTypeHelper<bool>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<bool> >::fromVariant(v);
+ else if (id == QDBusTypeHelper<short>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<short> >::fromVariant(v);
+ else if (id == QDBusTypeHelper<ushort>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<ushort> >::fromVariant(v);
+ else if (id == QDBusTypeHelper<int>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<int> >::fromVariant(v);
+ else if (id == QDBusTypeHelper<uint>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<uint> >::fromVariant(v);
+ else if (id == QDBusTypeHelper<qlonglong>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<qlonglong> >::fromVariant(v);
+ else if (id == QDBusTypeHelper<qulonglong>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<qulonglong> >::fromVariant(v);
+ else if (id == QDBusTypeHelper<double>::listId())
+ dbg.nospace() << QDBusTypeHelper<QList<double> >::fromVariant(v);
+ else
+ dbg.nospace() << "unknown";
+ }
+ }
+ dbg.nospace() << ")";
+}
+
+static void debugVariantList(QDebug dbg, const QVariantList &list)
+{
+ bool first = true;
+ QVariantList::ConstIterator it = list.constBegin();
+ QVariantList::ConstIterator end = list.constEnd();
+ for ( ; it != end; ++it) {
+ if (!first)
+ dbg.nospace() << ", ";
+ debugVariant(dbg, *it);
+ first = false;
+ }
+}
+
+static void debugVariantMap(QDebug dbg, const QVariantMap &map)
+{
+ QVariantMap::ConstIterator it = map.constBegin();
+ QVariantMap::ConstIterator end = map.constEnd();
+ for ( ; it != end; ++it) {
+ dbg << "(" << it.key() << ", ";
+ debugVariant(dbg, it.value());
+ dbg << ") ";
+ }
+}
+
+QDebug operator<<(QDebug dbg, const QDBusMessage &msg)
+{
+ dbg.nospace() << "QDBusMessage(type=" << msg.type()
+ << ", service=" << msg.service()
+ << ", path=" << msg.path()
+ << ", interface=" << msg.interface()
+ << ", name=" << msg.name()
+ << ", signature=" << msg.signature()
+ << ", contents=(";
+ debugVariantList(dbg, msg);
+ dbg.nospace() << " ) )";
+ return dbg.space();
+}
+#endif
+
diff --git a/qt/src/qdbusmessage.h b/qt/src/qdbusmessage.h
new file mode 100644
index 00000000..f8feeae4
--- /dev/null
+++ b/qt/src/qdbusmessage.h
@@ -0,0 +1,99 @@
+/* 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
+ *
+ * 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 QDBUSMESSAGE_H
+#define QDBUSMESSAGE_H
+
+#include "qdbusmacros.h"
+#include "qdbuserror.h"
+#include <QtCore/qlist.h>
+#include <QtCore/qvariant.h>
+
+#include <limits.h>
+
+class QDBusMessagePrivate;
+class QDBusConnection;
+class QDBusConnectionPrivate;
+struct DBusMessage;
+
+class QDBUS_EXPORT QDBusMessage: public QList<QVariant>
+{
+ //friend class QDBusConnection;
+ friend class QDBusConnectionPrivate;
+public:
+ enum { DefaultTimeout = -1, NoTimeout = INT_MAX};
+ enum MessageType { InvalidMessage, MethodCallMessage, ReplyMessage,
+ ErrorMessage, SignalMessage };
+
+ QDBusMessage();
+ QDBusMessage(const QDBusMessage &other);
+ ~QDBusMessage();
+
+ QDBusMessage &operator=(const QDBusMessage &other);
+
+ static QDBusMessage signal(const QString &path, const QString &interface,
+ const QString &name);
+ static QDBusMessage methodCall(const QString &destination, const QString &path,
+ const QString &interface, const QString &method);
+ 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;
+ 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);
+
+ bool noReply() const;
+
+ QString signature() const;
+ void setSignature(const QString &signature);
+
+ QDBusConnection connection() const;
+
+ int serialNumber() const;
+ int replySerialNumber() const;
+ bool wasRepliedTo() const;
+
+private:
+ DBusMessage *toDBusMessage() const;
+ static QDBusMessage fromDBusMessage(DBusMessage *dmsg, const QDBusConnection &connection);
+ static QDBusMessage fromError(const QDBusError& error);
+ QDBusMessagePrivate *d_ptr;
+};
+
+#ifndef QT_NO_DEBUG
+QDebug operator<<(QDebug, const QDBusMessage &);
+#endif
+
+#endif
+
diff --git a/qt/src/qdbusmessage_p.h b/qt/src/qdbusmessage_p.h
new file mode 100644
index 00000000..ea958b24
--- /dev/null
+++ b/qt/src/qdbusmessage_p.h
@@ -0,0 +1,50 @@
+/* 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
+ *
+ * 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 QDBUSMESSAGE_P_H
+#define QDBUSMESSAGE_P_H
+
+#include <qatomic.h>
+#include <qstring.h>
+#include "qdbusconnection.h"
+struct DBusMessage;
+
+class QDBusMessagePrivate
+{
+public:
+ QDBusMessagePrivate();
+ ~QDBusMessagePrivate();
+
+ QString service, path, interface, name, message, signature;
+ QDBusConnection connection;
+ DBusMessage *msg;
+ DBusMessage *reply;
+ int type;
+ int timeout;
+ QAtomic ref;
+
+ mutable bool repliedTo : 1;
+};
+
+#endif
diff --git a/qt/src/qdbusmetaobject.cpp b/qt/src/qdbusmetaobject.cpp
new file mode 100644
index 00000000..a923d79a
--- /dev/null
+++ b/qt/src/qdbusmetaobject.cpp
@@ -0,0 +1,689 @@
+/* -*- 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 "qdbusmetaobject_p.h"
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qvarlengtharray.h>
+
+#include "qdbusutil.h"
+#include "qdbuserror.h"
+#include "qdbusintrospection_p.h"
+#include "qdbusabstractinterface_p.h"
+
+class QDBusMetaObjectGenerator
+{
+public:
+ QDBusMetaObjectGenerator(const QString &interface,
+ const QDBusIntrospection::Interface *parsedData);
+ void write(QDBusMetaObject *obj);
+ void writeWithoutXml(QDBusMetaObject *obj);
+
+private:
+ struct Method {
+ QByteArray parameters;
+ QByteArray typeName;
+ QByteArray tag;
+ QByteArray inputSignature;
+ QByteArray outputSignature;
+ QVarLengthArray<int, 4> inputTypes;
+ QVarLengthArray<int, 4> outputTypes;
+ int flags;
+ };
+
+ struct Property {
+ QByteArray typeName;
+ QByteArray signature;
+ int type;
+ int flags;
+ };
+
+ enum PropertyFlags {
+ Invalid = 0x00000000,
+ Readable = 0x00000001,
+ Writable = 0x00000002,
+ Resettable = 0x00000004,
+ EnumOrFlag = 0x00000008,
+ StdCppSet = 0x00000100,
+ // Override = 0x00000200,
+ Designable = 0x00001000,
+ ResolveDesignable = 0x00002000,
+ Scriptable = 0x00004000,
+ ResolveScriptable = 0x00008000,
+ Stored = 0x00010000,
+ ResolveStored = 0x00020000,
+ Editable = 0x00040000,
+ ResolveEditable = 0x00080000,
+ User = 0x00100000,
+ ResolveUser = 0x00200000
+ };
+
+ enum MethodFlags {
+ AccessPrivate = 0x00,
+ AccessProtected = 0x01,
+ AccessPublic = 0x02,
+ AccessMask = 0x03, //mask
+
+ MethodMethod = 0x00,
+ MethodSignal = 0x04,
+ MethodSlot = 0x08,
+ MethodTypeMask = 0x0c,
+
+ MethodCompatibility = 0x10,
+ MethodCloned = 0x20,
+ MethodScriptable = 0x40
+ };
+
+ QMap<QByteArray, Method> methods;
+ QMap<QByteArray, Property> properties;
+
+ const QDBusIntrospection::Interface *data;
+ QString interface;
+
+ void parseMethods();
+ void parseSignals();
+ void parseProperties();
+};
+
+static const int intsPerProperty = 2;
+static const int intsPerMethod = 4;
+
+// ### from kernel/qmetaobject.cpp (Qt 4.1.2):
+struct QDBusMetaObjectPrivate
+{
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ int enumeratorCount, enumeratorData;
+
+ // this is specific for QDBusMetaObject:
+ int propertyDBusData;
+ int methodDBusData;
+};
+
+QDBusMetaObjectGenerator::QDBusMetaObjectGenerator(const QString &interfaceName,
+ const QDBusIntrospection::Interface *parsedData)
+ : data(parsedData), interface(interfaceName)
+{
+ if (data) {
+ parseProperties();
+ parseSignals(); // call parseSignals first so that slots override signals
+ parseMethods();
+ }
+}
+
+void QDBusMetaObjectGenerator::parseMethods()
+{
+ foreach (const QDBusIntrospection::Method &m, data->methods) {
+ Method mm;
+
+ QByteArray prototype = m.name.toLatin1();
+ prototype += '(';
+
+ bool ok = true;
+
+ // build the input argument list
+ foreach (const QDBusIntrospection::Argument &arg, m.inputArgs) {
+ int typeId = QDBusUtil::signatureToType(arg.type);
+ if (typeId == QVariant::Invalid) {
+ ok = false;
+ break;
+ }
+
+ mm.inputSignature += arg.type;
+ mm.inputTypes.append(typeId);
+
+ mm.parameters.append(arg.name.toLatin1());
+ mm.parameters.append(',');
+
+ prototype.append( QVariant::typeToName( QVariant::Type(typeId) ) );
+ prototype.append(',');
+ }
+ if (!ok) continue;
+
+ // build the output argument list:
+ for (int i = 0; i < m.outputArgs.count(); ++i) {
+ const QDBusIntrospection::Argument &arg = m.outputArgs.at(i);
+
+ int typeId = QDBusUtil::signatureToType(arg.type);
+ if (typeId == QVariant::Invalid) {
+ ok = false;
+ break;
+ }
+
+ mm.outputSignature += arg.type;
+ mm.outputTypes.append(typeId);
+
+ if (i == 0) {
+ // return value
+ mm.typeName = QVariant::typeToName( QVariant::Type(typeId) );
+ } else {
+ // non-const ref parameter
+ mm.parameters.append(arg.name.toLatin1());
+ mm.parameters.append(',');
+
+ prototype.append( QVariant::typeToName( QVariant::Type(typeId) ) );
+ prototype.append("&,");
+ }
+ }
+ if (!ok) continue;
+
+ // convert the last commas:
+ if (!mm.parameters.isEmpty()) {
+ mm.parameters.truncate(mm.parameters.length() - 1);
+ prototype[prototype.length() - 1] = ')';
+ } else {
+ prototype.append(')');
+ }
+
+ // check the async tag
+ if (m.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true"))
+ mm.tag = "Q_ASYNC";
+
+ // meta method flags
+ mm.flags = AccessPublic | MethodSlot | MethodScriptable;
+
+ // add
+ methods.insert(QMetaObject::normalizedSignature(prototype), mm);
+ }
+}
+
+void QDBusMetaObjectGenerator::parseSignals()
+{
+ foreach (const QDBusIntrospection::Signal &s, data->signals_) {
+ Method mm;
+
+ QByteArray prototype = s.name.toLatin1();
+ prototype += '(';
+
+ bool ok = true;
+
+ // build the output argument list
+ foreach (const QDBusIntrospection::Argument &arg, s.outputArgs) {
+ int typeId = QDBusUtil::signatureToType(arg.type);
+ if (typeId == QVariant::Invalid) {
+ ok = false;
+ break;
+ }
+
+ mm.inputSignature += arg.type;
+ mm.inputTypes.append(typeId);
+
+ mm.parameters.append(arg.name.toLatin1());
+ mm.parameters.append(',');
+
+ prototype.append( QVariant::typeToName( QVariant::Type(typeId) ) );
+ prototype.append(',');
+ }
+ if (!ok) continue;
+
+ // convert the last commas:
+ if (!mm.parameters.isEmpty()) {
+ mm.parameters.truncate(mm.parameters.length() - 1);
+ prototype[prototype.length() - 1] = ')';
+ } else {
+ prototype.append(')');
+ }
+
+ // meta method flags
+ mm.flags = AccessProtected | MethodSignal | MethodScriptable;
+
+ // add
+ methods.insert(QMetaObject::normalizedSignature(prototype), mm);
+ }
+}
+
+void QDBusMetaObjectGenerator::parseProperties()
+{
+ foreach (const QDBusIntrospection::Property &p, data->properties) {
+ Property mp;
+ mp.type = QDBusUtil::signatureToType(p.type);
+ if (mp.type == QVariant::Invalid)
+ continue;
+
+ QByteArray name = p.name.toLatin1();
+ mp.signature = p.type.toLatin1();
+ mp.typeName = QVariant::typeToName( QVariant::Type(mp.type) );
+
+ // build the flags:
+ mp.flags = StdCppSet | Scriptable | Stored;
+ if (p.access != QDBusIntrospection::Property::Write)
+ mp.flags |= Readable;
+ if (p.access != QDBusIntrospection::Property::Read)
+ mp.flags |= Writable;
+
+ if (mp.typeName == "QVariant")
+ mp.flags |= 0xff << 24;
+ else if (mp.type < 0xff)
+ // encode the type in the flags
+ mp.flags |= mp.type << 24;
+
+ // add the property:
+ properties.insert(name, mp);
+ }
+}
+
+void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
+{
+ // this code here is mostly copied from qaxbase.cpp
+ // with a few modifications to make it cleaner
+
+ QString className = interface;
+ className.replace(QLatin1Char('.'), QLatin1String("::"));
+ if (className.isEmpty())
+ className = QLatin1String("QDBusInterface");
+
+ QVarLengthArray<int> data;
+ data.resize(sizeof(QDBusMetaObjectPrivate) / sizeof(int));
+
+ QDBusMetaObjectPrivate *header = reinterpret_cast<QDBusMetaObjectPrivate *>(data.data());
+ header->revision = 1;
+ header->className = 0;
+ header->classInfoCount = 0;
+ header->classInfoData = 0;
+ header->methodCount = methods.count();
+ header->methodData = data.size();
+ header->propertyCount = properties.count();
+ header->propertyData = header->methodData + header->methodCount * 5;
+ header->enumeratorCount = 0;
+ header->enumeratorData = 0;
+ header->propertyDBusData = header->propertyData + header->propertyCount * 3;
+ header->methodDBusData = header->propertyDBusData + header->propertyCount * intsPerProperty;
+
+ int data_size = data.size() +
+ (header->methodCount * (5+intsPerMethod)) +
+ (header->propertyCount * (3+intsPerProperty));
+ foreach (const Method &mm, methods)
+ data_size += 2 + mm.inputTypes.count() + mm.outputTypes.count();
+ data.resize(data_size + 1);
+
+ char null('\0');
+ QByteArray stringdata = className.toLatin1();
+ stringdata += null;
+ stringdata.reserve(8192);
+
+ int offset = header->methodData;
+ int signatureOffset = header->methodDBusData;
+ int typeidOffset = header->methodDBusData + header->methodCount * intsPerMethod;
+ data[typeidOffset++] = 0; // eod
+
+ // add each method:
+ for (QMap<QByteArray, Method>::ConstIterator it = methods.constBegin();
+ it != methods.constEnd(); ++it) {
+ // form "prototype\0parameters\0typeName\0tag\0inputSignature\0outputSignature"
+ const Method &mm = it.value();
+
+ data[offset++] = stringdata.length();
+ stringdata += it.key(); // prototype
+ stringdata += null;
+ data[offset++] = stringdata.length();
+ stringdata += mm.parameters;
+ stringdata += null;
+ data[offset++] = stringdata.length();
+ stringdata += mm.typeName;
+ stringdata += null;
+ data[offset++] = stringdata.length();
+ stringdata += mm.tag;
+ stringdata += null;
+ data[offset++] = mm.flags;
+
+ data[signatureOffset++] = stringdata.length();
+ stringdata += mm.inputSignature;
+ stringdata += null;
+ data[signatureOffset++] = stringdata.length();
+ stringdata += mm.outputSignature;
+ stringdata += null;
+
+ data[signatureOffset++] = typeidOffset;
+ data[typeidOffset++] = mm.inputTypes.count();
+ memcpy(data.data() + typeidOffset, mm.inputTypes.data(), mm.inputTypes.count() * sizeof(int));
+ typeidOffset += mm.inputTypes.count();
+
+ data[signatureOffset++] = typeidOffset;
+ data[typeidOffset++] = mm.outputTypes.count();
+ memcpy(data.data() + typeidOffset, mm.outputTypes.data(), mm.outputTypes.count() * sizeof(int));
+ typeidOffset += mm.outputTypes.count();
+ }
+
+ Q_ASSERT(offset == header->propertyData);
+ Q_ASSERT(signatureOffset == header->methodDBusData + header->methodCount * intsPerMethod);
+ Q_ASSERT(typeidOffset == data.size());
+
+ // add each property
+ signatureOffset = header->propertyDBusData;
+ for (QMap<QByteArray, Property>::ConstIterator it = properties.constBegin();
+ it != properties.constEnd(); ++it) {
+ const Property &mp = it.value();
+
+ // form is "name\0typeName\0signature\0"
+ data[offset++] = stringdata.length();
+ stringdata += it.key(); // name
+ stringdata += null;
+ data[offset++] = stringdata.length();
+ stringdata += mp.typeName;
+ stringdata += null;
+ data[offset++] = mp.flags;
+
+ data[signatureOffset++] = stringdata.length();
+ stringdata += mp.signature;
+ stringdata += null;
+ data[signatureOffset++] = mp.type;
+ }
+
+ Q_ASSERT(offset == header->propertyDBusData);
+ Q_ASSERT(signatureOffset == header->methodDBusData);
+
+ char *string_data = new char[stringdata.length()];
+ memcpy(string_data, stringdata, stringdata.length());
+
+ uint *uint_data = new uint[data.size()];
+ memcpy(uint_data, data.data(), data.size() * sizeof(int));
+
+ // put the metaobject together
+ obj->d.data = uint_data;
+ obj->d.extradata = 0;
+ obj->d.stringdata = string_data;
+ obj->d.superdata = &QDBusAbstractInterface::staticMetaObject;
+}
+
+#if 0
+void QDBusMetaObjectGenerator::writeWithoutXml(const QString &interface)
+{
+ // no XML definition
+ QString tmp(interface);
+ tmp.replace(QLatin1Char('.'), QLatin1String("::"));
+ QByteArray name(tmp.toLatin1());
+
+ QDBusMetaObjectPrivate *header = new QDBusMetaObjectPrivate;
+ memset(header, 0, sizeof *header);
+ header->revision = 1;
+ // leave the rest with 0
+
+ char *stringdata = new char[name.length() + 1];
+ stringdata[name.length()] = '\0';
+
+ d.data = reinterpret_cast<uint*>(header);
+ d.extradata = 0;
+ d.stringdata = stringdata;
+ d.superdata = &QDBusAbstractInterface::staticMetaObject;
+ cached = false;
+}
+#endif
+
+/////////
+// class QDBusMetaObject
+
+QDBusMetaObject *QDBusMetaObject::createMetaObject(const QString &interface, const QString &xml,
+ QHash<QString, QDBusMetaObject *> &cache,
+ QDBusError &error)
+{
+ error = QDBusError();
+ QDBusIntrospection::Interfaces parsed = QDBusIntrospection::parseInterfaces(xml);
+
+ QDBusMetaObject *we = 0;
+ QDBusIntrospection::Interfaces::ConstIterator it = parsed.constBegin();
+ QDBusIntrospection::Interfaces::ConstIterator end = parsed.constEnd();
+ for ( ; it != end; ++it) {
+ // check if it's in the cache
+ QDBusMetaObject *obj = cache.value(it.key(), 0);
+ if (!obj) {
+ // not in cache; create
+ obj = new QDBusMetaObject;
+ QDBusMetaObjectGenerator generator(it.key(), it.value().constData());
+ generator.write(obj);
+
+ if ( (obj->cached = !it.key().startsWith( QLatin1String("local.") )) )
+ // cache it
+ cache.insert(it.key(), obj);
+
+ }
+
+ if (it.key() == interface)
+ // it's us
+ we = obj;
+ }
+
+ if (we)
+ return we;
+ // still nothing?
+
+ if (parsed.isEmpty()) {
+ // object didn't return introspection
+ we = new QDBusMetaObject;
+ QDBusMetaObjectGenerator generator(interface, 0);
+ generator.write(we);
+ we->cached = false;
+ return we;
+ } else if (interface.isEmpty()) {
+ // merge all interfaces
+ it = parsed.constBegin();
+ QDBusIntrospection::Interface merged = *it.value().constData();
+
+ for (++it; it != end; ++it) {
+ merged.annotations.unite(it.value()->annotations);
+ merged.methods.unite(it.value()->methods);
+ merged.signals_.unite(it.value()->signals_);
+ merged.properties.unite(it.value()->properties);
+ }
+
+ merged.name = QLatin1String("local.Merged");
+ merged.introspection.clear();
+
+ we = new QDBusMetaObject;
+ QDBusMetaObjectGenerator generator(merged.name, &merged);
+ generator.write(we);
+ we->cached = false;
+ return we;
+ }
+
+ // mark as an error
+ error = QDBusError(QDBusError::UnknownInterface,
+ QString( QLatin1String("Interface '%1' was not found") )
+ .arg(interface));
+ return 0;
+}
+
+QDBusMetaObject::QDBusMetaObject()
+{
+}
+
+inline const QDBusMetaObjectPrivate *priv(const uint* data)
+{
+ return reinterpret_cast<const QDBusMetaObjectPrivate *>(data);
+}
+
+const char *QDBusMetaObject::dbusNameForMethod(int id) const
+{
+ //id -= methodOffset();
+ if (id >= 0 && id < priv(d.data)->methodCount) {
+ int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
+ return d.stringdata + d.data[handle];
+ }
+ return 0;
+}
+
+const char *QDBusMetaObject::inputSignatureForMethod(int id) const
+{
+ //id -= methodOffset();
+ if (id >= 0 && id < priv(d.data)->methodCount) {
+ int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
+ return d.stringdata + d.data[handle + 1];
+ }
+ return 0;
+}
+
+const char *QDBusMetaObject::outputSignatureForMethod(int id) const
+{
+ //id -= methodOffset();
+ if (id >= 0 && id < priv(d.data)->methodCount) {
+ int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
+ return d.stringdata + d.data[handle + 2];
+ }
+ return 0;
+}
+
+const int *QDBusMetaObject::inputTypesForMethod(int id) const
+{
+ //id -= methodOffset();
+ if (id >= 0 && id < priv(d.data)->methodCount) {
+ int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
+ return reinterpret_cast<const int*>(d.data + d.data[handle + 3]);
+ }
+ return 0;
+}
+
+const int *QDBusMetaObject::outputTypesForMethod(int id) const
+{
+ //id -= methodOffset();
+ if (id >= 0 && id < priv(d.data)->methodCount) {
+ int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
+ return reinterpret_cast<const int*>(d.data + d.data[handle + 4]);
+ }
+ return 0;
+}
+
+int QDBusMetaObject::propertyMetaType(int id) const
+{
+ //id -= propertyOffset();
+ if (id >= 0 && id < priv(d.data)->propertyCount) {
+ int handle = priv(d.data)->propertyDBusData + id*intsPerProperty;
+ return d.data[handle + 1];
+ }
+ return 0;
+}
+
+template<typename T>
+static inline void assign_helper(void *ptr, const QVariant &value)
+{
+ *reinterpret_cast<T *>(ptr) = qvariant_cast<T>(value);
+}
+
+void QDBusMetaObject::assign(void *ptr, const QVariant &value)
+{
+ switch (value.userType())
+ {
+ case QVariant::Bool:
+ assign_helper<bool>(ptr, value);
+ return;
+
+ case QMetaType::UChar:
+ assign_helper<uchar>(ptr, value);
+ return;
+
+ case QMetaType::Short:
+ assign_helper<short>(ptr, value);
+ return;
+
+ case QMetaType::UShort:
+ assign_helper<ushort>(ptr, value);
+ return;
+
+ case QVariant::Int:
+ assign_helper<int>(ptr, value);
+ return;
+
+ case QVariant::UInt:
+ assign_helper<uint>(ptr, value);
+ return;
+
+ case QVariant::LongLong:
+ assign_helper<qlonglong>(ptr, value);
+ return;
+
+ case QVariant::ULongLong:
+ assign_helper<qulonglong>(ptr, value);
+ return;
+
+ case QVariant::Double:
+ assign_helper<double>(ptr, value);
+ return;
+
+ case QVariant::String:
+ assign_helper<QString>(ptr, value);
+ return;
+
+ case QVariant::ByteArray:
+ assign_helper<QByteArray>(ptr, value);
+ return;
+
+ case QVariant::List:
+ assign_helper<QVariantList>(ptr, value);
+ return;
+
+ case QVariant::Map:
+ assign_helper<QVariantMap>(ptr, value);
+ return;
+
+ default:
+ ;
+ }
+}
+
+bool QDBusMetaTypeId::initialized = false;
+int QDBusMetaTypeId::variant = 0;
+int QDBusMetaTypeId::boollist = 0;
+int QDBusMetaTypeId::shortlist = 0;
+int QDBusMetaTypeId::ushortlist = 0;
+int QDBusMetaTypeId::intlist = 0;
+int QDBusMetaTypeId::uintlist = 0;
+int QDBusMetaTypeId::longlonglist = 0;
+int QDBusMetaTypeId::ulonglonglist = 0;
+int QDBusMetaTypeId::doublelist = 0;
+
+bool QDBusMetaTypeId::innerInitialize()
+{
+ variant = qRegisterMetaType<QVariant>("QVariant");
+ boollist = qRegisterMetaType<QList<bool> >("QList<bool>");
+ shortlist = qRegisterMetaType<QList<short> >("QList<short>");
+ ushortlist = qRegisterMetaType<QList<ushort> >("QList<ushort>");
+ intlist = qRegisterMetaType<QList<int> >("QList<int>");
+ uintlist = qRegisterMetaType<QList<uint> >("QList<uint>");
+ longlonglist = qRegisterMetaType<QList<qlonglong> >("QList<qlonglong>");
+ ulonglonglist = qRegisterMetaType<QList<qulonglong> >("QList<qulonglong>");
+ doublelist = qRegisterMetaType<QList<double> >("QList<double>");
+ initialized = true;
+ return true;
+}
+
+int qDBusMetaTypeId(QVariant *)
+{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::variant; }
+int qDBusMetaTypeId(QList<bool> *)
+{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::boollist; }
+int qDBusMetaTypeId(QList<short> *)
+{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::shortlist; }
+int qDBusMetaTypeId(QList<ushort> *)
+{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::ushortlist; }
+int qDBusMetaTypeId(QList<int> *)
+{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::intlist; }
+int qDBusMetaTypeId(QList<uint> *)
+{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::uintlist; }
+int qDBusMetaTypeId(QList<qlonglong> *)
+{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::longlonglist; }
+int qDBusMetaTypeId(QList<qulonglong> *)
+{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::ulonglonglist; }
+int qDBusMetaTypeId(QList<double> *)
+{ QDBusMetaTypeId::initialize(); return QDBusMetaTypeId::doublelist; }
diff --git a/qt/src/qdbusmetaobject_p.h b/qt/src/qdbusmetaobject_p.h
new file mode 100644
index 00000000..746240d1
--- /dev/null
+++ b/qt/src/qdbusmetaobject_p.h
@@ -0,0 +1,96 @@
+/*
+ *
+ * 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 QDBUSMETAOBJECTPRIVATE_H
+#define QDBUSMETAOBJECTPRIVATE_H
+
+#include <QtCore/qmetaobject.h>
+#include "qdbusmacros.h"
+
+class QDBusError;
+
+struct QDBusMetaObjectPrivate;
+struct QDBUS_EXPORT QDBusMetaObject: public QMetaObject
+{
+ bool cached;
+
+ static QDBusMetaObject *createMetaObject(const QString &interface, const QString &xml,
+ QHash<QString, QDBusMetaObject *> &map,
+ QDBusError &error);
+ ~QDBusMetaObject()
+ {
+ delete [] d.stringdata;
+ delete [] d.data;
+ }
+
+ // methods (slots & signals):
+ const char *dbusNameForMethod(int id) const;
+ const char *inputSignatureForMethod(int id) const;
+ const char *outputSignatureForMethod(int id) const;
+ const int *inputTypesForMethod(int id) const;
+ const int *outputTypesForMethod(int id) const;
+
+ // properties:
+ int propertyMetaType(int id) const;
+
+ // helper function:
+ static void assign(void *, const QVariant &value);
+
+private:
+ QDBusMetaObject();
+};
+
+struct QDBusMetaTypeId
+{
+ static bool innerInitialize();
+ static bool initialized;
+ static inline void initialize()
+ {
+ if (initialized) return;
+ innerInitialize();
+ }
+
+ static int variant;
+ static int boollist;
+ static int shortlist;
+ static int ushortlist;
+ static int intlist;
+ static int uintlist;
+ static int longlonglist;
+ static int ulonglonglist;
+ static int doublelist;
+};
+
+#endif
diff --git a/qt/src/qdbusmisc.cpp b/qt/src/qdbusmisc.cpp
new file mode 100644
index 00000000..9aaf9f24
--- /dev/null
+++ b/qt/src/qdbusmisc.cpp
@@ -0,0 +1,156 @@
+/* qdbusmisc.cpp Miscellaneous routines that didn't fit anywhere else
+ *
+ * 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 <string.h>
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qmetaobject.h>
+
+#include "qdbusconnection_p.h"
+#include "qdbustypehelper_p.h"
+
+bool qDBusCheckAsyncTag(const char *tag)
+{
+ if (!tag || !*tag)
+ return false;
+
+ const char *p = strstr(tag, "async");
+ if (p != NULL &&
+ (p == tag || *(p-1) == ' ') &&
+ (p[5] == '\0' || p[5] == ' '))
+ return true;
+
+ p = strstr(tag, "Q_ASYNC");
+ if (p != NULL &&
+ (p == tag || *(p-1) == ' ') &&
+ (p[7] == '\0' || p[7] == ' '))
+ return true;
+
+ return false;
+}
+
+int qDBusNameToTypeId(const char *name)
+{
+ int id = static_cast<int>( QVariant::nameToType(name) );
+ if (id == QVariant::UserType)
+ id = QMetaType::type(name);
+
+ switch (id) {
+ case QVariant::Bool:
+ case QVariant::Int:
+ case QVariant::UInt:
+ case QVariant::Char:
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ case QMetaType::UChar:
+ case QVariant::LongLong:
+ case QVariant::ULongLong:
+ case QVariant::Double:
+ case QVariant::String:
+ case QVariant::Date:
+ case QVariant::Time:
+ case QVariant::DateTime:
+ case QVariant::Map:
+ case QVariant::StringList:
+ case QVariant::ByteArray:
+ case QVariant::List:
+ return id;
+
+ default:
+ if (id == QDBusConnectionPrivate::registerMessageMetaType() ||
+ id == QDBusTypeHelper<QVariant>::id() ||
+ id == QDBusTypeHelper<bool>::listId() ||
+ id == QDBusTypeHelper<short>::listId() ||
+ id == QDBusTypeHelper<ushort>::listId() ||
+ id == QDBusTypeHelper<int>::listId() ||
+ id == QDBusTypeHelper<qlonglong>::listId() ||
+ id == QDBusTypeHelper<qulonglong>::listId() ||
+ id == QDBusTypeHelper<double>::listId())
+ return id;
+
+ return 0; // invalid
+ }
+}
+
+// calculates the metatypes for the method
+// the slot must have the parameters in the following form:
+// - zero or more value or const-ref parameters of any kind
+// - zero or one const ref of QDBusMessage
+// - zero or more non-const ref parameters
+// No parameter may be a template.
+// this function returns -1 if the parameters don't match the above form
+// this function returns the number of *input* parameters, including the QDBusMessage one if any
+// this function does not check the return type, so metaTypes[0] is always 0 and always present
+// metaTypes.count() >= retval + 1 in all cases
+//
+// sig must be the normalised signature for the method
+int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes)
+{
+ QList<QByteArray> parameterTypes = mm.parameterTypes();
+ metaTypes.clear();
+
+ metaTypes.append(0); // return type
+ int inputCount = 0;
+ bool seenMessage = false;
+ foreach (QByteArray type, parameterTypes) {
+ if (type.endsWith('*')) {
+ //qWarning("Could not parse the method '%s'", mm.signature());
+ // pointer?
+ return -1;
+ }
+
+ if (type.endsWith('&')) {
+ type.truncate(type.length() - 1);
+ int id = qDBusNameToTypeId(type);
+ if (id == 0) {
+ //qWarning("Could not parse the method '%s'", mm.signature());
+ // invalid type in method parameter list
+ return -1;
+ }
+
+ metaTypes.append( id );
+ seenMessage = true; // it cannot appear anymore anyways
+ continue;
+ }
+
+ if (seenMessage) { // && !type.endsWith('&')
+ //qWarning("Could not parse the method '%s'", mm.signature());
+ // non-output parameters after message or after output params
+ return -1; // not allowed
+ }
+
+ int id = qDBusNameToTypeId(type);
+ if (id == 0) {
+ //qWarning("Could not parse the method '%s'", mm.signature());
+ // invalid type in method parameter list
+ return -1;
+ }
+ metaTypes.append(id);
+ ++inputCount;
+
+ if (id == QDBusConnectionPrivate::registerMessageMetaType())
+ seenMessage = true;
+ }
+
+ return inputCount;
+}
diff --git a/qt/src/qdbusreply.h b/qt/src/qdbusreply.h
new file mode 100644
index 00000000..0b5c12d9
--- /dev/null
+++ b/qt/src/qdbusreply.h
@@ -0,0 +1,132 @@
+/* qdbusreply.h QDBusReply object - a reply from D-Bus
+ *
+ * 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 QDBUSREPLY_H
+#define QDBUSREPLY_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qvariant.h>
+
+#include "qdbusmacros.h"
+#include "qdbusmessage.h"
+#include "qdbuserror.h"
+
+#include "qdbustypehelper_p.h"
+
+template<typename T>
+class QDBusReply
+{
+ typedef T Type;
+public:
+ inline QDBusReply(const QDBusMessage &reply)
+ : m_data(Type())
+ {
+ *this = reply;
+ }
+ inline QDBusReply& operator=(const QDBusMessage& reply)
+ {
+ m_error = reply;
+ if (isSuccess())
+ m_data = QDBusTypeHelper<Type>::fromVariant(reply.at(0));
+ else
+ m_data = Type();
+ return *this;
+ }
+
+ inline QDBusReply(const QDBusError &error = QDBusError())
+ : m_error(error), m_data(Type())
+ {
+ }
+ inline QDBusReply& operator=(const QDBusError& error)
+ {
+ m_error = error;
+ m_data = Type();
+ return *this;
+ }
+
+ inline QDBusReply& operator=(const QDBusReply& other)
+ {
+ m_error = other.m_error;
+ m_data = other.m_data;
+ return *this;
+ }
+
+ inline bool isError() const { return m_error.isValid(); }
+ inline bool isSuccess() const { return !m_error.isValid(); }
+
+ inline const QDBusError& error() { return m_error; }
+
+ inline Type value()
+ {
+ return m_data;
+ }
+
+ inline operator Type ()
+ {
+ return m_data;
+ }
+
+ static QDBusReply<T> fromVariant(const QDBusReply<QVariant> &variantReply)
+ {
+ QDBusReply<T> retval;
+ retval.m_error = variantReply.m_error;
+ if (retval.isSuccess()) {
+ retval.m_data = qvariant_cast<Type>(variantReply.m_data);
+ if (!qVariantCanConvert<Type>(variantReply.m_data))
+ retval.m_error = QDBusError(QDBusError::InvalidSignature,
+ QLatin1String("Unexpected reply signature"));
+ }
+ return retval;
+ }
+
+private:
+ QDBusError m_error;
+ Type m_data;
+};
+
+# ifndef Q_QDOC
+// specialize for void:
+template<>
+class QDBUS_EXPORT QDBusReply<void>
+{
+public:
+ inline QDBusReply(const QDBusMessage &reply)
+ : m_error(reply)
+ {
+ }
+ inline QDBusReply(const QDBusError &error)
+ : m_error(error)
+ {
+ }
+
+ inline bool isError() const { return m_error.isValid(); }
+ inline bool isSuccess() const { return !m_error.isValid(); }
+
+ inline const QDBusError& error() { return m_error; }
+
+private:
+ QDBusError m_error;
+};
+# endif
+
+#endif
diff --git a/qt/src/qdbusserver.cpp b/qt/src/qdbusserver.cpp
new file mode 100644
index 00000000..b3b9835e
--- /dev/null
+++ b/qt/src/qdbusserver.cpp
@@ -0,0 +1,61 @@
+/* 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
+ *
+ * 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 "qdbusserver.h"
+#include "qdbusconnection_p.h"
+
+QDBusServer::QDBusServer(const QString &addr, QObject *parent)
+ : QObject(parent)
+{
+ d = new QDBusConnectionPrivate(this);
+
+ if (addr.isEmpty())
+ return;
+
+ d->setServer(dbus_server_listen(addr.toUtf8().constData(), &d->error));
+}
+
+bool QDBusServer::isConnected() const
+{
+ return d->server && dbus_server_get_is_connected(d->server);
+}
+
+QDBusError QDBusServer::lastError() const
+{
+ return d->lastError;
+}
+
+QString QDBusServer::address() const
+{
+ QString addr;
+ if (d->server) {
+ char *c = dbus_server_get_address(d->server);
+ addr = QString::fromUtf8(c);
+ dbus_free(c);
+ }
+
+ return addr;
+}
+
+#include "qdbusserver.moc"
diff --git a/qt/src/qdbusserver.h b/qt/src/qdbusserver.h
new file mode 100644
index 00000000..55607860
--- /dev/null
+++ b/qt/src/qdbusserver.h
@@ -0,0 +1,48 @@
+/* qdbusserver.h QDBusServer 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 QDBUSSERVER_H
+#define QDBUSSERVER_H
+
+#include "qdbusmacros.h"
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+
+class QDBusConnectionPrivate;
+class QDBusError;
+
+class QDBUS_EXPORT QDBusServer: public QObject
+{
+ Q_OBJECT
+public:
+ QDBusServer(const QString &address, QObject *parent = 0);
+
+ bool isConnected() const;
+ QDBusError lastError() const;
+ QString address() const;
+
+private:
+ Q_DISABLE_COPY(QDBusServer)
+ QDBusConnectionPrivate *d;
+};
+
+#endif
diff --git a/qt/src/qdbusthread.cpp b/qt/src/qdbusthread.cpp
new file mode 100644
index 00000000..f45a0096
--- /dev/null
+++ b/qt/src/qdbusthread.cpp
@@ -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;
+}
+
+
diff --git a/qt/src/qdbustype.cpp b/qt/src/qdbustype.cpp
new file mode 100644
index 00000000..7f17a372
--- /dev/null
+++ b/qt/src/qdbustype.cpp
@@ -0,0 +1,847 @@
+/* -*- 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 "qdbustype_p.h"
+#include "qdbustypehelper_p.h"
+#include <dbus/dbus.h>
+
+#include <QtCore/qstringlist.h>
+
+class QDBusTypePrivate: public QSharedData
+{
+public:
+ int code;
+ mutable int qvariantType;
+ mutable QByteArray signature;
+ QDBusTypeList subTypes;
+
+ inline QDBusTypePrivate()
+ : code(0), qvariantType(QVariant::Invalid)
+ { }
+};
+
+/*!
+ \class QDBusType
+ \brief Represents one single D-Bus type.
+ \internal
+
+ D-Bus provides a set of primitive types that map to normal, C++ types and to QString, as well as
+ the possibility to extend the set with the so-called "container" types. The available types are
+ as follows:
+
+ - Primitive (or basic): integers of 16, 32 and 64 bits, both signed and unsigned; byte (8 bits);
+ double-precision floating point and Unicode strings
+ - Arrays: a homogeneous, ordered list of zero or more entries
+ - Maps: an unordered list of (key, value) pairs, where key must be a primitive type and value
+ can be any D-Bus type
+ - Structs: an ordered list of a fixed number of entries of any type
+ - Variants: a "wildcard" container that can assume the value of any other type, including
+ structs and arrays
+
+ Any type can be placed inside an array (including other arrays), but only entries of the same
+ type can be placed inside the same array. The analogous type for D-Bus arrays are the Qt
+ #QList template classes.
+
+ Structs have a fixed number of entries and each entry has a fixed type. They are analogous to C
+ and C++ structs (hence the name).
+
+ Maps or dictionaries are analogous to the Qt #QMap template class, with the additional
+ restriction that the key type must be a primitive one. D-Bus implements maps by using arrays of
+ a special type (a "dictionary entry"), so inspecting a QDBusType of a Map will reveal that it is
+ an array (see isArray()).
+
+ Variants contain exactly one entry, but the type can vary freely. It is analogous to the Qt
+ class #QVariant, but the QtDBus implementation uses #QDBusVariant to represent D-Bus Variants.
+*/
+
+/*!
+ Constructs an empty (invalid) type.
+*/
+QDBusType::QDBusType()
+ : d(0)
+{
+}
+
+/*!
+ Constructs the type based on the D-Bus type given by \a type.
+*/
+QDBusType::QDBusType(int type)
+{
+ char c[2] = { type, 0 };
+ *this = QDBusType(c);
+}
+
+/*!
+ Constructs the type based on the QVariant type given by \a type.
+
+ \sa QVariant::Type
+*/
+QDBusType::QDBusType(QVariant::Type type)
+{
+ const char *sig = dbusSignature(type);
+
+ // it never returns NULL
+ // but it may return an empty string:
+ if (sig[0] == '\0')
+ return;
+
+ if (qstrlen(sig) > 2) {
+ *this = QDBusType(sig);
+ } else {
+ d = new QDBusTypePrivate;
+ d->qvariantType = type;
+ d->code = sig[0];
+ if (sig[1] == '\0')
+ // single-letter type
+ return;
+ else {
+ // two-letter type
+ // must be an array
+ d->code = sig[0];
+ QDBusType t;
+ t.d = new QDBusTypePrivate;
+ t.d->code = sig[1];
+ d->subTypes << t;
+ }
+ }
+}
+
+/*!
+ Parses the D-Bus signature given by \a signature and constructs the type it represents.
+*/
+QDBusType::QDBusType(const char* signature)
+{
+ if ( !dbus_signature_validate_single(signature, 0) )
+ return;
+
+ DBusSignatureIter iter;
+ dbus_signature_iter_init(&iter, signature);
+ *this = QDBusType(&iter);
+ if (d)
+ d->signature = signature;
+}
+
+/*!
+ \overload
+ Parses the D-Bus signature given by \a str and constructs the type it represents.
+*/
+QDBusType::QDBusType(const QString& str)
+{
+ *this = QDBusType( str.toUtf8().constData() );
+}
+
+/*!
+ \overload
+ Parses the D-Bus signature given by \a str and constructs the type it represents.
+*/
+QDBusType::QDBusType(const QByteArray& str)
+{
+ *this = QDBusType( str.constData() );
+}
+
+/*!
+ \internal
+ Creates a QDBusType object based on the current element pointed to by \a iter.
+*/
+QDBusType::QDBusType(DBusSignatureIter* iter)
+ : d(new QDBusTypePrivate)
+{
+ if ( dbus_type_is_container( d->code = dbus_signature_iter_get_current_type(iter) ) ) {
+ // we have to recurse
+ if ( d->code == DBUS_TYPE_VARIANT )
+ return; // no we don't. dbus_type_is_container lies to us
+
+ // we have to recurse
+ DBusSignatureIter subiter;
+ dbus_signature_iter_recurse(iter, &subiter);
+
+ d->subTypes = QDBusTypeList(&subiter);
+
+ // sanity checking:
+ if ( d->code == DBUS_TYPE_ARRAY )
+ Q_ASSERT_X(d->subTypes.size() == 1, "QDBusType",
+ "more than one element in array");
+ else if (d->code == DBUS_TYPE_DICT_ENTRY )
+ Q_ASSERT_X(d->subTypes.size() == 2, "QDBusType",
+ "maps must have exactly two elements");
+ }
+}
+
+/*!
+ Copies the type from the object \a other.
+*/
+QDBusType::QDBusType(const QDBusType& other)
+ : d(other.d)
+{
+}
+
+/*!
+ Release the resources associated with this type.
+*/
+QDBusType::~QDBusType()
+{
+}
+
+/*!
+ Copies the type from the object given by \a other.
+*/
+QDBusType& QDBusType::operator=(const QDBusType& other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Returns the DBus type for this type.
+*/
+int QDBusType::dbusType() const
+{
+ return d ? d->code : DBUS_TYPE_INVALID;
+}
+
+/*!
+ Returns the DBus signature for this type and subtypes.
+*/
+QByteArray QDBusType::dbusSignature() const
+{
+ if (!d)
+ return QByteArray();
+
+ if (!d->signature.isEmpty())
+ return d->signature;
+
+ if (d->subTypes.isEmpty())
+ return d->signature = QByteArray(1, d->code);
+
+ QByteArray retval;
+ switch (d->code) {
+ // can only be array, map or struct
+
+ case DBUS_TYPE_ARRAY:
+ Q_ASSERT_X(d->subTypes.size() == 1, "QDBusType::dbusSignature",
+ "more than one element in array");
+
+ retval += DBUS_TYPE_ARRAY;
+ retval += d->subTypes.at(0).dbusSignature();
+ break;
+
+ case DBUS_TYPE_DICT_ENTRY: {
+ Q_ASSERT_X(d->subTypes.size() == 2, "QDBusType::dbusSignature",
+ "maps must have exactly two elements");
+
+ QByteArray value = d->subTypes.at(1).dbusSignature();
+ char key = d->subTypes.at(0).dbusType();
+
+ Q_ASSERT(key != DBUS_TYPE_INVALID);
+ Q_ASSERT(!value.isEmpty());
+
+ retval.reserve(value.length() + 3);
+ retval = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING;
+ retval += key;
+ retval += value;
+ retval += DBUS_DICT_ENTRY_END_CHAR;
+ break;
+ }
+
+ case DBUS_TYPE_STRUCT:
+ retval = d->subTypes.dbusSignature();
+ retval.prepend(DBUS_STRUCT_BEGIN_CHAR);
+ retval.append(DBUS_STRUCT_END_CHAR);
+ break;
+
+ default:
+ Q_ASSERT_X(false, "QDBusType::dbusSignature", "invalid container type");
+ }
+
+ d->signature = retval;
+ return retval;
+}
+
+/*!
+ Returns the QVariant::Type for this entry.
+*/
+int QDBusType::qvariantType() const
+{
+ if (d && d->qvariantType != QVariant::Invalid)
+ return d->qvariantType;
+
+ if (!d)
+ return QVariant::Invalid;
+
+ return d->qvariantType = qvariantType(dbusSignature().constData());
+}
+
+/*!
+ Returns true if this type is a valid one.
+*/
+bool QDBusType::isValid() const
+{
+ return d && d->code != DBUS_TYPE_INVALID;
+}
+
+/*!
+ Returns true if this type is a basic one.
+*/
+bool QDBusType::isBasic() const
+{
+ return d && dbus_type_is_basic(d->code);
+}
+
+/*!
+ Returns true if this type is a container.
+*/
+bool QDBusType::isContainer() const
+{
+ return d && dbus_type_is_container(d->code);
+}
+
+/*!
+ Returns the subtypes of this type, if this is a container.
+
+ \sa isContainer()
+*/
+QDBusTypeList QDBusType::subTypes() const
+{
+ if (d)
+ return d->subTypes;
+ return QDBusTypeList();
+}
+
+/*!
+ Returns true if this type is an array.
+
+ \sa isContainer(), arrayElement()
+*/
+bool QDBusType::isArray() const
+{
+ return dbusType() == DBUS_TYPE_ARRAY;
+}
+
+/*!
+ This is a convenience function that returns the element type of an array.
+ If this object is not an array, it returns an invalid QDBusType.
+
+ \sa isArray()
+*/
+QDBusType QDBusType::arrayElement() const
+{
+ if (isArray() && d->subTypes.count() == 1)
+ return d->subTypes.first();
+ return QDBusType();
+}
+
+/*!
+ Returns true if this type is a map (i.e., an array of dictionary entries).
+
+ \sa isContainer(), isArray(), arrayElement()
+*/
+bool QDBusType::isMap() const
+{
+ return arrayElement().dbusType() == DBUS_TYPE_DICT_ENTRY;
+}
+
+/*!
+ If this object is a map, returns the (basic) type that corresponds to the key type.
+ If this object is not a map, returns an invalid QDBusType.
+
+ \sa isMap()
+*/
+QDBusType QDBusType::mapKey() const
+{
+ if (isMap())
+ return arrayElement().d->subTypes.first();
+ return QDBusType();
+}
+
+/*!
+ If this object is a map, returns the type that corresponds to the value type.
+ If this object is not a map, returns an invalid QDBusType.
+
+ \sa isMap()
+*/
+QDBusType QDBusType::mapValue() const
+{
+ if (isMap())
+ return arrayElement().d->subTypes.at(1);
+ return QDBusType();
+}
+
+/*!
+ Returns true if this type is the same one as \a other.
+*/
+bool QDBusType::operator==(const QDBusType& other) const
+{
+ if (!d && !other.d)
+ return true;
+ if (!d || !other.d)
+ return false;
+ return d->code == other.d->code && d->subTypes == other.d->subTypes;
+}
+
+/*!
+ \fn QDBusType::operator!=(const QDBusType &other) const
+ Returns true if the this type and the one given by \a other are different.
+*/
+
+/*!
+ Converts the DBus type code \a type to QVariant::Type.
+*/
+int QDBusType::qvariantType(int type)
+{
+ char c[2] = { type, 0 };
+ return qvariantType(c);
+}
+
+/*!
+ Converts the DBus type signature \a signature to QVariant::Type.
+*/
+int QDBusType::qvariantType(const char* signature)
+{
+ if (!signature)
+ return QVariant::Invalid;
+
+ // three special cases that don't validate as single:
+ if (qstrlen(signature) == 1) {
+ if (signature[0] == DBUS_TYPE_STRUCT)
+ return QVariant::List;
+ else if (signature[0] == DBUS_TYPE_DICT_ENTRY)
+ return QVariant::Map;
+ else if (signature[0] == DBUS_TYPE_ARRAY)
+ return QVariant::List;
+ }
+
+ // now we can validate
+ if ( !dbus_signature_validate_single(signature, 0) )
+ return QVariant::Invalid;
+
+ switch (signature[0])
+ {
+ case DBUS_TYPE_BOOLEAN:
+ return QVariant::Bool;
+
+ case DBUS_TYPE_BYTE:
+ return QMetaType::UChar;
+
+ case DBUS_TYPE_INT16:
+ return QMetaType::Short;
+
+ case DBUS_TYPE_UINT16:
+ return QMetaType::UShort;
+
+ case DBUS_TYPE_INT32:
+ return QVariant::Int;
+
+ case DBUS_TYPE_UINT32:
+ return QVariant::UInt;
+
+ case DBUS_TYPE_INT64:
+ return QVariant::LongLong;
+
+ case DBUS_TYPE_UINT64:
+ return QVariant::ULongLong;
+
+ case DBUS_TYPE_DOUBLE:
+ return QVariant::Double;
+
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ return QVariant::String;
+
+ case DBUS_STRUCT_BEGIN_CHAR:
+ return QVariant::List; // change to QDBusStruct in the future
+
+ case DBUS_TYPE_VARIANT:
+ return QDBusTypeHelper<QVariant>::id();
+
+ case DBUS_TYPE_ARRAY: // special case
+ switch (signature[1]) {
+ case DBUS_TYPE_BOOLEAN:
+ return QDBusTypeHelper<bool>::listId();
+
+ case DBUS_TYPE_BYTE:
+ return QVariant::ByteArray;
+
+ case DBUS_TYPE_INT16:
+ return QDBusTypeHelper<short>::listId();
+
+ case DBUS_TYPE_UINT16:
+ return QDBusTypeHelper<ushort>::listId();
+
+ case DBUS_TYPE_INT32:
+ return QDBusTypeHelper<int>::listId();
+
+ case DBUS_TYPE_UINT32:
+ return QDBusTypeHelper<uint>::listId();
+
+ case DBUS_TYPE_INT64:
+ return QDBusTypeHelper<qlonglong>::listId();
+
+ case DBUS_TYPE_UINT64:
+ return QDBusTypeHelper<qulonglong>::listId();
+
+ case DBUS_TYPE_DOUBLE:
+ return QDBusTypeHelper<double>::listId();
+
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ return QVariant::StringList;
+
+ case DBUS_TYPE_VARIANT:
+ return QVariant::List;
+
+ case DBUS_DICT_ENTRY_BEGIN_CHAR:
+ return QVariant::Map;
+
+ default:
+ return QVariant::List;
+ }
+ default:
+ return QVariant::Invalid;
+
+ }
+}
+
+/*!
+ Converts the QVariant::Type \a t to a DBus type code.
+*/
+int QDBusType::dbusType(QVariant::Type t)
+{
+ switch (t)
+ {
+ case QVariant::Bool:
+ return DBUS_TYPE_BOOLEAN;
+
+ case QVariant::Int:
+ return DBUS_TYPE_INT32;
+
+ case QVariant::UInt:
+ return DBUS_TYPE_UINT32;
+
+ case QVariant::LongLong:
+ return DBUS_TYPE_INT64;
+
+ case QVariant::ULongLong:
+ return DBUS_TYPE_UINT64;
+
+ case QVariant::Double:
+ return DBUS_TYPE_DOUBLE;
+
+ // from QMetaType:
+ case QMetaType::Short:
+ return DBUS_TYPE_INT16;
+
+ case QMetaType::UShort:
+ return DBUS_TYPE_UINT16;
+
+ case QMetaType::UChar:
+ return DBUS_TYPE_BYTE;
+
+ case QVariant::String:
+ return DBUS_TYPE_STRING;
+
+ case QVariant::Map:
+ // internal type information has been lost
+ return DBUS_TYPE_DICT_ENTRY;
+
+ case QVariant::List:
+ case QVariant::StringList:
+ case QVariant::ByteArray:
+ // could also be a struct...
+ return DBUS_TYPE_ARRAY;
+
+ case QVariant::UserType:
+ return DBUS_TYPE_INVALID; // invalid
+
+ default:
+ break; // avoid compiler warnings
+ }
+
+ if (int(t) == QDBusTypeHelper<QVariant>::id())
+ return DBUS_TYPE_VARIANT;
+
+ return DBUS_TYPE_INVALID;
+}
+
+/*!
+ Converts the QVariant::Type \a t to a DBus type signature.
+*/
+const char* QDBusType::dbusSignature(QVariant::Type t)
+{
+ switch (t)
+ {
+ case QVariant::Bool:
+ return DBUS_TYPE_BOOLEAN_AS_STRING;
+
+ case QVariant::Int:
+ return DBUS_TYPE_INT32_AS_STRING;
+
+ case QVariant::UInt:
+ return DBUS_TYPE_UINT32_AS_STRING;
+
+ case QMetaType::Short:
+ return DBUS_TYPE_INT16_AS_STRING;
+
+ case QMetaType::UShort:
+ return DBUS_TYPE_UINT16_AS_STRING;
+
+ case QMetaType::UChar:
+ return DBUS_TYPE_BYTE_AS_STRING;
+
+ case QVariant::LongLong:
+ return DBUS_TYPE_INT64_AS_STRING;
+
+ case QVariant::ULongLong:
+ return DBUS_TYPE_UINT64_AS_STRING;
+
+ case QVariant::Double:
+ return DBUS_TYPE_DOUBLE_AS_STRING;
+
+ case QVariant::String:
+ return DBUS_TYPE_STRING_AS_STRING;
+
+ case QVariant::Map:
+ // internal type information has been lost
+ return DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING; // a{sv}
+
+ case QVariant::StringList:
+ return DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING; // as
+
+ case QVariant::ByteArray:
+ return DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_BYTE_AS_STRING; // ay
+
+ case QVariant::List:
+ // not a string list
+ // internal list data has been lost
+ // could also be a struct...
+ return DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING; // av
+
+ default:
+ if (int(t) == QDBusTypeHelper<QVariant>::id())
+ return DBUS_TYPE_VARIANT_AS_STRING;
+ if (int(t) == QDBusTypeHelper<bool>::listId())
+ return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BOOLEAN_AS_STRING;
+ if (int(t) == QDBusTypeHelper<short>::listId())
+ return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT16_AS_STRING;
+ if (int(t) == QDBusTypeHelper<ushort>::listId())
+ return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT16_AS_STRING;
+ if (int(t) == QDBusTypeHelper<int>::listId())
+ return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING;
+ if (int(t) == QDBusTypeHelper<uint>::listId())
+ return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT32_AS_STRING;
+ if (int(t) == QDBusTypeHelper<qlonglong>::listId())
+ return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT64_AS_STRING;
+ if (int(t) == QDBusTypeHelper<qulonglong>::listId())
+ return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT64_AS_STRING;
+ if (int(t) == QDBusTypeHelper<double>::listId())
+ return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_DOUBLE_AS_STRING;
+
+ return DBUS_TYPE_INVALID_AS_STRING;
+ }
+}
+
+/*!
+ \enum QDBusType::VariantListMode
+ Defines how the guessFromVariant() function will behave when the QVariant is of type
+ QVariant::List.
+*/
+
+/*!
+ Guesses the DBus type from the given \a variant.
+*/
+QDBusType QDBusType::guessFromVariant(const QVariant& variant, VariantListMode mode)
+{
+ if (variant.type() == QVariant::List) {
+ // investigate deeper
+ QDBusType t;
+ t.d = new QDBusTypePrivate;
+ const QVariantList list = variant.toList();
+
+ t.d->code = DBUS_TYPE_ARRAY;
+ if (!list.isEmpty()) {
+ // check if all elements have the same type
+ QVariant::Type type = list.first().type();
+ foreach (const QVariant& v, list)
+ if (type != v.type()) {
+ // at least one is different
+ type = QVariant::Invalid;
+ break;
+ }
+
+ if (type != QVariant::Invalid) {
+ // all are of the same type
+ t.d->subTypes << guessFromVariant(list.first());
+ return t;
+ }
+ } else {
+ // an array of "something"
+ t.d->subTypes << QDBusType('v');
+ return t;
+ }
+
+ // treat it as a struct
+ t.d->code = DBUS_TYPE_STRUCT;
+ foreach (const QVariant& v, list)
+ t.d->subTypes << guessFromVariant(v, mode);
+
+ return t;
+ }
+ else if (variant.type() == QVariant::Map) {
+ // investigate deeper
+ QDBusType t, t2, t3;
+ t2.d = new QDBusTypePrivate;
+ t2.d->code = DBUS_TYPE_DICT_ENTRY;
+
+ // the key
+ t3.d = new QDBusTypePrivate;
+ t3.d->code = DBUS_TYPE_STRING;
+ t2.d->subTypes << t3;
+
+ const QVariantMap map = variant.toMap();
+ if (!map.isEmpty()) {
+ // check if all elements have the same type
+ QVariantMap::const_iterator it = map.constBegin(),
+ end = map.constEnd();
+ QVariant::Type type = it.value().type();
+ for ( ; it != end; ++it)
+ if (type != it.value().type()) {
+ // at least one is different
+ type = QVariant::Invalid;
+ break;
+ }
+
+ if (type != QVariant::Invalid)
+ t2.d->subTypes << guessFromVariant(map.constBegin().value());
+ else {
+ // multiple types
+ t3.d->code = DBUS_TYPE_VARIANT;
+ t2.d->subTypes << t3;
+ }
+ }
+ else {
+ // information lost
+ t3.d->code = DBUS_TYPE_VARIANT;
+ t2.d->subTypes << t3;
+ }
+
+ t.d = new QDBusTypePrivate;
+ t.d->code = DBUS_TYPE_ARRAY;
+ t.d->subTypes << t2;
+ return t;
+ }
+ else
+ return QDBusType( QVariant::Type( variant.userType() ) );
+}
+
+/*!
+ \class QDBusTypeList
+ \brief A list of DBus types.
+ \internal
+
+ Represents zero or more DBus types in sequence, such as those used in argument lists
+ or in subtypes of structs and maps.
+*/
+
+/*!
+ \fn QDBusTypeList::QDBusTypeList()
+
+ Default constructor.
+ */
+
+/*!
+ \fn QDBusTypeList::QDBusTypeList(const QDBusTypeList& other)
+
+ Copy constructor: copies the type list from \a other.
+*/
+
+/*!
+ \fn QDBusTypeList::QDBusTypeList(const QList<QDBusType>& other)
+
+ Copy constructor: copies the type list from \a other.
+*/
+
+/*!
+ Constructs a type list by parsing the given \a signature.
+*/
+QDBusTypeList::QDBusTypeList(const char* signature)
+{
+ if (!signature || !*signature)
+ return; // empty
+
+ // validate it first
+ if ( !dbus_signature_validate(signature, 0) )
+ return;
+
+ // split it into components
+ DBusSignatureIter iter;
+ dbus_signature_iter_init(&iter, signature);
+
+ do {
+ *this << QDBusType(&iter);
+ } while (dbus_signature_iter_next(&iter));
+}
+
+/*!
+ \internal
+ Constructs a type list by parsing the elements on this iterator level.
+*/
+QDBusTypeList::QDBusTypeList(DBusSignatureIter* iter)
+{
+ do {
+ QDBusType item(iter);
+ if (!item.isValid()) {
+ clear();
+ return;
+ }
+
+ *this << item;
+ } while (dbus_signature_iter_next(iter));
+}
+
+/*!
+ Returns true if this type list can represent the inner components of a map.
+*/
+bool QDBusTypeList::canBeMap() const
+{
+ return size() == 2 && at(0).isBasic();
+}
+
+/*!
+ Reconstructs the type signature that this type list represents.
+*/
+QByteArray QDBusTypeList::dbusSignature() const
+{
+ QByteArray retval;
+ foreach (QDBusType t, *this)
+ retval += t.dbusSignature();
+ return retval;
+}
diff --git a/qt/src/qdbustype_p.h b/qt/src/qdbustype_p.h
new file mode 100644
index 00000000..b719960e
--- /dev/null
+++ b/qt/src/qdbustype_p.h
@@ -0,0 +1,109 @@
+/* -*- 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:
+ 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);
+
+ int 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;
+ inline bool operator!=(const QDBusType &other) const
+ { return !(*this == other); }
+
+ static int qvariantType(int type);
+ static int 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;
+
+ QByteArray dbusSignature() const;
+};
+
+#endif // QDBUSTYPE_H
diff --git a/qt/src/qdbustypehelper_p.h b/qt/src/qdbustypehelper_p.h
new file mode 100644
index 00000000..7ebd7f3e
--- /dev/null
+++ b/qt/src/qdbustypehelper_p.h
@@ -0,0 +1,231 @@
+/* qdbuslisthelper_p.h Helper class to convert to and from QVariantList
+ *
+ * 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.
+ *
+ */
+
+//
+// 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 QDBUSTYPEHELPERPRIVATE_H
+#define QDBUSTYPEHELPERPRIVATE_H
+
+#include <QtCore/qlist.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qmetatype.h>
+
+// we're going to support all D-Bus primitive types here:
+// uchar -- not needed: QByteArray
+// bool
+// short
+// ushort
+// int
+// uint
+// qlonglong
+// qulonglong
+// double
+// QString -- not needed: QStringList
+// QList -- not possible: will use QVariant
+// QVariant
+// QDBusStruct -- not yet existant
+// QMap -- not possible: will use QVariant
+
+inline QDBUS_EXPORT int qDBusMetaTypeId(bool *) { return QVariant::Bool; }
+inline QDBUS_EXPORT int qDBusMetaTypeId(uchar *) { return QMetaType::UChar; }
+inline QDBUS_EXPORT int qDBusMetaTypeId(short *) { return QMetaType::Short; }
+inline QDBUS_EXPORT int qDBusMetaTypeId(ushort *) { return QMetaType::UShort; }
+inline QDBUS_EXPORT int qDBusMetaTypeId(int *) { return QVariant::Int; }
+inline QDBUS_EXPORT int qDBusMetaTypeId(uint *) { return QVariant::UInt; }
+inline QDBUS_EXPORT int qDBusMetaTypeId(qlonglong *) { return QVariant::LongLong; }
+inline QDBUS_EXPORT int qDBusMetaTypeId(qulonglong *) { return QVariant::ULongLong; }
+inline QDBUS_EXPORT int qDBusMetaTypeId(double *) { return QVariant::Double; }
+inline QDBUS_EXPORT int qDBusMetaTypeId(QString *) { return QVariant::String; }
+QDBUS_EXPORT int qDBusMetaTypeId(QVariant *);
+QDBUS_EXPORT int qDBusMetaTypeId(QList<bool> *);
+inline QDBUS_EXPORT int qDBusMetaTypeId(QByteArray *) { return QVariant::ByteArray; }
+QDBUS_EXPORT int qDBusMetaTypeId(QList<short> *);
+QDBUS_EXPORT int qDBusMetaTypeId(QList<ushort> *);
+QDBUS_EXPORT int qDBusMetaTypeId(QList<int> *);
+QDBUS_EXPORT int qDBusMetaTypeId(QList<uint> *);
+QDBUS_EXPORT int qDBusMetaTypeId(QList<qlonglong> *);
+QDBUS_EXPORT int qDBusMetaTypeId(QList<qulonglong> *);
+QDBUS_EXPORT int qDBusMetaTypeId(QList<double> *);
+inline QDBUS_EXPORT int qDBusMetaTypeId(QStringList *) { return QVariant::StringList; }
+inline QDBUS_EXPORT int qDBusMetaTypeId(QVariantList *) { return QVariant::List; }
+inline QDBUS_EXPORT int qDBusMetaTypeId(QVariantMap *) { return QVariant::Map; }
+
+// implement the copy mechanism
+template<class T>
+struct QDBusTypeHelper
+{
+ typedef T Type;
+ typedef QList<T> List;
+
+ static inline int id()
+ {
+ Type* t = 0;
+ return qDBusMetaTypeId(t);
+ }
+
+ static inline int listId()
+ {
+ List *l = 0;
+ return qDBusMetaTypeId(l);
+ }
+
+ static inline QVariant toVariant(const Type &t)
+ {
+ return QVariant(id(), &t);
+ }
+
+ static bool canSpecialConvert(const QVariant &);
+ static Type specialConvert(const QVariant &);
+
+ static inline Type fromVariant(const QVariant &v)
+ {
+ if (canSpecialConvert(v))
+ return specialConvert(v);
+
+ QVariant copy(v);
+ if (copy.convert( QVariant::Type(id()) ))
+ return *reinterpret_cast<const Type *>(copy.constData());
+ return Type();
+ }
+
+ static inline QVariantList toVariantList(const List list)
+ {
+ QVariantList tmp;
+ Q_FOREACH (const Type &t, list)
+ tmp.append(toVariant(t));
+ return tmp;
+ }
+
+ static inline QVariantList toVariantList(const QVariant &v)
+ {
+ return toVariantList(QDBusTypeHelper<List>::fromVariant(v));
+ }
+
+ static inline List fromVariantList(const QVariantList list)
+ {
+ List tmp;
+ Q_FOREACH (const QVariant &v, list)
+ tmp.append(fromVariant(v));
+ return tmp;
+ }
+};
+
+template<>
+struct QDBusTypeHelper<QVariant>
+{
+ static inline int id()
+ {
+ QVariant *t = 0;
+ return qDBusMetaTypeId(t);
+ }
+
+ static inline int listId()
+ {
+ return QVariant::List;
+ }
+
+ static inline QVariant toVariant(const QVariant &t)
+ {
+ return QVariant(id(), &t);
+ }
+
+ static inline QVariant fromVariant(const QVariant &v)
+ {
+ if (v.userType() == id())
+ return *reinterpret_cast<const QVariant *>(v.constData());
+ return v;
+ }
+
+ static inline QVariantList toVariantList(const QVariantList &list)
+ {
+ return list;
+ }
+
+ static inline QVariantList fromVariantList(const QVariantList &list)
+ {
+ return list;
+ }
+};
+
+#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_NO_CAST_TO_ASCII)
+template<>
+struct QDBusTypeHelper<char *>
+{
+ static inline int id()
+ { return QVariant::String; }
+
+ static inline QVariant toVariant(const char *t)
+ { return QVariant(t); }
+
+ static inline QByteArray fromVariant(const QVariant &v)
+ { return v.toString().toAscii(); }
+};
+
+template<>
+struct QDBusTypeHelper<const char *>
+{
+ static inline int id()
+ { return QVariant::String; }
+
+ static inline QVariant toVariant(const char *t)
+ { return QVariant(t); }
+
+ static inline QByteArray fromVariant(const QVariant &v)
+ { return v.toString().toAscii(); }
+};
+#endif
+
+// support three exceptions: uchar, short and ushort
+// we have to do this as long as QVariant can't convert to/from the integer metatypes
+template<> inline bool QDBusTypeHelper<short>::canSpecialConvert(const QVariant &v)
+{ return v.userType() < int(QVariant::UserType); }
+template<> inline short QDBusTypeHelper<short>::specialConvert(const QVariant &v)
+{ return v.toInt(); }
+
+template<> inline bool QDBusTypeHelper<ushort>::canSpecialConvert(const QVariant &v)
+{ return v.userType() < int(QVariant::UserType); }
+template<> inline ushort QDBusTypeHelper<ushort>::specialConvert(const QVariant &v)
+{ return v.toUInt(); }
+
+template<> inline bool QDBusTypeHelper<uchar>::canSpecialConvert(const QVariant &v)
+{ return v.userType() < int(QVariant::UserType); }
+template<> inline uchar QDBusTypeHelper<uchar>::specialConvert(const QVariant &v)
+{ return v.toUInt(); }
+
+template<typename T> inline bool QDBusTypeHelper<T>::canSpecialConvert(const QVariant &)
+{ return false; }
+template<typename T> inline T QDBusTypeHelper<T>::specialConvert(const QVariant &)
+{ return T(); }
+
+#endif
diff --git a/qt/src/qdbusutil.cpp b/qt/src/qdbusutil.cpp
new file mode 100644
index 00000000..872434c5
--- /dev/null
+++ b/qt/src/qdbusutil.cpp
@@ -0,0 +1,235 @@
+/* -*- 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>
+
+#include "qdbustype_p.h"
+
+/*!
+ \namespace QDBusUtil
+ The QDBusUtil namespace contains a few functions that are of general use when dealing with D-Bus
+ strings.
+*/
+namespace QDBusUtil
+{
+ /*!
+ \fn QDBusUtil::isValidInterfaceName(const QString &ifaceName)
+ Returns true if this is \a ifaceName is a valid interface name.
+
+ Valid interface names must:
+ \list
+ \o not be empty
+ \o not exceed 255 characters in length
+ \o be composed of dot-separated string components that contain only ASCII letters, digits
+ and the underscore ("_") character
+ \o contain at least two such components
+ \endlist
+ */
+ bool isValidInterfaceName(const QString& ifaceName)
+ {
+ if (ifaceName.isEmpty() || ifaceName.length() > DBUS_MAXIMUM_NAME_LENGTH)
+ return false;
+
+ QStringList parts = ifaceName.split(QLatin1Char('.'));
+ if (parts.count() < 2)
+ return false; // at least two parts
+
+ foreach (QString part, parts)
+ if (!isValidMemberName(part))
+ return false;
+
+ return true;
+ }
+
+ /*!
+ \fn QDBusUtil::isValidUniqueConnectionName(const QString &connName)
+ Returns true if \a connName is a valid unique connection name.
+
+ Unique connection names start with a colon (":") and are followed by a list of dot-separated
+ components composed of ASCII letters, digits, the hypen or the underscore ("_") character.
+ */
+ bool isValidUniqueConnectionName(const QString &connName)
+ {
+ if (connName.isEmpty() || connName.length() > DBUS_MAXIMUM_NAME_LENGTH ||
+ !connName.startsWith(QLatin1Char(':')))
+ return false;
+
+ QStringList parts = connName.mid(1).split(QLatin1Char('.'));
+ if (parts.count() < 1)
+ return false;
+
+ QRegExp regex(QLatin1String("[a-zA-Z0-9_-]+"));
+ foreach (QString part, parts)
+ if (!regex.exactMatch(part))
+ return false;
+
+ return true;
+ }
+
+ /*!
+ \fn QDBusUtil::isValidBusName(const QString &busName)
+ Returns true if \a busName is a valid bus name.
+
+ A valid bus name is either a valid unique connection name or follows the rules:
+ \list
+ \o is not empty
+ \o does not exceed 255 characters in length
+ \o be composed of dot-separated string components that contain only ASCII letters, digits,
+ hyphens or underscores ("_"), but don't start with a digit
+ \o contains at least two such elements
+ \endlist
+
+ \sa isValidUniqueConnectionName()
+ */
+ bool isValidBusName(const QString &busName)
+ {
+ if (busName.isEmpty() || busName.length() > DBUS_MAXIMUM_NAME_LENGTH)
+ return false;
+
+ if (busName.startsWith(QLatin1Char(':')))
+ return isValidUniqueConnectionName(busName);
+
+ QStringList parts = busName.split(QLatin1Char('.'));
+ if (parts.count() < 1)
+ return false;
+
+ QRegExp regex(QLatin1String("[a-zA-Z_-][a-zA-Z0-9_-]*"));
+ foreach (QString part, parts)
+ if (!regex.exactMatch(part))
+ return false;
+
+ return true;
+ }
+
+ /*!
+ \fn QDBusUtil::isValidMemberName(const QString &memberName)
+ Returns true if \a memberName is a valid member name. A valid member name does not exceed
+ 255 characters in length, is not empty, is composed only of ASCII letters, digits and
+ underscores, but does not start with a digit.
+ */
+ bool isValidMemberName(const QString &memberName)
+ {
+ if (memberName.isEmpty() || memberName.length() > DBUS_MAXIMUM_NAME_LENGTH)
+ return false;
+
+ QRegExp regex(QLatin1String("[a-zA-Z_][a-zA-Z0-9_]+"));
+ return regex.exactMatch(memberName);
+ }
+
+ /*!
+ \fn QDBusUtil::isValidErrorName(const QString &errorName)
+ Returns true if \a errorName is a valid error name. Valid error names are valid interface
+ names and vice-versa, so this function is actually an alias for isValidInterfaceName.
+ */
+ bool isValidErrorName(const QString &errorName)
+ {
+ return isValidInterfaceName(errorName);
+ }
+
+ /*!
+ \fn QDBusUtil::isValidObjectPath(const QString &path)
+ Returns true if \a path is valid object path.
+
+ Valid object paths follow the rules:
+ \list
+ \o start with the slash character ("/")
+ \o do not end in a slash, unless the path is just the initial slash
+ \o do not contain any two slashes in sequence
+ \o contain slash-separated parts, each of which is composed of ASCII letters, digits and
+ underscores ("_")
+ \endlist
+ */
+ bool isValidObjectPath(const QString &path)
+ {
+ if (path == QLatin1String("/"))
+ return true;
+
+ if (!path.startsWith(QLatin1Char('/')) || path.indexOf(QLatin1String("//")) != -1 ||
+ path.endsWith(QLatin1Char('/')))
+ return false;
+
+ QStringList parts = path.split(QLatin1Char('/'));
+ Q_ASSERT(parts.count() >= 1);
+ parts.removeFirst(); // it starts with /, so we get an empty first part
+
+ QRegExp regex(QLatin1String("[a-zA-Z0-9_]+"));
+ foreach (QString part, parts)
+ if (!regex.exactMatch(part))
+ return false;
+
+ return true;
+ }
+
+ /*!
+ \fn QDBusUtil::isValidSignature(const QString &signature)
+ Returns true if \a signature is a valid D-Bus type signature for one or more types.
+ This function returns true if it can all of \a signature into valid, individual types and no
+ characters remain in \a signature.
+
+ \sa isValidSingleSignature()
+ */
+ bool isValidSignature(const QString &signature)
+ {
+ return dbus_signature_validate(signature.toUtf8(), 0);
+ }
+
+ /*!
+ \fn QDBusUtil::isValidSingleSignature(const QString &signature)
+ Returns true if \a signature is a valid D-Bus type signature for exactly one full type. This
+ function tries to convert the type signature into a D-Bus type and, if it succeeds and no
+ characters remain in the signature, it returns true.
+ */
+ bool isValidSingleSignature(const QString &signature)
+ {
+ return dbus_signature_validate_single(signature.toUtf8(), 0);
+ }
+
+ /*!
+ \fn QDBusUtil::signatureToType(const QString &signature)
+ Returns the Qt meta type id for the given D-Bus signature for exactly one full type, given
+ by \a signature.
+
+ \sa isValidSingleSignature(), typeToSignature(), QVariant::type(), QVariant::userType()
+ */
+ QVariant::Type signatureToType(const QString &signature)
+ {
+ return QVariant::Type( QDBusType::qvariantType(signature.toLatin1().constData()) );
+ }
+
+ /*!
+ \fn QDBusUtil::typeToSignature(QVariant::Type type)
+ Returns the D-Bus signature equivalent to the supplied meta type id \a type.
+
+ \sa isValidSingleSignature(), signatureToType(), QVariant::type(), QVariant::userType()
+ */
+ const char *typeToSignature(QVariant::Type type)
+ {
+ return QDBusType::dbusSignature( type );
+ }
+
+} // namespace QDBusUtil
diff --git a/qt/src/qdbusutil.h b/qt/src/qdbusutil.h
new file mode 100644
index 00000000..dd2b4df9
--- /dev/null
+++ b/qt/src/qdbusutil.h
@@ -0,0 +1,55 @@
+/* -*- 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 <QtCore/qvariant.h>
+
+#include "qdbusmacros.h"
+
+namespace QDBusUtil
+{
+ QDBUS_EXPORT 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 QVariant::Type signatureToType(const QString &signature);
+
+ QDBUS_EXPORT const char *typeToSignature(QVariant::Type type);
+}
+
+#endif
diff --git a/qt/src/qdbusxmlgenerator.cpp b/qt/src/qdbusxmlgenerator.cpp
new file mode 100644
index 00000000..cbd5388b
--- /dev/null
+++ b/qt/src/qdbusxmlgenerator.cpp
@@ -0,0 +1,194 @@
+/* -*- 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 <QtCore/qcoreapplication.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qstringlist.h>
+
+#include "qdbusinterface_p.h" // for ANNOTATION_NO_WAIT
+#include "qdbusabstractadaptor_p.h" // for QCLASSINFO_DBUS_*
+#include "qdbusconnection_p.h" // for the flags
+#include "qdbusutil.h"
+
+extern QDBUS_EXPORT QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
+ const QMetaObject *base, int flags);
+
+// implement the D-Bus org.freedesktop.DBus.Introspectable interface
+// we do that by analysing the metaObject of all the adaptor interfaces
+
+static QString generateInterfaceXml(const QMetaObject *mo, int flags, int methodOffset, int propOffset)
+{
+ QString retval;
+
+ // start with properties:
+ if (flags & QDBusConnection::ExportProperties) {
+ for (int i = propOffset; i < mo->propertyCount(); ++i) {
+ static const char *accessvalues[] = {0, "read", "write", "readwrite"};
+
+ QMetaProperty mp = mo->property(i);
+
+ if (!mp.isScriptable() && (flags & QDBusConnection::ExportAllProperties) !=
+ QDBusConnection::ExportAllProperties)
+ continue;
+
+ int access = 0;
+ if (mp.isReadable())
+ access |= 1;
+ if (mp.isWritable())
+ access |= 2;
+
+ int typeId = qDBusNameToTypeId(mp.typeName());
+ if (!typeId)
+ continue;
+
+ retval += QString(QLatin1String(" <property name=\"%1\" type=\"%2\" access=\"%3\" />\n"))
+ .arg(mp.name())
+ .arg(QLatin1String( QDBusUtil::typeToSignature( QVariant::Type(typeId) )))
+ .arg(QLatin1String( accessvalues[access] ));
+ }
+ }
+
+ // now add methods:
+ for (int i = methodOffset; i < mo->methodCount(); ++i) {
+ QMetaMethod mm = mo->method(i);
+ QByteArray signature = mm.signature();
+ int paren = signature.indexOf('(');
+
+ bool isSignal;
+ if (mm.methodType() == QMetaMethod::Signal)
+ // adding a signal
+ isSignal = true;
+ else if (mm.methodType() == QMetaMethod::Slot && mm.access() == QMetaMethod::Public)
+ isSignal = false;
+ else
+ continue; // neither signal nor public slot
+
+ if ((isSignal && !(flags & QDBusConnection::ExportSignals)) ||
+ (!isSignal && !(flags & QDBusConnection::ExportSlots)))
+ continue;
+
+ QString xml = QString(QLatin1String(" <%1 name=\"%2\">\n"))
+ .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"))
+ .arg(QLatin1String(signature.left(paren)));
+
+ // check the return type first
+ int typeId = qDBusNameToTypeId(mm.typeName());
+ if (typeId)
+ xml += QString(QLatin1String(" <arg type=\"%1\" direction=\"out\"/>\n"))
+ .arg(QLatin1String(QDBusUtil::typeToSignature( QVariant::Type(typeId) )));
+ else if (*mm.typeName())
+ continue; // wasn't a valid type
+
+ QList<QByteArray> names = mm.parameterNames();
+ QList<int> types;
+ int inputCount = qDBusParametersForMethod(mm, types);
+ if (inputCount == -1)
+ continue; // invalid form
+ if (isSignal && inputCount + 1 != types.count())
+ continue; // signal with output arguments?
+ if (isSignal && types.at(inputCount) == QDBusConnectionPrivate::messageMetaType)
+ continue; // signal with QDBusMessage argument?
+
+ int j;
+ bool isScriptable = mm.attributes() & QMetaMethod::Scriptable;
+ for (j = 1; j < types.count(); ++j) {
+ // input parameter for a slot or output for a signal
+ if (types.at(j) == QDBusConnectionPrivate::messageMetaType) {
+ isScriptable = true;
+ continue;
+ }
+
+ QString name;
+ if (!names.at(j - 1).isEmpty())
+ name = QString(QLatin1String("name=\"%1\" ")).arg(QLatin1String(names.at(j - 1)));
+
+ bool isOutput = isSignal || j > inputCount;
+
+ xml += QString(QLatin1String(" <arg %1type=\"%2\" direction=\"%3\"/>\n"))
+ .arg(name)
+ .arg(QLatin1String(QDBusUtil::typeToSignature( QVariant::Type(types.at(j)) )))
+ .arg(isOutput ? QLatin1String("out") : QLatin1String("in"));
+ }
+
+ if (!isScriptable) {
+ // check if this was added by other means
+ if (isSignal && (flags & QDBusConnection::ExportAllSignals) != QDBusConnection::ExportAllSignals)
+ continue;
+ if (!isSignal && (flags & QDBusConnection::ExportAllSlots) != QDBusConnection::ExportAllSlots)
+ continue;
+ }
+
+ if (qDBusCheckAsyncTag(mm.tag()))
+ // add the no-reply annotation
+ xml += QLatin1String(" <annotation name=\"" ANNOTATION_NO_WAIT "\""
+ " value=\"true\"/>\n");
+
+ retval += xml;
+ retval += QString(QLatin1String(" </%1>\n"))
+ .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"));
+ }
+
+ return retval;
+}
+
+QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo, const QMetaObject *base,
+ int flags)
+{
+ if (interface.isEmpty()) {
+ // generate the interface name from the meta object
+ int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
+ if (idx >= mo->classInfoOffset()) {
+ interface = QLatin1String(mo->classInfo(idx).value());
+ } else {
+ interface = QLatin1String(mo->className());
+ interface.replace(QLatin1String("::"), QLatin1String("."));
+
+ if (interface.startsWith( QLatin1String("QDBus") )) {
+ interface.prepend( QLatin1String("com.trolltech.QtDBus.") );
+ } else if (interface.startsWith( QLatin1Char('Q') )) {
+ // assume it's Qt
+ interface.prepend( QLatin1String("com.trolltech.Qt.") );
+ } else if (!QCoreApplication::instance() ||
+ QCoreApplication::instance()->applicationName().isEmpty()) {
+ interface.prepend( QLatin1String("local.") );
+ } else {
+ interface.prepend(QLatin1Char('.')).prepend( QCoreApplication::instance()->applicationName() );
+ QStringList domainName = QCoreApplication::instance()->organizationDomain().split(QLatin1Char('.'));
+ foreach (const QString &part, domainName)
+ interface.prepend(QLatin1Char('.')).prepend(part);
+ }
+ }
+ }
+
+ QString xml;
+ int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTROSPECTION);
+ if (idx >= mo->classInfoOffset())
+ return QString::fromUtf8(mo->classInfo(idx).value());
+ else
+ xml = generateInterfaceXml(mo, flags, base->methodCount(), base->propertyCount());
+
+ if (xml.isEmpty())
+ return QString(); // don't add an empty interface
+ return QString(QLatin1String(" <interface name=\"%1\">\n%2 </interface>\n"))
+ .arg(interface, xml);
+}
diff --git a/qt/src/qdbusxmlparser.cpp b/qt/src/qdbusxmlparser.cpp
new file mode 100644
index 00000000..0370cb23
--- /dev/null
+++ b/qt/src/qdbusxmlparser.cpp
@@ -0,0 +1,308 @@
+/* -*- 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 "qdbusutil.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(QLatin1String("annotation"));
+ for (int i = 0; i < list.count(); ++i)
+ {
+ QDomElement ann = list.item(i).toElement();
+ if (ann.isNull())
+ continue;
+
+ QString name = ann.attribute(QLatin1String("name")),
+ value = ann.attribute(QLatin1String("value"));
+
+ if (name.isEmpty())
+ continue;
+
+ retval.insert(name, value);
+ }
+
+ return retval;
+}
+
+static QDBusIntrospection::Arguments
+parseArgs(const QDomElement& elem, const QLatin1String& direction, bool acceptEmpty = false)
+{
+ QDBusIntrospection::Arguments retval;
+ QDomNodeList list = elem.elementsByTagName(QLatin1String("arg"));
+ for (int i = 0; i < list.count(); ++i)
+ {
+ QDomElement arg = list.item(i).toElement();
+ if (arg.isNull())
+ continue;
+
+ if ((acceptEmpty && !arg.hasAttribute(QLatin1String("direction"))) ||
+ arg.attribute(QLatin1String("direction")) == direction) {
+
+ QDBusIntrospection::Argument argData;
+ if (arg.hasAttribute(QLatin1String("name")))
+ argData.name = arg.attribute(QLatin1String("name")); // can be empty
+ argData.type = arg.attribute(QLatin1String("type"));
+ if (!QDBusUtil::isValidSingleSignature(argData.type))
+ continue;
+
+ retval << argData;
+ }
+ }
+ return retval;
+}
+
+QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
+ const QString& xmlData)
+ : m_service(service), m_path(path)
+{
+ QDomDocument doc;
+ doc.setContent(xmlData);
+ m_node = doc.firstChildElement(QLatin1String("node"));
+}
+
+QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
+ const QDomElement& node)
+ : m_service(service), m_path(path), m_node(node)
+{
+}
+
+QDBusIntrospection::Interfaces
+QDBusXmlParser::interfaces() const
+{
+ QDBusIntrospection::Interfaces retval;
+
+ if (m_node.isNull())
+ return retval;
+
+ QDomNodeList interfaces = m_node.elementsByTagName(QLatin1String("interface"));
+ for (int i = 0; i < interfaces.count(); ++i)
+ {
+ QDomElement iface = interfaces.item(i).toElement();
+ QString ifaceName = iface.attribute(QLatin1String("name"));
+ if (iface.isNull() || ifaceName.isEmpty())
+ continue; // for whatever reason
+
+ QDBusIntrospection::Interface *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(QLatin1String("method"));
+ for (int j = 0; j < list.count(); ++j)
+ {
+ QDomElement method = list.item(j).toElement();
+ QString methodName = method.attribute(QLatin1String("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(QLatin1String("signal"));
+ for (int j = 0; j < list.count(); ++j)
+ {
+ QDomElement signal = list.item(j).toElement();
+ QString signalName = signal.attribute(QLatin1String("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(QLatin1String("property"));
+ for (int j = 0; j < list.count(); ++j)
+ {
+ QDomElement property = list.item(j).toElement();
+ QString propertyName = property.attribute(QLatin1String("name"));
+ if (property.isNull() || propertyName.isEmpty())
+ continue;
+
+ QDBusIntrospection::Property propertyData;
+
+ // parse data
+ propertyData.name = propertyName;
+ propertyData.type = property.attribute(QLatin1String("type"));
+ propertyData.annotations = parseAnnotations(property);
+
+ if (!QDBusUtil::isValidSingleSignature(propertyData.type))
+ // cannot be!
+ continue;
+
+ QString access = property.attribute(QLatin1String("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
+{
+ if (m_node.isNull())
+ return QSharedDataPointer<QDBusIntrospection::Object>();
+
+ QDBusIntrospection::Object* objData;
+ 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(QLatin1String("node"));
+ for (int i = 0; i < objects.count(); ++i) {
+ QDomElement obj = objects.item(i).toElement();
+ QString objName = obj.attribute(QLatin1String("name"));
+ if (obj.isNull() || objName.isEmpty())
+ continue; // for whatever reason
+
+ objData->childObjects.append(objName);
+ }
+
+ QDomNodeList interfaces = m_node.elementsByTagName(QLatin1String("interface"));
+ for (int i = 0; i < interfaces.count(); ++i) {
+ QDomElement iface = interfaces.item(i).toElement();
+ QString ifaceName = iface.attribute(QLatin1String("name"));
+ if (iface.isNull() || ifaceName.isEmpty())
+ continue;
+
+ objData->interfaces.append(ifaceName);
+ }
+ } else {
+ objData->introspection = QLatin1String("<node/>\n");
+ }
+
+ QSharedDataPointer<QDBusIntrospection::Object> retval;
+ retval = objData;
+ 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(QLatin1String("node"));
+ for (int i = 0; i < objects.count(); ++i) {
+ QDomElement obj = objects.item(i).toElement();
+ QString objName = obj.attribute(QLatin1String("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(QLatin1Char('/')))
+ objAbsName.append(QLatin1Char('/'));
+ objAbsName += objName;
+
+ QDBusXmlParser parser(m_service, objAbsName, obj);
+ retval->childObjectData.insert(objName, parser.objectTree());
+ }
+
+ retval->childObjects << objName;
+ }
+
+ return QSharedDataPointer<QDBusIntrospection::ObjectTree>( retval );
+}
+
diff --git a/qt/src/qdbusxmlparser_p.h b/qt/src/qdbusxmlparser_p.h
new file mode 100644
index 00000000..8f4f69b1
--- /dev/null
+++ b/qt/src/qdbusxmlparser_p.h
@@ -0,0 +1,53 @@
+/* -*- 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_p.h"
+
+/*!
+ \internal
+*/
+class QDBusXmlParser
+{
+ QString m_service;
+ QString m_path;
+ QDomElement m_node;
+
+public:
+ QDBusXmlParser(const QString& service, const QString& path,
+ const QString& xmlData);
+ QDBusXmlParser(const QString& service, const QString& path,
+ const QDomElement& node);
+
+ QDBusIntrospection::Interfaces interfaces() const;
+ QSharedDataPointer<QDBusIntrospection::Object> object() const;
+ QSharedDataPointer<QDBusIntrospection::ObjectTree> objectTree() const;
+};
+
+#endif