6367654d71bb470fe26f75029523a337289bacd6
[platform/upstream/dbus.git] / qt / qdbusinterface.cpp
1 /* -*- C++ -*-
2  *
3  * Copyright (C) 2006 Trolltech AS. All rights reserved.
4  *    Author: Thiago Macieira <thiago.macieira@trolltech.com>
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #include "qdbusinterface.h"
25
26 #include <dbus/dbus.h>
27 #include <QtCore/qpointer.h>
28
29 #include "qdbusinterface_p.h"
30 #include "qdbusconnection_p.h"
31
32 /*!
33     \class QDBusInterface
34     \brief Proxy class for interfaces on remote objects.
35
36     QDBusInterface is a generic accessor class that is used to place calls to remote objects,
37     connect to signals exported by remote objects and get/set the value of remote properties. This
38     class is useful for dynamic access to remote objects: that is, when you do not have a generated
39     code that represents the remote interface.
40
41     Calls are usually placed by using the call() function, which constructs the message, sends it
42     over the bus, waits for the reply and decodes the reply. Signals are connected to by using the
43     normal QObject::connect() function. Finally, properties are accessed using the
44     QObject::property() and QObject::setProperty() functions. 
45 */
46
47 QDBusInterface::QDBusInterface(QDBusInterfacePrivate *p)
48     : QDBusAbstractInterface(p)
49 {
50 }
51
52 /*!
53     Destroy the object interface and frees up any resource used.
54 */
55 QDBusInterface::~QDBusInterface()
56 {
57     // resources are freed in QDBusInterfacePrivate::~QDBusInterfacePrivate()
58 }
59
60 /*!
61     \internal
62     Overrides QObject::metaObject to return our own copy.
63 */
64 const QMetaObject *QDBusInterface::metaObject() const
65 {
66     return d_func()->isValid ? d_func()->metaObject : &QDBusAbstractInterface::staticMetaObject;
67 }
68
69 /*!
70     \internal
71     Override QObject::qt_metacast to catch the interface name too.
72 */
73 void *QDBusInterface::qt_metacast(const char *_clname)
74 {
75     if (!_clname) return 0;
76     if (!strcmp(_clname, "QDBusInterface"))
77         return static_cast<void*>(const_cast<QDBusInterface*>(this));
78     if (d_func()->interface == _clname)
79         return static_cast<void*>(const_cast<QDBusInterface*>(this));
80     return QDBusAbstractInterface::qt_metacast(_clname);
81 }
82
83 /*!
84     \internal
85     Dispatch the call through the private.
86 */
87 int QDBusInterface::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
88 {
89     _id = QDBusAbstractInterface::qt_metacall(_c, _id, _a);
90     if (_id < 0 || !d_func()->isValid)
91         return _id;
92     return d_func()->metacall(_c, _id, _a);
93 }
94
95 int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv)
96 {
97     Q_Q(QDBusInterface);
98     
99     if (c == QMetaObject::InvokeMetaMethod) {
100         int offset = metaObject->methodOffset();
101         QMetaMethod mm = metaObject->method(id + offset);
102         
103         if (mm.methodType() == QMetaMethod::Signal) {
104             // signal relay from D-Bus world to Qt world
105             QMetaObject::activate(q, metaObject, id, argv);
106             
107         } else if (mm.methodType() == QMetaMethod::Slot) {
108             // method call relay from Qt world to D-Bus world
109             // get D-Bus equivalent signature
110             QString methodName = metaObject->dbusNameForMethod(id);
111             const int *inputTypes = metaObject->inputTypesForMethod(id);
112             const int *outputTypes = metaObject->outputTypesForMethod(id);
113
114             int inputTypesCount = *inputTypes;
115             int outputTypesCount = *outputTypes++;
116
117             // we will assume that the input arguments were passed correctly
118             QVariantList args;
119             for (int i = 1; i <= inputTypesCount; ++i)
120                 args << QVariant(inputTypes[i], argv[i]);
121
122             // make the call
123             QPointer<QDBusInterface> qq = q;
124             QDBusMessage reply = q->callWithArgs(methodName, args);
125             args.clear();
126
127             // access to "this" or to "q" below this point must check for "qq"
128             // we may have been deleted!
129
130             // check if we got the right number of parameters back:
131             bool success = false;
132             if (reply.count() == outputTypesCount) {
133                 // copy the values out
134                 for (int i = 0; i < outputTypesCount; ++i) {
135                     // treat the return value specially, since it may be null:
136                     if (i == 0 && argv[0] == 0)
137                         continue;
138
139                     // ensure that the types are correct:
140                     const QVariant &item = reply.at(i);
141                     if (outputTypes[i] != item.userType()) {
142                         success = false;
143                         break;
144                     }
145
146                     if (i == 0)
147                         QDBusMetaObject::assign(argv[0], item);
148                     else
149                         QDBusMetaObject::assign(argv[inputTypesCount + i], item);
150                 }
151             }
152
153             // bail out, something weird happened
154             if (!success && !qq.isNull()) {
155                 QString errmsg = QLatin1String("Invalid signature `%1' in return from call to %2.%3");
156                 lastError = QDBusError(QDBusError::InvalidSignature,
157                                        errmsg.arg(reply.signature(), interface, methodName));
158             }
159
160             // done
161             return -1;
162         }
163     } else if (c == QMetaObject::ReadProperty) {
164         // Qt doesn't support non-readable properties
165         // we have to re-check
166         QMetaProperty mp = metaObject->property(id + metaObject->propertyOffset());
167         if (!mp.isReadable())
168             return -1;          // don't read
169
170         QVariant value = property(mp);
171         if (value.type() == QVariant::Invalid)
172             // an error occurred -- property already set lastError
173             return -1;
174         else if (mp.type() == QVariant::LastType)
175             // QVariant is special in this context
176             *reinterpret_cast<QVariant *>(argv[0]) = value;
177         else
178             QDBusMetaObject::assign(argv[0], value);
179
180         return -1; // handled
181     } else if (c == QMetaObject::WriteProperty) {
182         // QMetaProperty::write has already checked that we're writable
183         // it has also checked that the type is right
184         QVariant value(metaObject->propertyMetaType(id), argv[0]);
185         QMetaProperty mp = metaObject->property(id + metaObject->propertyOffset());
186
187         setProperty(mp, value);
188         return -1;
189     }
190     return id;
191 }
192
193 QDBusInterfacePtr::QDBusInterfacePtr(QDBusConnection &conn, const QString &service, const QString &path,
194                    const QString &interface)
195     : d(conn.findInterface(service, path, interface))
196 {
197 }
198
199 QDBusInterfacePtr::QDBusInterfacePtr(const QString &service, const QString &path, const QString &interface)
200     : d(QDBus::sessionBus().findInterface(service, path, interface))
201 {
202 }
203