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 doc/src/snippets/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 doc/src/snippets/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 bool QDBusPendingCallWatcher::isFinished() const
291 Returns true if the pending call has finished processing and the
292 reply has been received.
294 Note that this function only changes state if you call
295 waitForFinished() or if an external D-Bus event happens, which in
296 general only happens if you return to the event loop execution.
298 \sa QDBusPendingReply::isFinished()
301 \fn bool QDBusPendingReply::isFinished() const
303 Returns true if the pending call has finished processing and the
304 reply has been received. If this function returns true, the
305 isError(), error() and reply() methods should return valid
308 Note that this function only changes state if you call
309 waitForFinished() or if an external D-Bus event happens, which in
310 general only happens if you return to the event loop execution.
312 \sa QDBusPendingCallWatcher::isFinished()
315 bool QDBusPendingCall::isFinished() const
318 return true; // considered finished
320 QMutexLocker locker(&d->mutex);
321 return d->replyMessage.type() != QDBusMessage::InvalidMessage;
324 void QDBusPendingCall::waitForFinished()
326 if (d) d->waitForFinished();
330 \fn bool QDBusPendingReply::isValid() const
332 Returns true if the reply contains a normal reply message, false
333 if it contains anything else.
335 If the pending call has not finished processing, this function
338 bool QDBusPendingCall::isValid() const
342 QMutexLocker locker(&d->mutex);
343 return d->replyMessage.type() == QDBusMessage::ReplyMessage;
347 \fn bool QDBusPendingReply::isError() const
349 Returns true if the reply contains an error message, false if it
350 contains a normal method reply.
352 If the pending call has not finished processing, this function
355 bool QDBusPendingCall::isError() const
358 return true; // considered finished and an error
359 QMutexLocker locker(&d->mutex);
360 return d->replyMessage.type() == QDBusMessage::ErrorMessage;
364 \fn QDBusError QDBusPendingReply::error() const
366 Retrieves the error content of the reply message, if it has
367 finished processing. If the reply message has not finished
368 processing or if it contains a normal reply message (non-error),
369 this function returns an invalid QDBusError.
371 QDBusError QDBusPendingCall::error() const
374 QMutexLocker locker(&d->mutex);
375 return QDBusError(d->replyMessage);
378 // not connected, return an error
379 QDBusError err = QDBusError(QDBusError::Disconnected,
380 QLatin1String("Not connected to D-Bus server"));
385 \fn QDBusMessage QDBusPendingReply::reply() const
387 Retrieves the reply message received for the asynchronous call
388 that was sent, if it has finished processing. If the pending call
389 is not finished, this function returns a QDBusMessage of type
390 QDBusMessage::InvalidMessage.
392 After it has finished processing, the message type will either be
393 an error message or a normal method reply message.
395 QDBusMessage QDBusPendingCall::reply() const
398 return QDBusMessage::createError(error());
399 QMutexLocker locker(&d->mutex);
400 return d->replyMessage;
405 Sets the slot \a member in object \a target to be called when the
406 reply arrives. The slot's parameter list must match the reply
407 message's arguments for it to be called.
409 It may, optionally, contain a QDBusMessage final parameter. If it
410 is present, the parameter will contain the reply message object.
412 The callback will not be called if the reply is an error message.
414 This function returns true if it could set the callback, false
415 otherwise. It is not a guarantee that the callback will be
418 \warning QDBusPendingCall only supports one callback per pending
419 asynchronous call, even if multiple QDBusPendingCall
420 objects are referencing the same pending call.
422 bool QDBusPendingCall::setReplyCallback(QObject *target, const char *member)
427 return d->setReplyCallback(target, member);
433 Creates a QDBusPendingCall object based on the error condition
434 \a error. The resulting pending call object will be in the
435 "finished" state and QDBusPendingReply::isError() will return true.
437 \sa fromCompletedCall()
439 QDBusPendingCall QDBusPendingCall::fromError(const QDBusError &error)
441 return fromCompletedCall(QDBusMessage::createError(error));
446 Creates a QDBusPendingCall object based on the message \a msg.
447 The message must be of type QDBusMessage::ErrorMessage or
448 QDBusMessage::ReplyMessage (that is, a message that is typical
449 of a completed call).
451 This function is useful for code that requires simulating a pending
452 call, but that has already finished.
456 QDBusPendingCall QDBusPendingCall::fromCompletedCall(const QDBusMessage &msg)
458 QDBusPendingCallPrivate *d = 0;
459 if (msg.type() == QDBusMessage::ErrorMessage ||
460 msg.type() == QDBusMessage::ReplyMessage) {
461 d = new QDBusPendingCallPrivate(QDBusMessage(), 0);
462 d->replyMessage = msg;
465 return QDBusPendingCall(d);
469 class QDBusPendingCallWatcherPrivate: public QObjectPrivate
474 Q_DECLARE_PUBLIC(QDBusPendingCallWatcher)
477 inline void QDBusPendingCallWatcherPrivate::_q_finished()
479 Q_Q(QDBusPendingCallWatcher);
484 Creates a QDBusPendingCallWatcher object to watch for replies on the
485 asynchronous pending call \a call and sets this object's parent
488 QDBusPendingCallWatcher::QDBusPendingCallWatcher(const QDBusPendingCall &call, QObject *parent)
489 : QObject(*new QDBusPendingCallWatcherPrivate, parent), QDBusPendingCall(call)
491 if (d) { // QDBusPendingCall::d
492 QMutexLocker locker(&d->mutex);
493 if (!d->watcherHelper) {
494 d->watcherHelper = new QDBusPendingCallWatcherHelper;
495 if (d->replyMessage.type() != QDBusMessage::InvalidMessage) {
496 // cause a signal emission anyways
497 QMetaObject::invokeMethod(d->watcherHelper, "finished", Qt::QueuedConnection);
500 d->watcherHelper->add(this);
505 Destroys this object. If this QDBusPendingCallWatcher object was the
506 last reference to the unfinished pending call, the call will be
509 QDBusPendingCallWatcher::~QDBusPendingCallWatcher()
514 \fn void QDBusPendingCallWatcher::waitForFinished()
516 Suspends the execution of the calling thread until the reply is
517 received and processed. After this function returns, isFinished()
518 should return true, indicating the reply's contents are ready to
521 \sa QDBusPendingReply::waitForFinished()
523 void QDBusPendingCallWatcher::waitForFinished()
526 d->waitForFinished();
528 // our signals were queued, so deliver them
529 QCoreApplication::sendPostedEvents(d->watcherHelper, QEvent::MetaCall);
530 QCoreApplication::sendPostedEvents(this, QEvent::MetaCall);
537 #include "moc_qdbuspendingcall.cpp"