dbus/qt/src .cvsignore, NONE, 1.1 Makefile.am, NONE, 1.1 qdbus.h,
NONE, 1.1 qdbusabstractadaptor.cpp, NONE,
1.1 qdbusabstractadaptor.h, NONE, 1.1 qdbusabstractadaptor_p.h,
NONE, 1.1 qdbusabstractinterface.cpp, NONE,
1.1 qdbusabstractinterface.h, NONE,
1.1 qdbusabstractinterface_p.h, NONE, 1.1 qdbusbus.cpp, NONE,
1.1 qdbusbus.h, NONE, 1.1 qdbusconnection.cpp, NONE,
1.1 qdbusconnection.h, NONE, 1.1 qdbusconnection_p.h, NONE,
1.1 qdbuserror.cpp, NONE, 1.1 qdbuserror.h, NONE,
1.1 qdbusintegrator.cpp, NONE, 1.1 qdbusinterface.cpp, NONE,
1.1 qdbusinterface.h, NONE, 1.1 qdbusinterface_p.h, NONE,
1.1 qdbusinternalfilters.cpp, NONE, 1.1 qdbusintrospection.cpp,
NONE, 1.1 qdbusintrospection_p.h, NONE, 1.1 qdbusmacros.h,
NONE, 1.1 qdbusmarshall.cpp, NONE, 1.1 qdbusmarshall_p.h, NONE,
1.1 qdbusmessage.cpp, NONE, 1.1 qdbusmessage.h, NONE,
1.1 qdbusmessage_p.h, NONE, 1.1 qdbusmetaobject.cpp, NONE,
1.1 qdbusmetaobject_p.h, NONE, 1.1 qdbusmisc.cpp, NONE,
1.1 qdbusreply.h, NONE, 1.1 qdbusserver.cpp, NONE,
1.1 qdbusserver.h, NONE, 1.1 qdbusthread.cpp, NONE,
1.1 qdbustype.cpp, NONE, 1.1 qdbustype_p.h, NONE,
1.1 qdbustypehelper_p.h, NONE, 1.1 qdbusutil.cpp, NONE,
1.1 qdbusutil.h, NONE, 1.1 qdbusxmlgenerator.cpp, NONE,
1.1 qdbusxmlparser.cpp, NONE, 1.1 qdbusxmlparser_p.h, NONE, 1.1
Thiago J. Macieira
thiago at kemper.freedesktop.org
Sun Jun 4 08:52:07 PDT 2006
- Previous message: dbus/qt/tools .cvsignore, NONE, 1.1 Makefile.am, NONE,
1.1 dbuscpp2xml.cpp, NONE, 1.1 dbusidl2cpp.cpp, NONE, 1.1
- Next message: dbus/qt Doxyfile, 1.1, 1.2 Makefile.am, 1.23, 1.24 dbuscpp2xml.cpp,
1.1, NONE dbusidl2cpp.cpp, 1.5, NONE qdbusabstractadaptor.cpp,
1.5, NONE qdbusabstractadaptor.h, 1.3,
NONE qdbusabstractadaptor_p.h, 1.1,
NONE qdbusabstractinterface.cpp, 1.5,
NONE qdbusabstractinterface.h, 1.5,
NONE qdbusabstractinterface_p.h, 1.3, NONE qdbusbus.cpp, 1.1,
NONE qdbusbus.h, 1.2, NONE qdbusconnection.cpp, 1.8,
NONE qdbusconnection.h, 1.7, NONE qdbusconnection_p.h, 1.10,
NONE qdbuserror.cpp, 1.4, NONE qdbuserror.h, 1.5,
NONE qdbusintegrator.cpp, 1.12, NONE qdbusinterface.cpp, 1.8,
NONE qdbusinterface.h, 1.6, NONE qdbusinterface_p.h, 1.5,
NONE qdbusinternalfilters.cpp, 1.6,
NONE qdbusintrospection.cpp, 1.3, NONE qdbusintrospection_p.h,
1.1, NONE qdbusmacros.h, 1.6, NONE qdbusmarshall.cpp, 1.6,
NONE qdbusmarshall_p.h, 1.1, NONE qdbusmessage.cpp, 1.7,
NONE qdbusmessage.h, 1.6, NONE qdbusmessage_p.h, 1.5,
NONE qdbusmetaobject.cpp, 1.3, NONE qdbusmetaobject_p.h, 1.2,
NONE qdbusmisc.cpp, 1.1, NONE qdbusreply.h, 1.3,
NONE qdbusserver.cpp, 1.2, NONE qdbusserver.h, 1.3,
NONE qdbusthread.cpp, 1.1, NONE qdbustype.cpp, 1.3,
NONE qdbustype_p.h, 1.1, NONE qdbustypehelper_p.h, 1.3,
NONE qdbusutil.cpp, 1.3, NONE qdbusutil.h, 1.2,
NONE qdbusxmlgenerator.cpp, 1.1, NONE qdbusxmlparser.cpp, 1.3,
NONE qdbusxmlparser_p.h, 1.2, NONE qt.tag, NONE, 1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /cvs/dbus/dbus/qt/src
In directory kemper:/tmp/cvs-serv5955/qt/src
Added Files:
.cvsignore Makefile.am qdbus.h qdbusabstractadaptor.cpp
qdbusabstractadaptor.h qdbusabstractadaptor_p.h
qdbusabstractinterface.cpp qdbusabstractinterface.h
qdbusabstractinterface_p.h qdbusbus.cpp qdbusbus.h
qdbusconnection.cpp qdbusconnection.h qdbusconnection_p.h
qdbuserror.cpp qdbuserror.h qdbusintegrator.cpp
qdbusinterface.cpp qdbusinterface.h qdbusinterface_p.h
qdbusinternalfilters.cpp qdbusintrospection.cpp
qdbusintrospection_p.h qdbusmacros.h qdbusmarshall.cpp
qdbusmarshall_p.h qdbusmessage.cpp qdbusmessage.h
qdbusmessage_p.h qdbusmetaobject.cpp qdbusmetaobject_p.h
qdbusmisc.cpp qdbusreply.h qdbusserver.cpp qdbusserver.h
qdbusthread.cpp qdbustype.cpp qdbustype_p.h
qdbustypehelper_p.h qdbusutil.cpp qdbusutil.h
qdbusxmlgenerator.cpp qdbusxmlparser.cpp qdbusxmlparser_p.h
Log Message:
* qt/: Update to Subversion r548032.
This includes a big reorganisation of the files inside the
subdir.
We really need a version control system that supports moving of
files. I'm not bothering with history anyways anymore, since the
bindings will be moved out to git. The history should be restored from
Subversion when that happens.
--- NEW FILE: .cvsignore ---
.deps
.libs
Makefile
Makefile.in
*.lo
*.la
*.bb
*.bbg
*.da
*.gcov
*.moc
--- NEW FILE: Makefile.am ---
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) $< > $@
--- NEW FILE: qdbus.h ---
/* qdbus.h precompiled header
*
* Copyright (C) 2005 Harald Fernengel <harry at 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
--- NEW FILE: qdbusabstractadaptor.cpp ---
/* -*- mode: C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbusabstractadaptor.h"
#include <QtCore/qmetaobject.h>
#include <QtCore/qtimer.h>
#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"
--- NEW FILE: qdbusabstractadaptor.h ---
/* -*- mode: C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSABSTRACTADAPTOR_H
#define QDBUSABSTRACTADAPTOR_H
#include <QtCore/qobject.h>
#include "qdbusmacros.h"
class 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
--- NEW FILE: qdbusabstractadaptor_p.h ---
/* -*- mode: C++; set-fill-width: 100 -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#ifndef 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
--- NEW FILE: qdbusabstractinterface.cpp ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "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"
--- NEW FILE: qdbusabstractinterface.h ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef 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
--- NEW FILE: qdbusabstractinterface_p.h ---
/*
*
* Copyright (C) 2006 Thiago José Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#ifndef 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
--- NEW FILE: qdbusbus.cpp ---
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at 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"
--- NEW FILE: qdbusbus.h ---
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at 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
--- NEW FILE: qdbusconnection.cpp ---
/* qdbusconnection.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* 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);
}
}
--- NEW FILE: qdbusconnection.h ---
/* qdbusconnection.h QDBusConnection object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* 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
--- NEW FILE: qdbusconnection_p.h ---
/* qdbusconnection_p.h QDBusConnection private object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* 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
--- NEW FILE: qdbuserror.cpp ---
/* qdbuserror.h QDBusError object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* 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
--- NEW FILE: qdbuserror.h ---
/* qdbuserror.h QDBusError object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* 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
--- NEW FILE: qdbusintegrator.cpp ---
/* qdbusintegrator.cpp QDBusConnection private implementation
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <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> ¶ms)
{
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"
--- NEW FILE: qdbusinterface.cpp ---
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "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))
{
}
--- NEW FILE: qdbusinterface.h ---
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef 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
--- NEW FILE: qdbusinterface_p.h ---
/*
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#ifndef 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
--- NEW FILE: qdbusinternalfilters.cpp ---
/* -*- mode: C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "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);
}
--- NEW FILE: qdbusintrospection.cpp ---
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbusintrospection_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;
}
--- NEW FILE: qdbusintrospection_p.h ---
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSINTROSPECTION_H
#define QDBUSINTROSPECTION_H
#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qmap.h>
#include <QtCore/qpair.h>
#include <QtCore/qshareddata.h>
#include "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
--- NEW FILE: qdbusmacros.h ---
/* qdbusmessage.h QDBusMessage object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* 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
--- NEW FILE: qdbusmarshall.cpp ---
/* qdbusmarshall.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* 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()));
}
--- NEW FILE: qdbusmarshall_p.h ---
/* qdbusmarshall_p.h QDBusMarshall object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* 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
--- NEW FILE: qdbusmessage.cpp ---
/* qdbusmessage.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* 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
--- NEW FILE: qdbusmessage.h ---
/* qdbusmessage.h QDBusMessage object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* 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
--- NEW FILE: qdbusmessage_p.h ---
/* qdbusmessage.h QDBusMessage private object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* 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
--- NEW FILE: qdbusmetaobject.cpp ---
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "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; }
--- NEW FILE: qdbusmetaobject_p.h ---
/*
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#ifndef 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
--- NEW FILE: qdbusmisc.cpp ---
/* qdbusmisc.cpp Miscellaneous routines that didn't fit anywhere else
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <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;
}
--- NEW FILE: qdbusreply.h ---
/* qdbusreply.h QDBusReply object - a reply from D-Bus
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef 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
--- NEW FILE: qdbusserver.cpp ---
/* qdbusserver.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* 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"
--- NEW FILE: qdbusserver.h ---
/* qdbusserver.h QDBusServer object
*
* Copyright (C) 2005 Harald Fernengel <harry at 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
--- NEW FILE: qdbusthread.cpp ---
/* qdbusintegrator.cpp QDBusConnection private implementation
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <QtCore/qmutex.h>
#include <QtCore/qwaitcondition.h>
#include <dbus/dbus.h>
struct DBusMutex: public QMutex
{
inline DBusMutex()
: QMutex( QMutex::NonRecursive )
{ }
static DBusMutex* mutex_new()
{
return new DBusMutex;
}
static void mutex_free(DBusMutex *mutex)
{
delete mutex;
}
static dbus_bool_t mutex_lock(DBusMutex *mutex)
{
mutex->lock();
return true;
}
static dbus_bool_t mutex_unlock(DBusMutex *mutex)
{
mutex->unlock();
return true;
}
};
struct DBusCondVar: public QWaitCondition
{
inline DBusCondVar()
{ }
static DBusCondVar* condvar_new()
{
return new DBusCondVar;
}
static void condvar_free(DBusCondVar *cond)
{
delete cond;
}
static void condvar_wait(DBusCondVar *cond, DBusMutex *mutex)
{
cond->wait(mutex);
}
static dbus_bool_t condvar_wait_timeout(DBusCondVar *cond, DBusMutex *mutex, int msec)
{
return cond->wait(mutex, msec);
}
static void condvar_wake_one(DBusCondVar *cond)
{
cond->wakeOne();
}
static void condvar_wake_all(DBusCondVar *cond)
{
cond->wakeAll();
}
};
bool qDBusInitThreads()
{
static DBusThreadFunctions fcn = {
DBUS_THREAD_FUNCTIONS_ALL_MASK,
DBusMutex::mutex_new,
DBusMutex::mutex_free,
DBusMutex::mutex_lock,
DBusMutex::mutex_unlock,
DBusCondVar::condvar_new,
DBusCondVar::condvar_free,
DBusCondVar::condvar_wait,
DBusCondVar::condvar_wait_timeout,
DBusCondVar::condvar_wake_one,
DBusCondVar::condvar_wake_all,
0, 0, 0, 0, 0, 0, 0, 0
};
dbus_threads_init(&fcn);
return true;
}
--- NEW FILE: qdbustype.cpp ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbustype_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;
}
--- NEW FILE: qdbustype_p.h ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef 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
--- NEW FILE: qdbustypehelper_p.h ---
/* qdbuslisthelper_p.h Helper class to convert to and from QVariantList
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
//
// 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
--- NEW FILE: qdbusutil.cpp ---
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbusutil.h"
#include <dbus/dbus.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qregexp.h>
#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
--- NEW FILE: qdbusutil.h ---
/* -*- C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSUTIL_H
#define QDBUSUTIL_H
#include <QtCore/qstring.h>
#include <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
--- NEW FILE: qdbusxmlgenerator.cpp ---
/* -*- mode: C++ -*-
*
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <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);
}
--- NEW FILE: qdbusxmlparser.cpp ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "qdbusxmlparser_p.h"
#include "qdbusinterface.h"
#include "qdbusinterface_p.h"
#include "qdbusconnection_p.h"
#include "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 );
}
--- NEW FILE: qdbusxmlparser_p.h ---
/* -*- C++ -*-
*
* Copyright (C) 2005 Thiago Macieira <thiago at kde.org>
* Copyright (C) 2006 Trolltech AS. All rights reserved.
* Author: Thiago Macieira <thiago.macieira at trolltech.com>
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef QDBUSXMLPARSER_H
#define QDBUSXMLPARSER_H
#include <QtCore/qmap.h>
#include <QtXml/qdom.h>
#include "qdbusmacros.h"
#include "qdbusintrospection_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
- Previous message: dbus/qt/tools .cvsignore, NONE, 1.1 Makefile.am, NONE,
1.1 dbuscpp2xml.cpp, NONE, 1.1 dbusidl2cpp.cpp, NONE, 1.1
- Next message: dbus/qt Doxyfile, 1.1, 1.2 Makefile.am, 1.23, 1.24 dbuscpp2xml.cpp,
1.1, NONE dbusidl2cpp.cpp, 1.5, NONE qdbusabstractadaptor.cpp,
1.5, NONE qdbusabstractadaptor.h, 1.3,
NONE qdbusabstractadaptor_p.h, 1.1,
NONE qdbusabstractinterface.cpp, 1.5,
NONE qdbusabstractinterface.h, 1.5,
NONE qdbusabstractinterface_p.h, 1.3, NONE qdbusbus.cpp, 1.1,
NONE qdbusbus.h, 1.2, NONE qdbusconnection.cpp, 1.8,
NONE qdbusconnection.h, 1.7, NONE qdbusconnection_p.h, 1.10,
NONE qdbuserror.cpp, 1.4, NONE qdbuserror.h, 1.5,
NONE qdbusintegrator.cpp, 1.12, NONE qdbusinterface.cpp, 1.8,
NONE qdbusinterface.h, 1.6, NONE qdbusinterface_p.h, 1.5,
NONE qdbusinternalfilters.cpp, 1.6,
NONE qdbusintrospection.cpp, 1.3, NONE qdbusintrospection_p.h,
1.1, NONE qdbusmacros.h, 1.6, NONE qdbusmarshall.cpp, 1.6,
NONE qdbusmarshall_p.h, 1.1, NONE qdbusmessage.cpp, 1.7,
NONE qdbusmessage.h, 1.6, NONE qdbusmessage_p.h, 1.5,
NONE qdbusmetaobject.cpp, 1.3, NONE qdbusmetaobject_p.h, 1.2,
NONE qdbusmisc.cpp, 1.1, NONE qdbusreply.h, 1.3,
NONE qdbusserver.cpp, 1.2, NONE qdbusserver.h, 1.3,
NONE qdbusthread.cpp, 1.1, NONE qdbustype.cpp, 1.3,
NONE qdbustype_p.h, 1.1, NONE qdbustypehelper_p.h, 1.3,
NONE qdbusutil.cpp, 1.3, NONE qdbusutil.h, 1.2,
NONE qdbusxmlgenerator.cpp, 1.1, NONE qdbusxmlparser.cpp, 1.3,
NONE qdbusxmlparser_p.h, 1.2, NONE qt.tag, NONE, 1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the dbus-commit
mailing list