summaryrefslogtreecommitdiffstats
path: root/qt/src
diff options
context:
space:
mode:
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