source: trunk/src/dbus/qdbusinterface.cpp@ 561

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 11.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtDBus module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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
52QT_BEGIN_NAMESPACE
53
54static void copyArgument(void *to, int id, const QVariant &arg)
55{
56 if (id == arg.userType()) {
57 switch (id) {
58 case QVariant::Bool:
59 *reinterpret_cast<bool *>(to) = arg.toBool();
60 return;
61
62 case QMetaType::UChar:
63 *reinterpret_cast<uchar *>(to) = arg.value<uchar>();
64 return;
65
66 case QMetaType::Short:
67 *reinterpret_cast<short *>(to) = arg.value<short>();
68 return;
69
70 case QMetaType::UShort:
71 *reinterpret_cast<ushort *>(to) = arg.value<ushort>();
72 return;
73
74 case QVariant::Int:
75 *reinterpret_cast<int *>(to) = arg.toInt();
76 return;
77
78 case QVariant::UInt:
79 *reinterpret_cast<uint *>(to) = arg.toUInt();
80 return;
81
82 case QVariant::LongLong:
83 *reinterpret_cast<qlonglong *>(to) = arg.toLongLong();
84 return;
85
86 case QVariant::ULongLong:
87 *reinterpret_cast<qulonglong *>(to) = arg.toULongLong();
88 return;
89
90 case QVariant::Double:
91 *reinterpret_cast<double *>(to) = arg.toDouble();
92 return;
93
94 case QVariant::String:
95 *reinterpret_cast<QString *>(to) = arg.toString();
96 return;
97
98 case QVariant::ByteArray:
99 *reinterpret_cast<QByteArray *>(to) = arg.toByteArray();
100 return;
101
102 case QVariant::StringList:
103 *reinterpret_cast<QStringList *>(to) = arg.toStringList();
104 return;
105 }
106
107 if (id == QDBusMetaTypeId::variant) {
108 *reinterpret_cast<QDBusVariant *>(to) = arg.value<QDBusVariant>();
109 return;
110 } else if (id == QDBusMetaTypeId::objectpath) {
111 *reinterpret_cast<QDBusObjectPath *>(to) = arg.value<QDBusObjectPath>();
112 return;
113 } else if (id == QDBusMetaTypeId::signature) {
114 *reinterpret_cast<QDBusSignature *>(to) = arg.value<QDBusSignature>();
115 return;
116 }
117
118 // those above are the only types possible
119 // the demarshaller code doesn't demarshall anything else
120 qFatal("Found a decoded basic type in a D-Bus reply that shouldn't be there");
121 }
122
123 // if we got here, it's either an un-dermarshalled type or a mismatch
124 if (arg.userType() != QDBusMetaTypeId::argument) {
125 // it's a mismatch
126 //qWarning?
127 return;
128 }
129
130 // is this type registered?
131 const char *userSignature = QDBusMetaType::typeToSignature(id);
132 if (!userSignature || !*userSignature) {
133 // type not registered
134 //qWarning?
135 return;
136 }
137
138 // is it the same signature?
139 QDBusArgument dbarg = arg.value<QDBusArgument>();
140 if (dbarg.currentSignature() != QLatin1String(userSignature)) {
141 // not the same signature, another mismatch
142 //qWarning?
143 return;
144 }
145
146 // we can demarshall
147 QDBusMetaType::demarshall(dbarg, id, to);
148}
149
150QDBusInterfacePrivate::QDBusInterfacePrivate(const QString &serv, const QString &p,
151 const QString &iface, const QDBusConnection &con)
152 : QDBusAbstractInterfacePrivate(serv, p, iface, con, true), metaObject(0)
153{
154 // QDBusAbstractInterfacePrivate's constructor checked the parameters for us
155 if (connection.isConnected()) {
156 metaObject = connectionPrivate()->findMetaObject(service, path, interface, lastError);
157
158 if (!metaObject) {
159 // creation failed, somehow
160 // most common causes are that the service doesn't exist or doesn't support introspection
161 // those are not fatal errors, so we continue working
162
163 if (!lastError.isValid())
164 lastError = QDBusError(QDBusError::InternalError, QLatin1String("Unknown error"));
165 }
166 }
167}
168
169QDBusInterfacePrivate::~QDBusInterfacePrivate()
170{
171 if (metaObject && !metaObject->cached)
172 delete metaObject;
173}
174
175
176/*!
177 \class QDBusInterface
178 \inmodule QtDBus
179 \since 4.2
180
181 \brief The QDBusInterface class is a proxy for interfaces on remote objects.
182
183 QDBusInterface is a generic accessor class that is used to place calls to remote objects,
184 connect to signals exported by remote objects and get/set the value of remote properties. This
185 class is useful for dynamic access to remote objects: that is, when you do not have a generated
186 code that represents the remote interface.
187
188 Calls are usually placed by using the call() function, which constructs the message, sends it
189 over the bus, waits for the reply and decodes the reply. Signals are connected to by using the
190 normal QObject::connect() function. Finally, properties are accessed using the
191 QObject::property() and QObject::setProperty() functions.
192
193 The following code snippet demonstrates how to perform a
194 mathematical operation of \tt{"2 + 2"} in a remote application
195 called \c com.example.Calculator, accessed via the session bus.
196
197 \snippet doc/src/snippets/code/src_qdbus_qdbusinterface.cpp 0
198
199 \sa {QtDBus XML compiler (qdbusxml2cpp)}
200*/
201
202/*!
203 Creates a dynamic QDBusInterface object associated with the
204 interface \a interface on object at path \a path on service \a
205 service, using the given \a connection. If \a interface is an
206 empty string, the object created will refer to the merging of all
207 interfaces found in that object.
208
209 \a parent is passed to the base class constructor.
210
211 If the remote service \a service is not present or if an error
212 occurs trying to obtain the description of the remote interface
213 \a interface, the object created will not be valid (see
214 isValid()).
215*/
216QDBusInterface::QDBusInterface(const QString &service, const QString &path, const QString &interface,
217 const QDBusConnection &connection, QObject *parent)
218 : QDBusAbstractInterface(*new QDBusInterfacePrivate(service, path, interface, connection),
219 parent)
220{
221}
222
223/*!
224 Destroy the object interface and frees up any resource used.
225*/
226QDBusInterface::~QDBusInterface()
227{
228 // resources are freed in QDBusInterfacePrivate::~QDBusInterfacePrivate()
229}
230
231/*!
232 \internal
233 Overrides QObject::metaObject to return our own copy.
234*/
235const QMetaObject *QDBusInterface::metaObject() const
236{
237 return d_func()->metaObject ? d_func()->metaObject : &QDBusAbstractInterface::staticMetaObject;
238}
239
240/*!
241 \internal
242 Override QObject::qt_metacast to catch the interface name too.
243*/
244void *QDBusInterface::qt_metacast(const char *_clname)
245{
246 if (!_clname) return 0;
247 if (!strcmp(_clname, "QDBusInterface"))
248 return static_cast<void*>(const_cast<QDBusInterface*>(this));
249 if (d_func()->interface.toLatin1() == _clname)
250 return static_cast<void*>(const_cast<QDBusInterface*>(this));
251 return QDBusAbstractInterface::qt_metacast(_clname);
252}
253
254/*!
255 \internal
256 Dispatch the call through the private.
257*/
258int QDBusInterface::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
259{
260 _id = QDBusAbstractInterface::qt_metacall(_c, _id, _a);
261 if (_id < 0 || !d_func()->isValid)
262 return _id;
263 return d_func()->metacall(_c, _id, _a);
264}
265
266int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv)
267{
268 Q_Q(QDBusInterface);
269
270 if (c == QMetaObject::InvokeMetaMethod) {
271 int offset = metaObject->methodOffset();
272 QMetaMethod mm = metaObject->method(id + offset);
273
274 if (mm.methodType() == QMetaMethod::Signal) {
275 // signal relay from D-Bus world to Qt world
276 QMetaObject::activate(q, metaObject, id, argv);
277
278 } else if (mm.methodType() == QMetaMethod::Slot) {
279 // method call relay from Qt world to D-Bus world
280 // get D-Bus equivalent signature
281 QString methodName = QLatin1String(metaObject->dbusNameForMethod(id));
282 const int *inputTypes = metaObject->inputTypesForMethod(id);
283 int inputTypesCount = *inputTypes;
284
285 // we will assume that the input arguments were passed correctly
286 QVariantList args;
287 int i = 1;
288 for ( ; i <= inputTypesCount; ++i)
289 args << QVariant(inputTypes[i], argv[i]);
290
291 // make the call
292 QDBusMessage reply = q->callWithArgumentList(QDBus::Block, methodName, args);
293
294 if (reply.type() == QDBusMessage::ReplyMessage) {
295 // attempt to demarshall the return values
296 args = reply.arguments();
297 QVariantList::ConstIterator it = args.constBegin();
298 const int *outputTypes = metaObject->outputTypesForMethod(id);
299 int outputTypesCount = *outputTypes++;
300
301 if (*mm.typeName()) {
302 // this method has a return type
303 if (argv[0] && it != args.constEnd())
304 copyArgument(argv[0], *outputTypes++, *it);
305
306 // skip this argument even if we didn't copy it
307 --outputTypesCount;
308 ++it;
309 }
310
311 for (int j = 0; j < outputTypesCount && it != args.constEnd(); ++i, ++j, ++it) {
312 copyArgument(argv[i], outputTypes[j], *it);
313 }
314 }
315
316 // done
317 lastError = reply;
318 return -1;
319 }
320 }
321 return id;
322}
323
324QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.