QDBusPendingCallPrivate: save 8 bytes on 64-bit archs
[profile/ivi/qtbase.git] / src / dbus / qdbuspendingcall.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDBus module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdbuspendingcall.h"
43 #include "qdbuspendingcall_p.h"
44
45 #include "qdbusconnection_p.h"
46 #include "qdbusmetatype_p.h"
47 #include "qcoreapplication.h"
48 #include "qcoreevent.h"
49 #include <private/qobject_p.h>
50
51 #ifndef QT_NO_DBUS
52
53 QT_BEGIN_NAMESPACE
54
55 /*!
56     \class QDBusPendingCall
57     \inmodule QtDBus
58     \since 4.5
59
60     \brief The QDBusPendingCall class refers to one pending asynchronous call
61
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.
65
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.
70
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.
76
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)
82
83     \sa QDBusPendingReply, QDBusPendingCallWatcher,
84         QDBusAbstractInterface::asyncCall()
85 */
86
87 /*!
88     \class QDBusPendingCallWatcher
89     \inmodule QtDBus
90     \since 4.5
91
92     \brief The QDBusPendingCallWatcher class provides a convenient way for
93     waiting for asynchronous replies
94
95     The QDBusPendingCallWatcher provides the finished() signal that will be
96     emitted when a reply arrives.
97
98     It is usually used like the following example:
99
100     \snippet code/src_qdbus_qdbuspendingcall.cpp 0
101
102     Note that it is not necessary to keep the original QDBusPendingCall
103     object around since QDBusPendingCallWatcher inherits from that class
104     too.
105
106     The slot connected to by the above code could be something similar
107     to the following:
108
109     \snippet code/src_qdbus_qdbuspendingcall.cpp 1
110
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
114     return true.
115
116     \sa QDBusPendingReply, QDBusAbstractInterface::asyncCall()
117 */
118
119 /*!
120     \fn void QDBusPendingCallWatcher::finished(QDBusPendingCallWatcher *self)
121
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.
126 */
127
128 void QDBusPendingCallWatcherHelper::add(QDBusPendingCallWatcher *watcher)
129 {
130     connect(this, SIGNAL(finished()), watcher, SLOT(_q_finished()), Qt::QueuedConnection);
131 }
132
133 QDBusPendingCallPrivate::~QDBusPendingCallPrivate()
134 {
135     if (pending) {
136         q_dbus_pending_call_cancel(pending);
137         q_dbus_pending_call_unref(pending);
138     }
139     delete watcherHelper;
140 }
141
142 bool QDBusPendingCallPrivate::setReplyCallback(QObject *target, const char *member)
143 {
144     receiver = target;
145     metaTypes.clear();
146     methodIdx = -1;
147     if (!target)
148         return true;;           // unsetting
149
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");
156         return false;
157     }
158
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);
163     }
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()));
169         return false;
170     }
171
172     // success
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
177         return true;
178     }
179
180     if (metaTypes.at(count) == QDBusMetaTypeId::message)
181         --count;
182
183     setMetaTypes(count, count ? metaTypes.constData() + 1 : 0);
184     return true;
185 }
186
187 void QDBusPendingCallPrivate::setMetaTypes(int count, const int *types)
188 {
189     expectedReplyCount = count;
190     if (count == 0) {
191         expectedReplySignature = QLatin1String(""); // not null
192         return;
193     }
194
195     QByteArray sig;
196     sig.reserve(count + count / 2);
197     for (int i = 0; i < count; ++i) {
198         const char *typeSig = QDBusMetaType::typeToSignature(types[i]);
199         if (!typeSig) {
200             qFatal("QDBusPendingReply: type %s is not registered with QtDBus",
201                    QMetaType::typeName(types[i]));
202         }
203         sig += typeSig;
204     }
205
206     expectedReplySignature = QString::fromLatin1(sig);
207 }
208
209 void QDBusPendingCallPrivate::checkReceivedSignature()
210 {
211     // MUST BE CALLED WITH A LOCKED MUTEX!
212
213     if (replyMessage.type() == QDBusMessage::InvalidMessage)
214         return;                 // not yet finished - no message to
215                                 // validate against
216     if (replyMessage.type() == QDBusMessage::ErrorMessage)
217         return;                 // we don't have to check the signature of an error reply
218
219     if (expectedReplySignature.isNull())
220         return;                 // no signature to validate against
221
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\", "
225                                          "expected \"%2\"");
226         replyMessage = QDBusMessage::createError(
227             QDBusError::InvalidSignature,
228             errorMsg.arg(replyMessage.signature(), expectedReplySignature));
229
230     }
231 }
232
233 void QDBusPendingCallPrivate::waitForFinished()
234 {
235     QMutexLocker locker(&mutex);
236
237     if (replyMessage.type() != QDBusMessage::InvalidMessage)
238         return;                 // already finished
239
240     connection->waitForFinished(this);
241 }
242
243 /*!
244     Creates a copy of the \a other pending asynchronous call. Note
245     that both objects will refer to the same pending call.
246 */
247 QDBusPendingCall::QDBusPendingCall(const QDBusPendingCall &other)
248     : d(other.d)
249 {
250 }
251
252 /*!
253     \internal
254 */
255 QDBusPendingCall::QDBusPendingCall(QDBusPendingCallPrivate *dd)
256     : d(dd)
257 {
258 }
259
260 /*!
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.
265 */
266 QDBusPendingCall::~QDBusPendingCall()
267 {
268     // d deleted by QExplicitlySharedDataPointer
269 }
270
271
272 /*!
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.
276
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.
281 */
282 QDBusPendingCall &QDBusPendingCall::operator=(const QDBusPendingCall &other)
283 {
284     d = other.d;
285     return *this;
286 }
287
288 /*!
289     \fn void QDBusPendingCall::swap(QDBusPendingCall &other)
290     \since 5.0
291
292     Swaps this pending call instance with \a other. This function is
293     very fast and never fails.
294 */
295
296 /*!
297     \fn bool QDBusPendingCallWatcher::isFinished() const
298
299     Returns true if the pending call has finished processing and the
300     reply has been received.
301
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.
305
306     \sa QDBusPendingReply::isFinished()
307 */
308 /*!
309     \fn bool QDBusPendingReply::isFinished() const
310
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
314     information.
315
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.
319
320     \sa QDBusPendingCallWatcher::isFinished()
321 */
322
323 bool QDBusPendingCall::isFinished() const
324 {
325     if (!d)
326         return true; // considered finished
327
328     QMutexLocker locker(&d->mutex);
329     return d->replyMessage.type() != QDBusMessage::InvalidMessage;
330 }
331
332 void QDBusPendingCall::waitForFinished()
333 {
334     if (d) d->waitForFinished();
335 }
336
337 /*!
338     \fn bool QDBusPendingReply::isValid() const
339
340     Returns true if the reply contains a normal reply message, false
341     if it contains anything else.
342
343     If the pending call has not finished processing, this function
344     return false.
345 */
346 bool QDBusPendingCall::isValid() const
347 {
348     if (!d)
349         return false;
350     QMutexLocker locker(&d->mutex);
351     return d->replyMessage.type() == QDBusMessage::ReplyMessage;
352 }
353
354 /*!
355     \fn bool QDBusPendingReply::isError() const
356
357     Returns true if the reply contains an error message, false if it
358     contains a normal method reply.
359
360     If the pending call has not finished processing, this function
361     also returns true.
362 */
363 bool QDBusPendingCall::isError() const
364 {
365     if (!d)
366         return true; // considered finished and an error
367     QMutexLocker locker(&d->mutex);
368     return d->replyMessage.type() == QDBusMessage::ErrorMessage;
369 }
370
371 /*!
372     \fn QDBusError QDBusPendingReply::error() const
373
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.
378 */
379 QDBusError QDBusPendingCall::error() const
380 {
381     if (d) {
382         QMutexLocker locker(&d->mutex);
383         return QDBusError(d->replyMessage);
384     }
385
386     // not connected, return an error
387     QDBusError err = QDBusError(QDBusError::Disconnected,
388                                 QLatin1String("Not connected to D-Bus server"));
389     return err;
390 }
391
392 /*!
393     \fn QDBusMessage QDBusPendingReply::reply() const
394
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.
399
400     After it has finished processing, the message type will either be
401     an error message or a normal method reply message.
402 */
403 QDBusMessage QDBusPendingCall::reply() const
404 {
405     if (!d)
406         return QDBusMessage::createError(error());
407     QMutexLocker locker(&d->mutex);
408     return d->replyMessage;
409 }
410
411 #if 0
412 /*!
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.
416
417     It may, optionally, contain a QDBusMessage final parameter. If it
418     is present, the parameter will contain the reply message object.
419
420     The callback will not be called if the reply is an error message.
421
422     This function returns true if it could set the callback, false
423     otherwise. It is not a guarantee that the callback will be
424     called.
425
426     \warning QDBusPendingCall only supports one callback per pending
427              asynchronous call, even if multiple QDBusPendingCall
428              objects are referencing the same pending call.
429 */
430 bool QDBusPendingCall::setReplyCallback(QObject *target, const char *member)
431 {
432     if (!d)
433         return false;
434
435     return d->setReplyCallback(target, member);
436 }
437 #endif
438
439 /*!
440     \since 4.6
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.
444
445     \sa fromCompletedCall()
446 */
447 QDBusPendingCall QDBusPendingCall::fromError(const QDBusError &error)
448 {
449     return fromCompletedCall(QDBusMessage::createError(error));
450 }
451
452 /*!
453     \since 4.6
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).
458
459     This function is useful for code that requires simulating a pending
460     call, but that has already finished.
461
462     \sa fromError()
463 */
464 QDBusPendingCall QDBusPendingCall::fromCompletedCall(const QDBusMessage &msg)
465 {
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;
471     }
472
473     return QDBusPendingCall(d);
474 }
475
476
477 class QDBusPendingCallWatcherPrivate: public QObjectPrivate
478 {
479 public:
480     void _q_finished();
481
482     Q_DECLARE_PUBLIC(QDBusPendingCallWatcher)
483 };
484
485 inline void QDBusPendingCallWatcherPrivate::_q_finished()
486 {
487     Q_Q(QDBusPendingCallWatcher);
488     emit q->finished(q);
489 }
490
491 /*!
492     Creates a QDBusPendingCallWatcher object to watch for replies on the
493     asynchronous pending call \a call and sets this object's parent
494     to \a parent.
495 */
496 QDBusPendingCallWatcher::QDBusPendingCallWatcher(const QDBusPendingCall &call, QObject *parent)
497     : QObject(*new QDBusPendingCallWatcherPrivate, parent), QDBusPendingCall(call)
498 {
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);
506             }
507         }
508         d->watcherHelper->add(this);
509     }
510 }
511
512 /*!
513     Destroys this object. If this QDBusPendingCallWatcher object was the
514     last reference to the unfinished pending call, the call will be
515     canceled.
516 */
517 QDBusPendingCallWatcher::~QDBusPendingCallWatcher()
518 {
519 }
520
521 /*!
522     \fn void QDBusPendingCallWatcher::waitForFinished()
523
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
527     be processed.
528
529     \sa QDBusPendingReply::waitForFinished()
530 */
531 void QDBusPendingCallWatcher::waitForFinished()
532 {
533     if (d) {
534         d->waitForFinished();
535
536         // our signals were queued, so deliver them
537         QCoreApplication::sendPostedEvents(d->watcherHelper, QEvent::MetaCall);
538         QCoreApplication::sendPostedEvents(this, QEvent::MetaCall);
539     }
540 }
541 QT_END_NAMESPACE
542
543 #endif // QT_NO_DBUS
544
545 #include "moc_qdbuspendingcall.cpp"