Merge remote-tracking branch 'origin/api_changes'
[profile/ivi/qtbase.git] / src / dbus / qdbusinterface.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDBus module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdbusinterface.h"
43
44 #include "qdbus_symbols_p.h"
45 #include <QtCore/qpointer.h>
46 #include <QtCore/qstringlist.h>
47
48 #include "qdbusmetatype_p.h"
49 #include "qdbusinterface_p.h"
50 #include "qdbusconnection_p.h"
51
52 #ifndef QT_NO_DBUS
53
54 QT_BEGIN_NAMESPACE
55
56 static void copyArgument(void *to, int id, const QVariant &arg)
57 {
58     if (id == arg.userType()) {
59         switch (id) {
60         case QVariant::Bool:
61             *reinterpret_cast<bool *>(to) = arg.toBool();
62             return;
63
64         case QMetaType::UChar:
65             *reinterpret_cast<uchar *>(to) = arg.value<uchar>();
66             return;
67
68         case QMetaType::Short:
69             *reinterpret_cast<short *>(to) = arg.value<short>();
70             return;
71
72         case QMetaType::UShort:
73             *reinterpret_cast<ushort *>(to) = arg.value<ushort>();
74             return;
75
76         case QVariant::Int:
77             *reinterpret_cast<int *>(to) = arg.toInt();
78             return;
79
80         case QVariant::UInt:
81             *reinterpret_cast<uint *>(to) = arg.toUInt();
82             return;
83
84         case QVariant::LongLong:
85             *reinterpret_cast<qlonglong *>(to) = arg.toLongLong();
86             return;
87
88         case QVariant::ULongLong:
89             *reinterpret_cast<qulonglong *>(to) = arg.toULongLong();
90             return;
91
92         case QVariant::Double:
93             *reinterpret_cast<double *>(to) = arg.toDouble();
94             return;
95
96         case QVariant::String:
97             *reinterpret_cast<QString *>(to) = arg.toString();
98             return;
99
100         case QVariant::ByteArray:
101             *reinterpret_cast<QByteArray *>(to) = arg.toByteArray();
102             return;
103
104         case QVariant::StringList:
105             *reinterpret_cast<QStringList *>(to) = arg.toStringList();
106             return;
107         }
108
109         if (id == QDBusMetaTypeId::variant) {
110             *reinterpret_cast<QDBusVariant *>(to) = arg.value<QDBusVariant>();
111             return;
112         } else if (id == QDBusMetaTypeId::objectpath) {
113             *reinterpret_cast<QDBusObjectPath *>(to) = arg.value<QDBusObjectPath>();
114             return;
115         } else if (id == QDBusMetaTypeId::signature) {
116             *reinterpret_cast<QDBusSignature *>(to) = arg.value<QDBusSignature>();
117             return;
118         }
119
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");
123     }
124
125     // if we got here, it's either an un-dermarshalled type or a mismatch
126     if (arg.userType() != QDBusMetaTypeId::argument) {
127         // it's a mismatch
128         //qWarning?
129         return;
130     }
131
132     // is this type registered?
133     const char *userSignature = QDBusMetaType::typeToSignature(id);
134     if (!userSignature || !*userSignature) {
135         // type not registered
136         //qWarning?
137         return;
138     }
139
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
144         //qWarning?
145         return;
146     }
147
148     // we can demarshall
149     QDBusMetaType::demarshall(dbarg, id, to);
150 }
151
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)
155 {
156     // QDBusAbstractInterfacePrivate's constructor checked the parameters for us
157     if (connection.isConnected()) {
158         metaObject = connectionPrivate()->findMetaObject(service, path, interface, lastError);
159
160         if (!metaObject) {
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
164
165             if (!lastError.isValid())
166                 lastError = QDBusError(QDBusError::InternalError, QLatin1String("Unknown error"));
167         }
168     }
169 }
170
171 QDBusInterfacePrivate::~QDBusInterfacePrivate()
172 {
173     if (metaObject && !metaObject->cached)
174         delete metaObject;
175 }
176
177
178 /*!
179     \class QDBusInterface
180     \inmodule QtDBus
181     \since 4.2
182
183     \brief The QDBusInterface class is a proxy for interfaces on remote objects.
184
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.
189
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.
194
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.
198
199     \snippet doc/src/snippets/code/src_qdbus_qdbusinterface.cpp 0
200
201     \sa {QtDBus XML compiler (qdbusxml2cpp)}
202 */
203
204 /*!
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.
210
211     \a parent is passed to the base class constructor.
212
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
216     isValid()).
217 */
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),
221                              parent)
222 {
223 }
224
225 /*!
226     Destroy the object interface and frees up any resource used.
227 */
228 QDBusInterface::~QDBusInterface()
229 {
230     // resources are freed in QDBusInterfacePrivate::~QDBusInterfacePrivate()
231 }
232
233 /*!
234     \internal
235     Overrides QObject::metaObject to return our own copy.
236 */
237 const QMetaObject *QDBusInterface::metaObject() const
238 {
239     return d_func()->metaObject ? d_func()->metaObject : &QDBusAbstractInterface::staticMetaObject;
240 }
241
242 /*!
243     \internal
244     Override QObject::qt_metacast to catch the interface name too.
245 */
246 void *QDBusInterface::qt_metacast(const char *_clname)
247 {
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);
254 }
255
256 /*!
257     \internal
258     Dispatch the call through the private.
259 */
260 int QDBusInterface::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
261 {
262     _id = QDBusAbstractInterface::qt_metacall(_c, _id, _a);
263     if (_id < 0 || !d_func()->isValid || !d_func()->metaObject)
264         return _id;
265     return d_func()->metacall(_c, _id, _a);
266 }
267
268 int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv)
269 {
270     Q_Q(QDBusInterface);
271
272     if (c == QMetaObject::InvokeMetaMethod) {
273         int offset = metaObject->methodOffset();
274         QMetaMethod mm = metaObject->method(id + offset);
275
276         if (mm.methodType() == QMetaMethod::Signal) {
277             // signal relay from D-Bus world to Qt world
278             QMetaObject::activate(q, metaObject, id, argv);
279
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;
286
287             // we will assume that the input arguments were passed correctly
288             QVariantList args;
289             int i = 1;
290             for ( ; i <= inputTypesCount; ++i)
291                 args << QVariant(inputTypes[i], argv[i]);
292
293             // make the call
294             QDBusMessage reply = q->callWithArgumentList(QDBus::Block, methodName, args);
295
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++;
302
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);
307
308                     // skip this argument even if we didn't copy it
309                     --outputTypesCount;
310                     ++it;
311                 }
312
313                 for (int j = 0; j < outputTypesCount && it != args.constEnd(); ++i, ++j, ++it) {
314                     copyArgument(argv[i], outputTypes[j], *it);
315                 }
316             }
317
318             // done
319             lastError = QDBusError(reply);
320             return -1;
321         }
322     }
323     return id;
324 }
325
326 QT_END_NAMESPACE
327
328 #endif // QT_NO_DBUS