3 * Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
4 * Copyright (C) 2006 Trolltech AS. All rights reserved.
5 * Author: Thiago Macieira <thiago.macieira@trolltech.com>
7 * Licensed under the Academic Free License version 2.1
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include "qdbusabstractinterface.h"
27 #include "qdbusabstractinterface_p.h"
28 #include "qdbusmetaobject_p.h"
29 #include "qdbusconnection_p.h"
31 QVariant QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp) const
33 // try to read this property
34 QDBusMessage msg = QDBusMessage::methodCall(service, path, DBUS_INTERFACE_PROPERTIES,
35 QLatin1String("Get"));
36 msg << interface << QString::fromUtf8(mp.name());
37 QDBusMessage reply = connp->sendWithReply(msg, QDBusConnection::NoUseEventLoop);
39 if (reply.type() == QDBusMessage::ReplyMessage && reply.count() == 1 &&
40 reply.signature() == QLatin1String("v")) {
41 QVariant value = QDBusTypeHelper<QVariant>::fromVariant(reply.at(0));
43 // make sure the type is right
44 if (qstrcmp(mp.typeName(), value.typeName()) == 0) {
45 if (mp.type() == QVariant::LastType)
46 // QVariant is special in this context
47 return QDBusTypeHelper<QVariant>::fromVariant(value);
53 // there was an error...
54 if (reply.type() == QDBusMessage::ErrorMessage)
56 else if (reply.signature() != QLatin1String("v")) {
57 QString errmsg = QLatin1String("Invalid signature `%1' in return from call to "
58 DBUS_INTERFACE_PROPERTIES);
59 lastError = QDBusError(QDBusError::InvalidSignature, errmsg.arg(reply.signature()));
61 QString errmsg = QLatin1String("Unexpected type `%1' when retrieving property "
63 lastError = QDBusError(QDBusError::InvalidSignature,
64 errmsg.arg(QLatin1String(reply.at(0).typeName()),
65 QLatin1String(mp.typeName()),
66 interface, QString::fromUtf8(mp.name())));
72 void QDBusAbstractInterfacePrivate::setProperty(const QMetaProperty &mp, const QVariant &value)
75 QDBusMessage msg = QDBusMessage::methodCall(service, path, DBUS_INTERFACE_PROPERTIES,
76 QLatin1String("Set"));
77 msg.setSignature(QLatin1String("ssv"));
78 msg << interface << QString::fromUtf8(mp.name()) << value;
79 QDBusMessage reply = connp->sendWithReply(msg, QDBusConnection::NoUseEventLoop);
81 if (reply.type() != QDBusMessage::ReplyMessage)
86 \class QDBusAbstractInterface
87 \brief Base class for all D-Bus interfaces in the QtDBus binding, allowing access to remote interfaces.
89 Generated-code classes also derive from QDBusAbstractInterface, all methods described here are also
90 valid for generated-code classes. In addition to those described here, generated-code classes
91 provide member functions for the remote methods, which allow for compile-time checking of the
92 correct parameters and return values, as well as property type-matching and signal
95 \sa {dbusidl2cpp.html}{The dbusidl2cpp compiler}, QDBusInterface
99 \enum QDBusAbstractInterface::CallMode
101 Specifies how a call should be placed. The valid options are:
102 \value NoWaitForReply place the call but don't wait for the reply (the reply's contents
104 \value NoUseEventLoop don't use an event loop to wait for a reply, but instead block on
105 network operations while waiting. This option means the
106 user-interface may not be updated for the duration of the call.
107 \value UseEventLoop use the Qt event loop to wait for a reply. This option means the
108 user-interface will update, but it also means other events may
109 happen, like signal delivery and other D-Bus method calls.
111 When using UseEventLoop, applications must be prepared for reentrancy in any function.
117 QDBusAbstractInterface::QDBusAbstractInterface(QDBusAbstractInterfacePrivate* d)
118 #if QT_VERSION < 0x040200
126 Releases this object's resources.
128 QDBusAbstractInterface::~QDBusAbstractInterface()
134 Returns true if this is a valid reference to a remote object. It returns false if
135 there was an error during the creation of this interface (for instance, if the remote
136 application does not exist).
138 Note: when dealing with remote objects, it is not always possible to determine if it
139 exists when creating a QDBusInterface or QDBusInterfacePtr object.
141 bool QDBusAbstractInterface::isValid() const
143 return d_func()->isValid;
147 Returns the connection this interface is assocated with.
149 QDBusConnection QDBusAbstractInterface::connection() const
151 return d_func()->conn;
155 Returns the name of the service this interface is associated with.
157 QString QDBusAbstractInterface::service() const
159 return d_func()->service;
163 Returns the object path that this interface is associated with.
165 QString QDBusAbstractInterface::path() const
167 return d_func()->path;
171 Returns the name of this interface.
173 QString QDBusAbstractInterface::interface() const
175 return d_func()->interface;
179 Returns the error the last operation produced, or an invalid error if the last operation did not
182 QDBusError QDBusAbstractInterface::lastError() const
184 return d_func()->lastError;
189 Places a call to the remote method specified by \a method on this interface, using \a args as
190 arguments. This function returns the message that was received as a reply, which can be a normal
191 QDBusMessage::ReplyMessage (indicating success) or QDBusMessage::ErrorMessage (if the call
192 failed). The \a mode parameter specifies how this call should be placed.
194 If the call succeeds, lastError() will be cleared; otherwise, it will contain the error this
197 Normally, you should place calls using call().
199 \warning If you use \c UseEventLoop, your code must be prepared to deal with any reentrancy:
200 other method calls and signals may be delivered before this function returns, as well
201 as other Qt queued signals and events.
203 QDBusMessage QDBusAbstractInterface::callWithArgs(const QString& method, const QList<QVariant>& args,
206 Q_D(QDBusAbstractInterface);
208 QString m = method, sig;
209 // split out the signature from the method
210 int pos = method.indexOf(QLatin1Char('.'));
213 sig = method.mid(pos + 1);
216 if (mode == AutoDetect) {
217 // determine if this a sync or async call
218 mode = NoUseEventLoop;
219 const QMetaObject *mo = metaObject();
220 QByteArray match = method.toLatin1() + '(';
222 for (int i = staticMetaObject.methodCount(); i < mo->methodCount(); ++i) {
223 QMetaMethod mm = mo->method(i);
224 if (QByteArray(mm.signature()).startsWith(match)) {
225 // found a method with the same name as what we're looking for
226 // hopefully, nobody is overloading asynchronous and synchronous methods with
229 QList<QByteArray> tags = QByteArray(mm.tag()).split(' ');
230 if (tags.contains("async") || tags.contains("Q_ASYNC"))
231 mode = NoWaitForReply;
238 QDBusMessage msg = QDBusMessage::methodCall(service(), path(), interface(), m);
239 msg.setSignature(sig);
240 msg.QList<QVariant>::operator=(args);
243 if (mode != NoWaitForReply)
244 reply = d->conn.sendWithReply(msg, mode == UseEventLoop ?
245 QDBusConnection::UseEventLoop : QDBusConnection::NoUseEventLoop);
249 d->lastError = reply; // will clear if reply isn't an error
251 // ensure that there is at least one element
260 Places a call to the remote method specified by \a method on this interface, using \a args as
261 arguments. This function will return immediately after queueing the call. The reply from the
262 remote function or any errors emitted by it will be delivered to the \a slot slot on object \a
265 This function returns true if the queueing succeeded: it does not indicate that the call
266 succeeded. If it failed, the slot will be called with an error message. lastError() will not be
267 set under those circumstances.
269 \sa QDBusError, QDBusMessage
271 bool QDBusAbstractInterface::callWithArgs(const QString &method, QObject *receiver, const char *slot,
272 const QList<QVariant> &args)
274 Q_D(QDBusAbstractInterface);
276 QString m = method, sig;
277 // split out the signature from the method
278 int pos = method.indexOf(QLatin1Char('.'));
281 sig = method.mid(pos + 1);
284 QDBusMessage msg = QDBusMessage::methodCall(service(), path(), interface(), m);
285 msg.setSignature(sig);
286 msg.QList<QVariant>::operator=(args);
288 d->lastError = 0; // clear
289 return d->conn.sendWithReplyAsync(msg, receiver, slot);
294 Catch signal connections.
296 void QDBusAbstractInterface::connectNotify(const char *signal)
298 // someone connecting to one of our signals
299 Q_D(QDBusAbstractInterface);
301 d->connp->connectRelay(d->service, d->path, d->interface, this, signal);
306 Catch signal disconnections.
308 void QDBusAbstractInterface::disconnectNotify(const char *signal)
310 // someone disconnecting from one of our signals
311 Q_D(QDBusAbstractInterface);
313 d->connp->disconnectRelay(d->service, d->path, d->interface, this, signal);
318 Get the value of the property \a propname.
320 QVariant QDBusAbstractInterface::internalPropGet(const char *propname) const
322 // assume this property exists and is readable
323 // we're only called from generated code anyways
325 int idx = metaObject()->indexOfProperty(propname);
327 return d_func()->property(metaObject()->property(idx));
328 qWarning("QDBusAbstractInterface::internalPropGet called with unknown property '%s'", propname);
329 return QVariant(); // error
334 Set the value of the property \a propname to \a value.
336 void QDBusAbstractInterface::internalPropSet(const char *propname, const QVariant &value)
338 Q_D(QDBusAbstractInterface);
340 // assume this property exists and is writeable
341 // we're only called from generated code anyways
343 int idx = metaObject()->indexOfProperty(propname);
345 d->setProperty(metaObject()->property(idx), value);
347 qWarning("QDBusAbstractInterface::internalPropGet called with unknown property '%s'", propname);
352 \fn QDBusMessage QDBusAbstractInterface::call(const QString &method)
354 Calls the method \a method on this interface and passes the parameters to this function to the
357 The parameters to \c call are passed on to the remote function via D-Bus as input
358 arguments. Output arguments are returned in the QDBusMessage reply. If the reply is an error
359 reply, lastError() will also be set to the contents of the error message.
361 This function is implemented by actually 9 different function overloads called \c call, so you
362 can pass up to 8 parameters to your function call, which can be of any type accepted by QtDBus
363 (see the \l {allowedparameters.html}{allowed parameters} page for information on what types are
366 It can be used the following way:
369 QString value = retrieveValue();
372 QDBusReply<int> api = interface->call(QLatin1String("GetAPIVersion"));
374 reply = interface->call(QLatin1String("ProcessWorkUnicode"), value);
376 reply = interface->call(QLatin1String("ProcessWork"), QLatin1String("UTF-8"), value.toUtf8());
379 This example illustrates function calling with 0, 1 and 2 parameters and illustrates different
380 parameter types passed in each (the first call to \c "ProcessWorkUnicode" will contain one
381 Unicode string, the second call to \c "ProcessWork" will contain one string and one byte array).
383 \warning This function reenters the Qt event loop in order to wait for the reply, excluding user
384 input. During the wait, it may deliver signals and other method calls to your
385 application. Therefore, it must be prepared to handle a reentrancy whenever a call is
389 #include "qdbusabstractinterface.moc"