3 * Copyright (C) 2006 Trolltech AS. All rights reserved.
4 * Author: Thiago Macieira <thiago.macieira@trolltech.com>
6 * Licensed under the Academic Free License version 2.1
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.
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.
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.
24 #include "qdbusinterface.h"
26 #include <dbus/dbus.h>
27 #include <QtCore/qpointer.h>
29 #include "qdbusinterface_p.h"
30 #include "qdbusconnection_p.h"
34 \brief Proxy class for interfaces on remote objects.
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.
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.
47 QDBusInterface::QDBusInterface(QDBusInterfacePrivate *p)
48 : QDBusAbstractInterface(p)
53 Destroy the object interface and frees up any resource used.
55 QDBusInterface::~QDBusInterface()
57 // resources are freed in QDBusInterfacePrivate::~QDBusInterfacePrivate()
62 Overrides QObject::metaObject to return our own copy.
64 const QMetaObject *QDBusInterface::metaObject() const
66 return d_func()->isValid ? d_func()->metaObject : &QDBusAbstractInterface::staticMetaObject;
71 Override QObject::qt_metacast to catch the interface name too.
73 void *QDBusInterface::qt_metacast(const char *_clname)
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);
85 Dispatch the call through the private.
87 int QDBusInterface::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
89 _id = QDBusAbstractInterface::qt_metacall(_c, _id, _a);
90 if (_id < 0 || !d_func()->isValid)
92 return d_func()->metacall(_c, _id, _a);
95 int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv)
99 if (c == QMetaObject::InvokeMetaMethod) {
100 int offset = metaObject->methodOffset();
101 QMetaMethod mm = metaObject->method(id + offset);
103 if (mm.methodType() == QMetaMethod::Signal) {
104 // signal relay from D-Bus world to Qt world
105 QMetaObject::activate(q, metaObject, id, argv);
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);
114 int inputTypesCount = *inputTypes;
115 int outputTypesCount = *outputTypes++;
117 // we will assume that the input arguments were passed correctly
119 for (int i = 1; i <= inputTypesCount; ++i)
120 args << QVariant(inputTypes[i], argv[i]);
123 QPointer<QDBusInterface> qq = q;
124 QDBusMessage reply = q->callWithArgs(methodName, args);
127 // access to "this" or to "q" below this point must check for "qq"
128 // we may have been deleted!
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)
139 // ensure that the types are correct:
140 const QVariant &item = reply.at(i);
141 if (outputTypes[i] != item.userType()) {
147 QDBusMetaObject::assign(argv[0], item);
149 QDBusMetaObject::assign(argv[inputTypesCount + i], item);
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));
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
170 QVariant value = property(mp);
171 if (value.type() == QVariant::Invalid)
172 // an error occurred -- property already set lastError
174 else if (mp.type() == QVariant::LastType)
175 // QVariant is special in this context
176 *reinterpret_cast<QVariant *>(argv[0]) = value;
178 QDBusMetaObject::assign(argv[0], value);
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());
187 setProperty(mp, value);
193 QDBusInterfacePtr::QDBusInterfacePtr(QDBusConnection &conn, const QString &service, const QString &path,
194 const QString &interface)
195 : d(conn.findInterface(service, path, interface))
199 QDBusInterfacePtr::QDBusInterfacePtr(const QString &service, const QString &path, const QString &interface)
200 : d(QDBus::sessionBus().findInterface(service, path, interface))