1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDBus module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qdbuspendingcall.h"
43 #include "qdbuspendingcall_p.h"
45 #include "qdbusconnection_p.h"
46 #include "qdbusmetatype_p.h"
47 #include "qcoreapplication.h"
48 #include "qcoreevent.h"
49 #include <private/qobject_p.h>
56 \class QDBusPendingCall
60 \brief The QDBusPendingCall class refers to one pending asynchronous call
62 A QDBusPendingCall object is a reference to a method call that was
63 sent over D-Bus without waiting for a reply. QDBusPendingCall is an
64 opaque type, meant to be used as a handle for a pending reply.
66 In most programs, the QDBusPendingCall class will not be used
67 directly. It can be safely replaced with the template-based
68 QDBusPendingReply, in order to access the contents of the reply or
69 wait for it to be complete.
71 The QDBusPendingCallWatcher class allows one to connect to a signal
72 that will indicate when the reply has arrived or if the call has
73 timed out. It also provides the
74 QDBusPendingCallWatcher::waitForFinished() method which will suspend
75 the execution of the program until the reply has arrived.
77 \note If you create a copy of a QDBusPendingCall object, all
78 information will be shared among the many copies. Therefore,
79 QDBusPendingCall is an explicitly-shared object and does not
80 provide a method of detaching the copies (since they refer
81 to the same pending call)
83 \sa QDBusPendingReply, QDBusPendingCallWatcher,
84 QDBusAbstractInterface::asyncCall()
88 \class QDBusPendingCallWatcher
92 \brief The QDBusPendingCallWatcher class provides a convenient way for
93 waiting for asynchronous replies
95 The QDBusPendingCallWatcher provides the finished() signal that will be
96 emitted when a reply arrives.
98 It is usually used like the following example:
100 \snippet code/src_qdbus_qdbuspendingcall.cpp 0
102 Note that it is not necessary to keep the original QDBusPendingCall
103 object around since QDBusPendingCallWatcher inherits from that class
106 The slot connected to by the above code could be something similar
109 \snippet code/src_qdbus_qdbuspendingcall.cpp 1
111 Note the use of QDBusPendingReply to validate the argument types in
112 the reply. If the reply did not contain exactly two arguments
113 (one string and one QByteArray), QDBusPendingReply::isError() will
116 \sa QDBusPendingReply, QDBusAbstractInterface::asyncCall()
120 \fn void QDBusPendingCallWatcher::finished(QDBusPendingCallWatcher *self)
122 This signal is emitted when the pending call has finished and its
123 reply is available. The \a self parameter is a pointer to the
124 object itself, passed for convenience so that the slot can access
125 the properties and determine the contents of the reply.
128 void QDBusPendingCallWatcherHelper::add(QDBusPendingCallWatcher *watcher)
130 connect(this, SIGNAL(finished()), watcher, SLOT(_q_finished()), Qt::QueuedConnection);
133 QDBusPendingCallPrivate::~QDBusPendingCallPrivate()
136 q_dbus_pending_call_cancel(pending);
137 q_dbus_pending_call_unref(pending);
139 delete watcherHelper;
142 bool QDBusPendingCallPrivate::setReplyCallback(QObject *target, const char *member)
148 return true;; // unsetting
150 if (!member || !*member) {
151 // would not be able to deliver a reply
152 qWarning("QDBusPendingCall::setReplyCallback: error: cannot deliver a reply to %s::%s (%s)",
153 target ? target->metaObject()->className() : "(null)",
154 member ? member + 1 : "(null)",
155 target ? qPrintable(target->objectName()) : "no name");
159 methodIdx = QDBusConnectionPrivate::findSlot(target, member + 1, metaTypes);
160 if (methodIdx == -1) {
161 QByteArray normalizedName = QMetaObject::normalizedSignature(member + 1);
162 methodIdx = QDBusConnectionPrivate::findSlot(target, normalizedName, metaTypes);
164 if (methodIdx == -1) {
165 // would not be able to deliver a reply
166 qWarning("QDBusPendingCall::setReplyCallback: error: cannot deliver a reply to %s::%s (%s)",
167 target->metaObject()->className(),
168 member + 1, qPrintable(target->objectName()));
173 // construct the expected signature
174 int count = metaTypes.count() - 1;
175 if (count == 1 && metaTypes.at(1) == QDBusMetaTypeId::message) {
176 // wildcard slot, can receive anything, so don't set the signature
180 if (metaTypes.at(count) == QDBusMetaTypeId::message)
183 setMetaTypes(count, count ? metaTypes.constData() + 1 : 0);
187 void QDBusPendingCallPrivate::setMetaTypes(int count, const int *types)
189 expectedReplyCount = count;
191 expectedReplySignature = QLatin1String(""); // not null
196 sig.reserve(count + count / 2);
197 for (int i = 0; i < count; ++i) {
198 const char *typeSig = QDBusMetaType::typeToSignature(types[i]);
200 qFatal("QDBusPendingReply: type %s is not registered with QtDBus",
201 QMetaType::typeName(types[i]));
206 expectedReplySignature = QString::fromLatin1(sig);
209 void QDBusPendingCallPrivate::checkReceivedSignature()
211 // MUST BE CALLED WITH A LOCKED MUTEX!
213 if (replyMessage.type() == QDBusMessage::InvalidMessage)
214 return; // not yet finished - no message to
216 if (replyMessage.type() == QDBusMessage::ErrorMessage)
217 return; // we don't have to check the signature of an error reply
219 if (expectedReplySignature.isNull())
220 return; // no signature to validate against
222 // can't use startsWith here because a null string doesn't start or end with an empty string
223 if (!replyMessage.signature().indexOf(expectedReplySignature) == 0) {
224 QString errorMsg = QLatin1String("Unexpected reply signature: got \"%1\", "
226 replyMessage = QDBusMessage::createError(
227 QDBusError::InvalidSignature,
228 errorMsg.arg(replyMessage.signature(), expectedReplySignature));
233 void QDBusPendingCallPrivate::waitForFinished()
235 QMutexLocker locker(&mutex);
237 if (replyMessage.type() != QDBusMessage::InvalidMessage)
238 return; // already finished
240 connection->waitForFinished(this);
244 Creates a copy of the \a other pending asynchronous call. Note
245 that both objects will refer to the same pending call.
247 QDBusPendingCall::QDBusPendingCall(const QDBusPendingCall &other)
255 QDBusPendingCall::QDBusPendingCall(QDBusPendingCallPrivate *dd)
261 Destroys this copy of the QDBusPendingCall object. If this copy is
262 also the last copy of a pending asynchronous call, the call will
263 be canceled and no further notifications will be received. There
264 will be no way of accessing the reply's contents when it arrives.
266 QDBusPendingCall::~QDBusPendingCall()
268 // d deleted by QExplicitlySharedDataPointer
273 Creates a copy of the \a other pending asynchronous call and drops
274 the reference to the previously-referenced call. Note that both
275 objects will refer to the same pending call after this function.
277 If this object contained the last reference of a pending
278 asynchronous call, the call will be canceled and no further
279 notifications will be received. There will be no way of accessing
280 the reply's contents when it arrives.
282 QDBusPendingCall &QDBusPendingCall::operator=(const QDBusPendingCall &other)
289 \fn void QDBusPendingCall::swap(QDBusPendingCall &other)
292 Swaps this pending call instance with \a other. This function is
293 very fast and never fails.
297 \fn bool QDBusPendingCallWatcher::isFinished() const
299 Returns true if the pending call has finished processing and the
300 reply has been received.
302 Note that this function only changes state if you call
303 waitForFinished() or if an external D-Bus event happens, which in
304 general only happens if you return to the event loop execution.
306 \sa QDBusPendingReply::isFinished()
309 \fn bool QDBusPendingReply::isFinished() const
311 Returns true if the pending call has finished processing and the
312 reply has been received. If this function returns true, the
313 isError(), error() and reply() methods should return valid
316 Note that this function only changes state if you call
317 waitForFinished() or if an external D-Bus event happens, which in
318 general only happens if you return to the event loop execution.
320 \sa QDBusPendingCallWatcher::isFinished()
323 bool QDBusPendingCall::isFinished() const
326 return true; // considered finished
328 QMutexLocker locker(&d->mutex);
329 return d->replyMessage.type() != QDBusMessage::InvalidMessage;
332 void QDBusPendingCall::waitForFinished()
334 if (d) d->waitForFinished();
338 \fn bool QDBusPendingReply::isValid() const
340 Returns true if the reply contains a normal reply message, false
341 if it contains anything else.
343 If the pending call has not finished processing, this function
346 bool QDBusPendingCall::isValid() const
350 QMutexLocker locker(&d->mutex);
351 return d->replyMessage.type() == QDBusMessage::ReplyMessage;
355 \fn bool QDBusPendingReply::isError() const
357 Returns true if the reply contains an error message, false if it
358 contains a normal method reply.
360 If the pending call has not finished processing, this function
363 bool QDBusPendingCall::isError() const
366 return true; // considered finished and an error
367 QMutexLocker locker(&d->mutex);
368 return d->replyMessage.type() == QDBusMessage::ErrorMessage;
372 \fn QDBusError QDBusPendingReply::error() const
374 Retrieves the error content of the reply message, if it has
375 finished processing. If the reply message has not finished
376 processing or if it contains a normal reply message (non-error),
377 this function returns an invalid QDBusError.
379 QDBusError QDBusPendingCall::error() const
382 QMutexLocker locker(&d->mutex);
383 return QDBusError(d->replyMessage);
386 // not connected, return an error
387 QDBusError err = QDBusError(QDBusError::Disconnected,
388 QLatin1String("Not connected to D-Bus server"));
393 \fn QDBusMessage QDBusPendingReply::reply() const
395 Retrieves the reply message received for the asynchronous call
396 that was sent, if it has finished processing. If the pending call
397 is not finished, this function returns a QDBusMessage of type
398 QDBusMessage::InvalidMessage.
400 After it has finished processing, the message type will either be
401 an error message or a normal method reply message.
403 QDBusMessage QDBusPendingCall::reply() const
406 return QDBusMessage::createError(error());
407 QMutexLocker locker(&d->mutex);
408 return d->replyMessage;
413 Sets the slot \a member in object \a target to be called when the
414 reply arrives. The slot's parameter list must match the reply
415 message's arguments for it to be called.
417 It may, optionally, contain a QDBusMessage final parameter. If it
418 is present, the parameter will contain the reply message object.
420 The callback will not be called if the reply is an error message.
422 This function returns true if it could set the callback, false
423 otherwise. It is not a guarantee that the callback will be
426 \warning QDBusPendingCall only supports one callback per pending
427 asynchronous call, even if multiple QDBusPendingCall
428 objects are referencing the same pending call.
430 bool QDBusPendingCall::setReplyCallback(QObject *target, const char *member)
435 return d->setReplyCallback(target, member);
441 Creates a QDBusPendingCall object based on the error condition
442 \a error. The resulting pending call object will be in the
443 "finished" state and QDBusPendingReply::isError() will return true.
445 \sa fromCompletedCall()
447 QDBusPendingCall QDBusPendingCall::fromError(const QDBusError &error)
449 return fromCompletedCall(QDBusMessage::createError(error));
454 Creates a QDBusPendingCall object based on the message \a msg.
455 The message must be of type QDBusMessage::ErrorMessage or
456 QDBusMessage::ReplyMessage (that is, a message that is typical
457 of a completed call).
459 This function is useful for code that requires simulating a pending
460 call, but that has already finished.
464 QDBusPendingCall QDBusPendingCall::fromCompletedCall(const QDBusMessage &msg)
466 QDBusPendingCallPrivate *d = 0;
467 if (msg.type() == QDBusMessage::ErrorMessage ||
468 msg.type() == QDBusMessage::ReplyMessage) {
469 d = new QDBusPendingCallPrivate(QDBusMessage(), 0);
470 d->replyMessage = msg;
473 return QDBusPendingCall(d);
477 class QDBusPendingCallWatcherPrivate: public QObjectPrivate
482 Q_DECLARE_PUBLIC(QDBusPendingCallWatcher)
485 inline void QDBusPendingCallWatcherPrivate::_q_finished()
487 Q_Q(QDBusPendingCallWatcher);
492 Creates a QDBusPendingCallWatcher object to watch for replies on the
493 asynchronous pending call \a call and sets this object's parent
496 QDBusPendingCallWatcher::QDBusPendingCallWatcher(const QDBusPendingCall &call, QObject *parent)
497 : QObject(*new QDBusPendingCallWatcherPrivate, parent), QDBusPendingCall(call)
499 if (d) { // QDBusPendingCall::d
500 QMutexLocker locker(&d->mutex);
501 if (!d->watcherHelper) {
502 d->watcherHelper = new QDBusPendingCallWatcherHelper;
503 if (d->replyMessage.type() != QDBusMessage::InvalidMessage) {
504 // cause a signal emission anyways
505 QMetaObject::invokeMethod(d->watcherHelper, "finished", Qt::QueuedConnection);
508 d->watcherHelper->add(this);
513 Destroys this object. If this QDBusPendingCallWatcher object was the
514 last reference to the unfinished pending call, the call will be
517 QDBusPendingCallWatcher::~QDBusPendingCallWatcher()
522 \fn void QDBusPendingCallWatcher::waitForFinished()
524 Suspends the execution of the calling thread until the reply is
525 received and processed. After this function returns, isFinished()
526 should return true, indicating the reply's contents are ready to
529 \sa QDBusPendingReply::waitForFinished()
531 void QDBusPendingCallWatcher::waitForFinished()
534 d->waitForFinished();
536 // our signals were queued, so deliver them
537 QCoreApplication::sendPostedEvents(d->watcherHelper, QEvent::MetaCall);
538 QCoreApplication::sendPostedEvents(this, QEvent::MetaCall);
545 #include "moc_qdbuspendingcall.cpp"