1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDBus module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdbusinterface.h"
44 #include "qdbus_symbols_p.h"
45 #include <QtCore/qpointer.h>
46 #include <QtCore/qstringlist.h>
48 #include "qdbusmetatype_p.h"
49 #include "qdbusinterface_p.h"
50 #include "qdbusconnection_p.h"
56 static void copyArgument(void *to, int id, const QVariant &arg)
58 if (id == arg.userType()) {
61 *reinterpret_cast<bool *>(to) = arg.toBool();
64 case QMetaType::UChar:
65 *reinterpret_cast<uchar *>(to) = arg.value<uchar>();
68 case QMetaType::Short:
69 *reinterpret_cast<short *>(to) = arg.value<short>();
72 case QMetaType::UShort:
73 *reinterpret_cast<ushort *>(to) = arg.value<ushort>();
77 *reinterpret_cast<int *>(to) = arg.toInt();
81 *reinterpret_cast<uint *>(to) = arg.toUInt();
84 case QVariant::LongLong:
85 *reinterpret_cast<qlonglong *>(to) = arg.toLongLong();
88 case QVariant::ULongLong:
89 *reinterpret_cast<qulonglong *>(to) = arg.toULongLong();
92 case QVariant::Double:
93 *reinterpret_cast<double *>(to) = arg.toDouble();
96 case QVariant::String:
97 *reinterpret_cast<QString *>(to) = arg.toString();
100 case QVariant::ByteArray:
101 *reinterpret_cast<QByteArray *>(to) = arg.toByteArray();
104 case QVariant::StringList:
105 *reinterpret_cast<QStringList *>(to) = arg.toStringList();
109 if (id == QDBusMetaTypeId::variant) {
110 *reinterpret_cast<QDBusVariant *>(to) = arg.value<QDBusVariant>();
112 } else if (id == QDBusMetaTypeId::objectpath) {
113 *reinterpret_cast<QDBusObjectPath *>(to) = arg.value<QDBusObjectPath>();
115 } else if (id == QDBusMetaTypeId::signature) {
116 *reinterpret_cast<QDBusSignature *>(to) = arg.value<QDBusSignature>();
120 // those above are the only types possible
121 // the demarshaller code doesn't demarshall anything else
122 qFatal("Found a decoded basic type in a D-Bus reply that shouldn't be there");
125 // if we got here, it's either an un-dermarshalled type or a mismatch
126 if (arg.userType() != QDBusMetaTypeId::argument) {
132 // is this type registered?
133 const char *userSignature = QDBusMetaType::typeToSignature(id);
134 if (!userSignature || !*userSignature) {
135 // type not registered
140 // is it the same signature?
141 QDBusArgument dbarg = arg.value<QDBusArgument>();
142 if (dbarg.currentSignature() != QLatin1String(userSignature)) {
143 // not the same signature, another mismatch
149 QDBusMetaType::demarshall(dbarg, id, to);
152 QDBusInterfacePrivate::QDBusInterfacePrivate(const QString &serv, const QString &p,
153 const QString &iface, const QDBusConnection &con)
154 : QDBusAbstractInterfacePrivate(serv, p, iface, con, true), metaObject(0)
156 // QDBusAbstractInterfacePrivate's constructor checked the parameters for us
157 if (connection.isConnected()) {
158 metaObject = connectionPrivate()->findMetaObject(service, path, interface, lastError);
161 // creation failed, somehow
162 // most common causes are that the service doesn't exist or doesn't support introspection
163 // those are not fatal errors, so we continue working
165 if (!lastError.isValid())
166 lastError = QDBusError(QDBusError::InternalError, QLatin1String("Unknown error"));
171 QDBusInterfacePrivate::~QDBusInterfacePrivate()
173 if (metaObject && !metaObject->cached)
179 \class QDBusInterface
183 \brief The QDBusInterface class is a proxy for interfaces on remote objects.
185 QDBusInterface is a generic accessor class that is used to place calls to remote objects,
186 connect to signals exported by remote objects and get/set the value of remote properties. This
187 class is useful for dynamic access to remote objects: that is, when you do not have a generated
188 code that represents the remote interface.
190 Calls are usually placed by using the call() function, which constructs the message, sends it
191 over the bus, waits for the reply and decodes the reply. Signals are connected to by using the
192 normal QObject::connect() function. Finally, properties are accessed using the
193 QObject::property() and QObject::setProperty() functions.
195 The following code snippet demonstrates how to perform a
196 mathematical operation of \tt{"2 + 2"} in a remote application
197 called \c com.example.Calculator, accessed via the session bus.
199 \snippet doc/src/snippets/code/src_qdbus_qdbusinterface.cpp 0
201 \sa {QtDBus XML compiler (qdbusxml2cpp)}
205 Creates a dynamic QDBusInterface object associated with the
206 interface \a interface on object at path \a path on service \a
207 service, using the given \a connection. If \a interface is an
208 empty string, the object created will refer to the merging of all
209 interfaces found in that object.
211 \a parent is passed to the base class constructor.
213 If the remote service \a service is not present or if an error
214 occurs trying to obtain the description of the remote interface
215 \a interface, the object created will not be valid (see
218 QDBusInterface::QDBusInterface(const QString &service, const QString &path, const QString &interface,
219 const QDBusConnection &connection, QObject *parent)
220 : QDBusAbstractInterface(*new QDBusInterfacePrivate(service, path, interface, connection),
226 Destroy the object interface and frees up any resource used.
228 QDBusInterface::~QDBusInterface()
230 // resources are freed in QDBusInterfacePrivate::~QDBusInterfacePrivate()
235 Overrides QObject::metaObject to return our own copy.
237 const QMetaObject *QDBusInterface::metaObject() const
239 return d_func()->metaObject ? d_func()->metaObject : &QDBusAbstractInterface::staticMetaObject;
244 Override QObject::qt_metacast to catch the interface name too.
246 void *QDBusInterface::qt_metacast(const char *_clname)
248 if (!_clname) return 0;
249 if (!strcmp(_clname, "QDBusInterface"))
250 return static_cast<void*>(const_cast<QDBusInterface*>(this));
251 if (d_func()->interface.toLatin1() == _clname)
252 return static_cast<void*>(const_cast<QDBusInterface*>(this));
253 return QDBusAbstractInterface::qt_metacast(_clname);
258 Dispatch the call through the private.
260 int QDBusInterface::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
262 _id = QDBusAbstractInterface::qt_metacall(_c, _id, _a);
263 if (_id < 0 || !d_func()->isValid || !d_func()->metaObject)
265 return d_func()->metacall(_c, _id, _a);
268 int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv)
272 if (c == QMetaObject::InvokeMetaMethod) {
273 int offset = metaObject->methodOffset();
274 QMetaMethod mm = metaObject->method(id + offset);
276 if (mm.methodType() == QMetaMethod::Signal) {
277 // signal relay from D-Bus world to Qt world
278 QMetaObject::activate(q, metaObject, id, argv);
280 } else if (mm.methodType() == QMetaMethod::Slot || mm.methodType() == QMetaMethod::Method) {
281 // method call relay from Qt world to D-Bus world
282 // get D-Bus equivalent signature
283 QString methodName = QString::fromLatin1(mm.name());
284 const int *inputTypes = metaObject->inputTypesForMethod(id);
285 int inputTypesCount = *inputTypes;
287 // we will assume that the input arguments were passed correctly
290 for ( ; i <= inputTypesCount; ++i)
291 args << QVariant(inputTypes[i], argv[i]);
294 QDBusMessage reply = q->callWithArgumentList(QDBus::Block, methodName, args);
296 if (reply.type() == QDBusMessage::ReplyMessage) {
297 // attempt to demarshall the return values
298 args = reply.arguments();
299 QVariantList::ConstIterator it = args.constBegin();
300 const int *outputTypes = metaObject->outputTypesForMethod(id);
301 int outputTypesCount = *outputTypes++;
303 if (mm.returnType() != QMetaType::UnknownType && mm.returnType() != QMetaType::Void) {
304 // this method has a return type
305 if (argv[0] && it != args.constEnd())
306 copyArgument(argv[0], *outputTypes++, *it);
308 // skip this argument even if we didn't copy it
313 for (int j = 0; j < outputTypesCount && it != args.constEnd(); ++i, ++j, ++it) {
314 copyArgument(argv[i], outputTypes[j], *it);
319 lastError = QDBusError(reply);